mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-27 19:57:00 -05:00
Merge pull request #737
New Jar Processor API Shared Service improvements FMJ 2.0 support Move Minecraft jars to maven structure Improve intelij source attachment
This commit is contained in:
@@ -39,8 +39,7 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
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;
|
||||
@@ -69,17 +68,13 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
|
||||
LoomDependencyManager getDependencyManager();
|
||||
|
||||
void setJarProcessorManager(JarProcessorManager jarProcessorManager);
|
||||
|
||||
JarProcessorManager getJarProcessorManager();
|
||||
|
||||
MinecraftProvider getMinecraftProvider();
|
||||
|
||||
void setMinecraftProvider(MinecraftProvider minecraftProvider);
|
||||
|
||||
MappingsProviderImpl getMappingsProvider();
|
||||
MappingConfiguration getMappingConfiguration();
|
||||
|
||||
void setMappingsProvider(MappingsProviderImpl mappingsProvider);
|
||||
void setMappingConfiguration(MappingConfiguration mappingConfiguration);
|
||||
|
||||
NamedMinecraftProvider<?> getNamedMinecraftProvider();
|
||||
|
||||
@@ -91,8 +86,8 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
|
||||
default List<Path> getMinecraftJars(MappingsNamespace mappingsNamespace) {
|
||||
return switch (mappingsNamespace) {
|
||||
case NAMED -> getNamedMinecraftProvider().getMinecraftJars();
|
||||
case INTERMEDIARY -> getIntermediaryMinecraftProvider().getMinecraftJars();
|
||||
case NAMED -> getNamedMinecraftProvider().getMinecraftJarPaths();
|
||||
case INTERMEDIARY -> getIntermediaryMinecraftProvider().getMinecraftJarPaths();
|
||||
case OFFICIAL -> getMinecraftProvider().getMinecraftJars();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.ArtifactRepositoryContainer;
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler;
|
||||
import org.gradle.api.artifacts.repositories.ArtifactRepository;
|
||||
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
|
||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
||||
import org.gradle.api.initialization.Settings;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
@@ -62,10 +61,8 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
|
||||
}
|
||||
|
||||
private void declareRepositories(RepositoryHandler repositories, LoomFiles files, ExtensionAware target) {
|
||||
repositories.maven(repo -> {
|
||||
repo.setName("UserLocalRemappedMods");
|
||||
repo.setUrl(files.getRemappedModCache());
|
||||
});
|
||||
declareLocalRepositories(repositories, files);
|
||||
|
||||
repositories.maven(repo -> {
|
||||
repo.setName("Fabric");
|
||||
repo.setUrl(MirrorUtil.getFabricRepository(target));
|
||||
@@ -93,17 +90,22 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
|
||||
}
|
||||
|
||||
repositories.mavenCentral();
|
||||
}
|
||||
|
||||
repositories.ivy(repo -> {
|
||||
repo.setUrl(files.getUserCache());
|
||||
repo.patternLayout(layout -> layout.artifact("[revision]/[artifact](-[classifier])(.[ext])"));
|
||||
repo.metadataSources(IvyArtifactRepository.MetadataSources::artifact);
|
||||
private void declareLocalRepositories(RepositoryHandler repositories, LoomFiles files) {
|
||||
repositories.maven(repo -> {
|
||||
repo.setName("LoomLocalRemappedMods");
|
||||
repo.setUrl(files.getRemappedModCache());
|
||||
});
|
||||
|
||||
repositories.ivy(repo -> {
|
||||
repo.setUrl(files.getRootProjectPersistentCache());
|
||||
repo.patternLayout(layout -> layout.artifact("[revision]/[artifact](-[classifier])(.[ext])"));
|
||||
repo.metadataSources(IvyArtifactRepository.MetadataSources::artifact);
|
||||
repositories.maven(repo -> {
|
||||
repo.setName("LoomGlobalMinecraft");
|
||||
repo.setUrl(files.getGlobalMinecraftRepo());
|
||||
});
|
||||
|
||||
repositories.maven(repo -> {
|
||||
repo.setName("LoomLocalMinecraft");
|
||||
repo.setUrl(files.getLocalMinecraftRepo());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -38,15 +38,15 @@ public interface InterfaceInjectionExtensionAPI {
|
||||
*/
|
||||
Property<Boolean> getEnableDependencyInterfaceInjection();
|
||||
|
||||
Property<Boolean> getIsEnabled();
|
||||
|
||||
/**
|
||||
* Contains a list of {@link SourceSet} that may contain a fabric.mod.json file with interfaces to inject.
|
||||
* By default, this list contains only the main {@link SourceSet}.
|
||||
*
|
||||
* @return the list property containing the {@link SourceSet}
|
||||
* @deprecated now uses the source sets defined in {@link LoomGradleExtensionAPI#getMods()}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
ListProperty<SourceSet> getInterfaceInjectionSourceSets();
|
||||
|
||||
default boolean isEnabled() {
|
||||
return getEnableDependencyInterfaceInjection().get() || !getInterfaceInjectionSourceSets().get().isEmpty();
|
||||
return getIsEnabled().get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider;
|
||||
@@ -62,12 +63,18 @@ public interface LoomGradleExtensionAPI {
|
||||
|
||||
void decompilers(Action<NamedDomainObjectContainer<DecompilerOptions>> action);
|
||||
|
||||
@Deprecated()
|
||||
ListProperty<JarProcessor> getGameJarProcessors();
|
||||
|
||||
@Deprecated()
|
||||
default void addJarProcessor(JarProcessor processor) {
|
||||
getGameJarProcessors().add(processor);
|
||||
}
|
||||
|
||||
ListProperty<MinecraftJarProcessor<?>> getMinecraftJarProcessors();
|
||||
|
||||
void addMinecraftJarProcessor(Class<? extends MinecraftJarProcessor<?>> clazz, Object... parameters);
|
||||
|
||||
ConfigurableFileCollection getLog4jConfigs();
|
||||
|
||||
Dependency officialMojangMappings();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2016-2021 FabricMC
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,13 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.mappings;
|
||||
package net.fabricmc.loom.api.processor;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface MappingsProvider {
|
||||
Path mappingsWorkingDir();
|
||||
|
||||
File intermediaryTinyFile();
|
||||
public interface MappingProcessorContext {
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2016-2022 FabricMC
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,34 +22,32 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util;
|
||||
package net.fabricmc.loom.api.processor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.Named;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class ModUtils {
|
||||
private ModUtils() {
|
||||
}
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public static boolean isMod(File file) {
|
||||
return isMod(file.toPath());
|
||||
}
|
||||
public interface MinecraftJarProcessor<S extends MinecraftJarProcessor.Spec> extends Named {
|
||||
@Nullable
|
||||
S buildSpec(SpecContext context);
|
||||
|
||||
public static boolean isMod(Path input) {
|
||||
return ZipUtils.contains(input, "fabric.mod.json");
|
||||
}
|
||||
void processJar(Path jar, S spec, ProcessorContext context) throws IOException;
|
||||
|
||||
@Nullable
|
||||
public static JsonObject getFabricModJson(Path path) {
|
||||
try {
|
||||
return ZipUtils.unpackGsonNullable(path, "fabric.mod.json", JsonObject.class);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to extract fabric.mod.json from " + path, e);
|
||||
}
|
||||
default MappingsProcessor<S> processMappings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
interface Spec {
|
||||
// Must make sure hashCode is correctly implemented.
|
||||
}
|
||||
|
||||
interface MappingsProcessor<S> {
|
||||
boolean transform(MemoryMappingTree mappings, S spec, MappingProcessorContext context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.api.processor;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public interface ProcessorContext {
|
||||
MinecraftJarConfiguration getJarConfiguration();
|
||||
|
||||
boolean isMerged();
|
||||
|
||||
boolean includesClient();
|
||||
|
||||
boolean includesServer();
|
||||
|
||||
TinyRemapper createRemapper(MappingsNamespace from, MappingsNamespace to);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.api.processor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
|
||||
public interface SpecContext {
|
||||
List<FabricModJson> modDependencies();
|
||||
|
||||
List<FabricModJson> localMods();
|
||||
|
||||
// Returns mods that are both on the compile and runtime classpath
|
||||
List<FabricModJson> modDependenciesCompileRuntime();
|
||||
|
||||
default List<FabricModJson> allMods() {
|
||||
return Stream.concat(modDependencies().stream(), localMods().stream()).toList();
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.service.MixinMappingsService;
|
||||
import net.fabricmc.loom.task.PrepareJarRemapTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
/**
|
||||
@@ -93,8 +93,8 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
LoomGradleExtension loom = LoomGradleExtension.get(project);
|
||||
String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get();
|
||||
Map<String, String> args = new HashMap<>() {{
|
||||
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, MixinMappingsService.getMixinMappingFile(project, sourceSet).getCanonicalPath());
|
||||
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingConfiguration().tinyMappings.toFile().getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, getMixinMappingsForSourceSet(project, sourceSet).getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
||||
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:" + loom.getMixin().getRefmapTargetNamespace().get());
|
||||
put(Constants.MixinArguments.QUIET, "true");
|
||||
@@ -111,6 +111,9 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
args.put("MSG_" + key, value);
|
||||
});
|
||||
|
||||
// Ensure that all of the mixin mappings have been generated before we create the mixin mappings.
|
||||
runBeforePrepare(project, task);
|
||||
|
||||
project.getLogger().debug("Outputting refmap to dir: " + getRefmapDestinationDir(task) + " for compile task: " + task);
|
||||
args.forEach((k, v) -> passArgument(task, k, v));
|
||||
} catch (IOException e) {
|
||||
@@ -143,6 +146,12 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
}
|
||||
}
|
||||
|
||||
private void runBeforePrepare(Project project, Task compileTask) {
|
||||
project.getGradle().allprojects(otherProject -> {
|
||||
otherProject.getTasks().withType(PrepareJarRemapTask.class, prepareRemapTask -> prepareRemapTask.mustRunAfter(compileTask));
|
||||
});
|
||||
}
|
||||
|
||||
private static void checkPattern(String input, Pattern pattern) {
|
||||
final Matcher matcher = pattern.matcher(input);
|
||||
|
||||
@@ -150,4 +159,9 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
throw new IllegalArgumentException("Mixin argument (%s) does not match pattern (%s)".formatted(input, pattern.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public static File getMixinMappingsForSourceSet(Project project, SourceSet sourceSet) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
return new File(extension.getFiles().getProjectBuildCache(), "mixin-map-" + extension.getMappingConfiguration().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.task.RemapTaskConfiguration;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
|
||||
public final class IncludedJarFactory {
|
||||
private final Project project;
|
||||
@@ -143,7 +143,7 @@ public final class IncludedJarFactory {
|
||||
}
|
||||
|
||||
private File getNestableJar(final File input, final Metadata metadata) {
|
||||
if (ModUtils.isMod(input)) {
|
||||
if (FabricModJsonFactory.isModJar(input)) {
|
||||
// Input is a mod, nothing needs to be done.
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ import com.google.gson.JsonObject;
|
||||
import org.gradle.api.UncheckedIOException;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
|
||||
public class JarNester {
|
||||
public static void nestJars(Collection<File> jars, File modJar, Logger logger) {
|
||||
@@ -49,7 +49,7 @@ public class JarNester {
|
||||
return;
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(ModUtils.isMod(modJar), "Cannot nest jars into none mod jar " + modJar.getName());
|
||||
Preconditions.checkArgument(FabricModJsonFactory.isModJar(modJar), "Cannot nest jars into none mod jar " + modJar.getName());
|
||||
|
||||
try {
|
||||
ZipUtils.add(modJar.toPath(), jars.stream().map(file -> {
|
||||
@@ -69,7 +69,7 @@ public class JarNester {
|
||||
|
||||
for (File file : jars) {
|
||||
String nestedJarPath = "META-INF/jars/" + file.getName();
|
||||
Preconditions.checkArgument(ModUtils.isMod(file), "Cannot nest none mod jar: " + file.getName());
|
||||
Preconditions.checkArgument(FabricModJsonFactory.isModJar(file), "Cannot nest none mod jar: " + file.getName());
|
||||
|
||||
for (JsonElement nestedJar : nestedJars) {
|
||||
JsonObject jsonObject = nestedJar.getAsJsonObject();
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.gradle.api.NamedDomainObjectProvider;
|
||||
import org.gradle.api.Project;
|
||||
@@ -42,6 +43,7 @@ import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.api.tasks.javadoc.Javadoc;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.InterfaceInjectionExtensionAPI;
|
||||
import net.fabricmc.loom.build.mixin.GroovyApInvoker;
|
||||
import net.fabricmc.loom.build.mixin.JavaApInvoker;
|
||||
import net.fabricmc.loom.build.mixin.KaptApInvoker;
|
||||
@@ -49,9 +51,9 @@ import net.fabricmc.loom.build.mixin.ScalaApInvoker;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.processors.ModJavadocProcessor;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
@@ -63,6 +65,8 @@ import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ExceptionUtil;
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
public final class CompileConfiguration {
|
||||
private CompileConfiguration() {
|
||||
@@ -126,7 +130,9 @@ public final class CompileConfiguration {
|
||||
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
|
||||
});
|
||||
|
||||
GradleUtils.afterSuccessfulEvaluation(project, () -> {
|
||||
afterEvaluationWithService(project, (serviceManager) -> {
|
||||
final ConfigContext configContext = new ConfigContextImpl(project, serviceManager, extension);
|
||||
|
||||
MinecraftSourceSets.get(project).afterEvaluate(project);
|
||||
|
||||
final boolean previousRefreshDeps = extension.refreshDeps();
|
||||
@@ -137,14 +143,14 @@ public final class CompileConfiguration {
|
||||
}
|
||||
|
||||
try {
|
||||
setupMinecraft(project);
|
||||
setupMinecraft(configContext);
|
||||
} catch (Exception e) {
|
||||
throw ExceptionUtil.createDescriptiveWrapper(RuntimeException::new, "Failed to setup Minecraft", e);
|
||||
}
|
||||
|
||||
LoomDependencyManager dependencyManager = new LoomDependencyManager();
|
||||
extension.setDependencyManager(dependencyManager);
|
||||
dependencyManager.handleDependencies(project);
|
||||
dependencyManager.handleDependencies(project, serviceManager);
|
||||
|
||||
releaseLock(project);
|
||||
extension.setRefreshDeps(previousRefreshDeps);
|
||||
@@ -155,7 +161,7 @@ public final class CompileConfiguration {
|
||||
setupMixinAp(project, mixin);
|
||||
}
|
||||
|
||||
configureDecompileTasks(project);
|
||||
configureDecompileTasks(configContext);
|
||||
});
|
||||
|
||||
finalizedBy(project, "idea", "genIdeaWorkspace");
|
||||
@@ -178,29 +184,31 @@ 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);
|
||||
private static synchronized void setupMinecraft(ConfigContext configContext) throws Exception {
|
||||
final Project project = configContext.project();
|
||||
final LoomGradleExtension extension = configContext.extension();
|
||||
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
|
||||
|
||||
// Provide the vanilla mc jars -- TODO share across projects.
|
||||
final MinecraftProvider minecraftProvider = jarConfiguration.getMinecraftProviderFunction().apply(project);
|
||||
final MinecraftProvider minecraftProvider = jarConfiguration.getMinecraftProviderFunction().apply(configContext);
|
||||
extension.setMinecraftProvider(minecraftProvider);
|
||||
minecraftProvider.provide();
|
||||
|
||||
final DependencyInfo mappingsDep = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
|
||||
final MappingsProviderImpl mappingsProvider = MappingsProviderImpl.getInstance(project, mappingsDep, minecraftProvider);
|
||||
extension.setMappingsProvider(mappingsProvider);
|
||||
mappingsProvider.applyToProject(project, mappingsDep);
|
||||
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(project, configContext.serviceManager(), mappingsDep, minecraftProvider);
|
||||
extension.setMappingConfiguration(mappingConfiguration);
|
||||
mappingConfiguration.applyToProject(project, mappingsDep);
|
||||
|
||||
// Provide the remapped mc jars
|
||||
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(project, minecraftProvider);
|
||||
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(project, minecraftProvider);
|
||||
final IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider = jarConfiguration.getIntermediaryMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
|
||||
NamedMinecraftProvider<?> namedMinecraftProvider = jarConfiguration.getNamedMinecraftProviderBiFunction().apply(configContext, minecraftProvider);
|
||||
|
||||
final JarProcessorManager jarProcessorManager = createJarProcessorManager(project);
|
||||
registerGameProcessors(configContext);
|
||||
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(project);
|
||||
|
||||
if (jarProcessorManager.active()) {
|
||||
if (minecraftJarProcessorManager != null) {
|
||||
// Wrap the named MC provider for one that will provide the processed jars
|
||||
namedMinecraftProvider = jarConfiguration.getProcessedNamedMinecraftProviderBiFunction().apply(namedMinecraftProvider, jarProcessorManager);
|
||||
namedMinecraftProvider = jarConfiguration.getProcessedNamedMinecraftProviderBiFunction().apply(namedMinecraftProvider, minecraftJarProcessorManager);
|
||||
}
|
||||
|
||||
extension.setIntermediaryMinecraftProvider(intermediaryMinecraftProvider);
|
||||
@@ -210,43 +218,30 @@ public final class CompileConfiguration {
|
||||
namedMinecraftProvider.provide(true);
|
||||
}
|
||||
|
||||
private static JarProcessorManager createJarProcessorManager(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
private static void registerGameProcessors(ConfigContext configContext) {
|
||||
final LoomGradleExtension extension = configContext.extension();
|
||||
|
||||
if (extension.getAccessWidenerPath().isPresent()) {
|
||||
extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(project));
|
||||
extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(configContext));
|
||||
}
|
||||
|
||||
if (extension.getEnableTransitiveAccessWideners().get()) {
|
||||
TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(project);
|
||||
TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(configContext);
|
||||
|
||||
if (!transitiveAccessWidenerJarProcessor.isEmpty()) {
|
||||
extension.getGameJarProcessors().add(transitiveAccessWidenerJarProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getInterfaceInjection().isEnabled()) {
|
||||
InterfaceInjectionProcessor jarProcessor = new InterfaceInjectionProcessor(project);
|
||||
|
||||
if (!jarProcessor.isEmpty()) {
|
||||
extension.getGameJarProcessors().add(jarProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getEnableModProvidedJavadoc().get()) {
|
||||
// This doesn't do any processing on the compiled jar, but it does have an effect on the generated sources.
|
||||
final ModJavadocProcessor javadocProcessor = ModJavadocProcessor.create(project);
|
||||
|
||||
if (javadocProcessor != null) {
|
||||
extension.getGameJarProcessors().add(javadocProcessor);
|
||||
}
|
||||
extension.addMinecraftJarProcessor(ModJavadocProcessor.class, "fabric-loom:mod-javadoc");
|
||||
}
|
||||
|
||||
JarProcessorManager processorManager = new JarProcessorManager(extension.getGameJarProcessors().get());
|
||||
extension.setJarProcessorManager(processorManager);
|
||||
processorManager.setupProcessors();
|
||||
final InterfaceInjectionExtensionAPI interfaceInjection = extension.getInterfaceInjection();
|
||||
|
||||
return processorManager;
|
||||
if (interfaceInjection.isEnabled()) {
|
||||
extension.addMinecraftJarProcessor(InterfaceInjectionProcessor.class, "fabric-loom:interface-inject", interfaceInjection.getEnableDependencyInterfaceInjection().get());
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupMixinAp(Project project, MixinExtension mixin) {
|
||||
@@ -277,11 +272,11 @@ public final class CompileConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private static void configureDecompileTasks(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
private static void configureDecompileTasks(ConfigContext configContext) {
|
||||
final LoomGradleExtension extension = configContext.extension();
|
||||
|
||||
extension.getMinecraftJarConfiguration().get().getDecompileConfigurationBiFunction()
|
||||
.apply(project, extension.getNamedMinecraftProvider()).afterEvaluation();
|
||||
.apply(configContext, extension.getNamedMinecraftProvider()).afterEvaluation();
|
||||
}
|
||||
|
||||
private static Path getLockFile(Project project) {
|
||||
@@ -343,4 +338,12 @@ public final class CompileConfiguration {
|
||||
private static void finalizedBy(Project project, String a, String b) {
|
||||
project.getTasks().named(a).configure(task -> task.finalizedBy(project.getTasks().named(b)));
|
||||
}
|
||||
|
||||
private static void afterEvaluationWithService(Project project, Consumer<SharedServiceManager> consumer) {
|
||||
GradleUtils.afterSuccessfulEvaluation(project, () -> {
|
||||
try (var serviceManager = new ScopedSharedServiceManager()) {
|
||||
consumer.accept(serviceManager);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
public interface ConfigContext {
|
||||
Project project();
|
||||
SharedServiceManager serviceManager();
|
||||
LoomGradleExtension extension();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
public record ConfigContextImpl(Project project, SharedServiceManager serviceManager, LoomGradleExtension extension) implements ConfigContext {
|
||||
}
|
||||
@@ -44,9 +44,10 @@ import net.fabricmc.loom.configuration.mods.ModConfigurationRemapper;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.SourceRemapper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
public class LoomDependencyManager {
|
||||
public void handleDependencies(Project project) {
|
||||
public void handleDependencies(Project project, SharedServiceManager serviceManager) {
|
||||
List<Runnable> afterTasks = new ArrayList<>();
|
||||
|
||||
project.getLogger().info(":setting up loom dependencies");
|
||||
@@ -75,10 +76,10 @@ public class LoomDependencyManager {
|
||||
}
|
||||
}
|
||||
|
||||
SourceRemapper sourceRemapper = new SourceRemapper(project, true);
|
||||
String mappingsIdentifier = extension.getMappingsProvider().mappingsIdentifier();
|
||||
SourceRemapper sourceRemapper = new SourceRemapper(project, serviceManager, true);
|
||||
String mappingsIdentifier = extension.getMappingConfiguration().mappingsIdentifier();
|
||||
|
||||
ModConfigurationRemapper.supplyModConfigurations(project, mappingsIdentifier, extension, sourceRemapper);
|
||||
ModConfigurationRemapper.supplyModConfigurations(project, serviceManager, mappingsIdentifier, extension, sourceRemapper);
|
||||
|
||||
sourceRemapper.remapAll();
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.gradle.api.Project;
|
||||
import net.fabricmc.accesswidener.AccessWidener;
|
||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.util.Checksum;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
@@ -44,15 +45,13 @@ import net.fabricmc.loom.util.ZipUtils;
|
||||
public class AccessWidenerJarProcessor implements JarProcessor {
|
||||
// Filename used to store hash of input access widener in processed jar file
|
||||
private static final String HASH_FILENAME = "aw.sha256";
|
||||
// The mod's own access widener file
|
||||
private byte[] modAccessWidener;
|
||||
private final AccessWidener accessWidener = new AccessWidener();
|
||||
private final Project project;
|
||||
// This is a SHA256 hash across the mod's and all transitive AWs
|
||||
private byte[] inputHash;
|
||||
|
||||
public AccessWidenerJarProcessor(Project project) {
|
||||
this.project = project;
|
||||
public AccessWidenerJarProcessor(ConfigContext configContext) {
|
||||
this.project = configContext.project();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,6 +65,9 @@ public class AccessWidenerJarProcessor implements JarProcessor {
|
||||
Path awPath = extension.getAccessWidenerPath().get().getAsFile().toPath();
|
||||
|
||||
// Read our own mod's access widener, used later for producing a version remapped to intermediary
|
||||
// The mod's own access widener file
|
||||
byte[] modAccessWidener;
|
||||
|
||||
try {
|
||||
modAccessWidener = Files.readAllBytes(awPath);
|
||||
} catch (NoSuchFileException e) {
|
||||
|
||||
@@ -48,6 +48,7 @@ import net.fabricmc.accesswidener.TransitiveOnlyFilter;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
@@ -56,14 +57,16 @@ import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
* Applies transitive access wideners that are inherited from mod and api dependencies.
|
||||
*/
|
||||
public class TransitiveAccessWidenerJarProcessor implements JarProcessor {
|
||||
private final ConfigContext configContext;
|
||||
private final Project project;
|
||||
private final LoomGradleExtension extension;
|
||||
|
||||
private final List<AccessWidenerFile> transitiveAccessWideners;
|
||||
|
||||
public TransitiveAccessWidenerJarProcessor(Project project) {
|
||||
this.project = project;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
public TransitiveAccessWidenerJarProcessor(ConfigContext configContext) {
|
||||
this.configContext = configContext;
|
||||
this.project = configContext.project();
|
||||
this.extension = configContext.extension();
|
||||
|
||||
transitiveAccessWideners = getTransitiveAccessWideners();
|
||||
|
||||
@@ -166,7 +169,7 @@ public class TransitiveAccessWidenerJarProcessor implements JarProcessor {
|
||||
|
||||
private TinyRemapper createTinyRemapper() {
|
||||
try {
|
||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, configContext.serviceManager(), "intermediary", "named");
|
||||
|
||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.UnpickJarTask;
|
||||
|
||||
@@ -38,20 +39,20 @@ public abstract class DecompileConfiguration<T extends MappedMinecraftProvider>
|
||||
protected final Project project;
|
||||
protected final T minecraftProvider;
|
||||
protected final LoomGradleExtension extension;
|
||||
protected final MappingsProviderImpl mappingsProvider;
|
||||
protected final MappingConfiguration mappingConfiguration;
|
||||
|
||||
public DecompileConfiguration(Project project, T minecraftProvider) {
|
||||
this.project = project;
|
||||
public DecompileConfiguration(ConfigContext configContext, T minecraftProvider) {
|
||||
this.project = configContext.project();
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
this.mappingsProvider = extension.getMappingsProvider();
|
||||
this.extension = configContext.extension();
|
||||
this.mappingConfiguration = extension.getMappingConfiguration();
|
||||
}
|
||||
|
||||
public abstract void afterEvaluation();
|
||||
|
||||
protected final TaskProvider<UnpickJarTask> createUnpickJarTask(String name, File inputJar, File outputJar) {
|
||||
return project.getTasks().register(name, UnpickJarTask.class, unpickJarTask -> {
|
||||
unpickJarTask.getUnpickDefinitions().set(mappingsProvider.getUnpickDefinitionsFile());
|
||||
unpickJarTask.getUnpickDefinitions().set(mappingConfiguration.getUnpickDefinitionsFile());
|
||||
unpickJarTask.getInputJar().set(inputJar);
|
||||
unpickJarTask.getOutputJar().set(outputJar);
|
||||
});
|
||||
|
||||
@@ -28,29 +28,28 @@ import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public class SingleJarDecompileConfiguration extends DecompileConfiguration<MappedMinecraftProvider> {
|
||||
public SingleJarDecompileConfiguration(Project project, MappedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
public SingleJarDecompileConfiguration(ConfigContext configContext, MappedMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void afterEvaluation() {
|
||||
List<Path> minecraftJars = minecraftProvider.getMinecraftJars();
|
||||
List<Path> minecraftJars = minecraftProvider.getMinecraftJarPaths();
|
||||
assert minecraftJars.size() == 1;
|
||||
|
||||
final File namedJar = minecraftJars.get(0).toFile();
|
||||
|
||||
File mappedJar = namedJar;
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
File outputJar = new File(extension.getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
File outputJar = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-unpicked.jar");
|
||||
createUnpickJarTask("unpickJar", namedJar, outputJar);
|
||||
|
||||
mappedJar = outputJar;
|
||||
@@ -70,7 +69,7 @@ public class SingleJarDecompileConfiguration extends DecompileConfiguration<Mapp
|
||||
task.setDescription("Decompile minecraft using %s.".formatted(decompilerName));
|
||||
task.setGroup(Constants.TaskGroup.FABRIC);
|
||||
|
||||
if (mappingsProvider.hasUnpickDefinitions()) {
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
task.dependsOn(project.getTasks().named("unpickJar"));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,19 +27,19 @@ 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.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.task.UnpickJarTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public final class SplitDecompileConfiguration extends DecompileConfiguration<MappedMinecraftProvider.Split> {
|
||||
public SplitDecompileConfiguration(Project project, MappedMinecraftProvider.Split minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
public SplitDecompileConfiguration(ConfigContext configContext, MappedMinecraftProvider.Split minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,9 +50,9 @@ public final class SplitDecompileConfiguration extends DecompileConfiguration<Ma
|
||||
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");
|
||||
if (mappingConfiguration.hasUnpickDefinitions()) {
|
||||
commonJarToDecompile = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-common-unpicked.jar");
|
||||
clientOnlyJarToDecompile = new File(extension.getMappingConfiguration().mappingsWorkingDir().toFile(), "minecraft-clientonly-unpicked.jar");
|
||||
|
||||
unpickCommonJar = createUnpickJarTask("unpickCommonJar", minecraftProvider.getCommonJar().toFile(), commonJarToDecompile);
|
||||
unpickClientOnlyJar = createUnpickJarTask("unpickClientOnlyJar", minecraftProvider.getClientOnlyJar().toFile(), clientOnlyJarToDecompile);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-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
|
||||
@@ -24,20 +24,32 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.ide.idea;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.gradle.StartParameter;
|
||||
import org.gradle.TaskExecutionRequest;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import org.gradle.internal.DefaultTaskExecutionRequest;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.task.LoomTasks;
|
||||
|
||||
public class IdeaConfiguration {
|
||||
private static final String INIT_SCRIPT_NAME = "ijmiscinit";
|
||||
private static final Pattern NOTATION_PATTERN = Pattern.compile("'net\\.minecraft:(?<name>.*):(.*):sources'");
|
||||
|
||||
public static void setup(Project project) {
|
||||
TaskProvider<IdeaSyncTask> ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, task -> {
|
||||
if (LoomGradleExtension.get(project).getRunConfigs().stream().anyMatch(RunConfigSettings::isIdeConfigGenerated)) {
|
||||
@@ -47,6 +59,12 @@ public class IdeaConfiguration {
|
||||
}
|
||||
});
|
||||
|
||||
project.getTasks().configureEach(task -> {
|
||||
if (task.getName().equals("DownloadSources")) {
|
||||
hookDownloadSources(project, task);
|
||||
}
|
||||
});
|
||||
|
||||
if (!IdeaUtils.isIdeaSync()) {
|
||||
return;
|
||||
}
|
||||
@@ -57,4 +75,63 @@ public class IdeaConfiguration {
|
||||
taskRequests.add(new DefaultTaskExecutionRequest(List.of("ideaSyncTask")));
|
||||
startParameter.setTaskRequests(taskRequests);
|
||||
}
|
||||
|
||||
/*
|
||||
"Parse" the init script enough to figure out what jar we are talking about.
|
||||
|
||||
Intelij code: https://github.com/JetBrains/intellij-community/blob/a09b1b84ab64a699794c860bc96774766dd38958/plugins/gradle/java/src/util/GradleAttachSourcesProvider.java
|
||||
*/
|
||||
private static void hookDownloadSources(Project project, Task task) {
|
||||
List<File> initScripts = project.getGradle().getStartParameter().getInitScripts();
|
||||
|
||||
for (File initScript : initScripts) {
|
||||
if (!initScript.getName().contains(INIT_SCRIPT_NAME)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
final String script = Files.readString(initScript.toPath(), StandardCharsets.UTF_8);
|
||||
final String notation = parseInitScript(project, script);
|
||||
|
||||
if (notation != null) {
|
||||
task.dependsOn(getGenSourcesTaskName(LoomGradleExtension.get(project), notation));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String parseInitScript(Project project, String script) {
|
||||
if (!script.contains("Attempt to download sources from")
|
||||
|| !script.contains("downloadSources_")
|
||||
|| !script.contains("'%s'".formatted(project.getPath()))) {
|
||||
// Failed some basic sanity checks.
|
||||
return null;
|
||||
}
|
||||
|
||||
// A little gross but should do the job nicely.
|
||||
final Matcher matcher = NOTATION_PATTERN.matcher(script);
|
||||
|
||||
if (matcher.find()) {
|
||||
return matcher.group("name");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getGenSourcesTaskName(LoomGradleExtension extension, String notation) {
|
||||
final MinecraftJarConfiguration configuration = extension.getMinecraftJarConfiguration().get();
|
||||
|
||||
if (configuration == MinecraftJarConfiguration.SPLIT) {
|
||||
if (notation.contains("minecraft-clientOnly")) {
|
||||
return "genClientOnlySources";
|
||||
}
|
||||
|
||||
return "genCommonSources";
|
||||
}
|
||||
|
||||
return "genSources";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,230 +24,157 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.ifaceinject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.hash.Hasher;
|
||||
import com.google.common.hash.Hashing;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.InterfaceInjectionExtensionAPI;
|
||||
import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.Checksum;
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext;
|
||||
import net.fabricmc.loom.api.processor.SpecContext;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.mappingio.tree.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public class InterfaceInjectionProcessor implements JarProcessor, GenerateSourcesTask.MappingsProcessor {
|
||||
// Filename used to store hash of injected interfaces in processed jar file
|
||||
private static final String HASH_FILENAME = "injected_interfaces.sha256";
|
||||
public abstract class InterfaceInjectionProcessor implements MinecraftJarProcessor<InterfaceInjectionProcessor.Spec> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceInjectionProcessor.class);
|
||||
|
||||
private final Map<String, List<InjectedInterface>> injectedInterfaces;
|
||||
private final Project project;
|
||||
private final LoomGradleExtension extension;
|
||||
private final InterfaceInjectionExtensionAPI interfaceInjectionExtension;
|
||||
private final byte[] inputHash;
|
||||
private Map<String, List<InjectedInterface>> remappedInjectedInterfaces;
|
||||
private final String name;
|
||||
private final boolean fromDependencies;
|
||||
|
||||
public InterfaceInjectionProcessor(Project project) {
|
||||
this.project = project;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
this.interfaceInjectionExtension = this.extension.getInterfaceInjection();
|
||||
this.injectedInterfaces = getInjectedInterfaces().stream()
|
||||
.collect(Collectors.groupingBy(InjectedInterface::className));
|
||||
|
||||
this.inputHash = hashInjectedInterfaces();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return injectedInterfaces.isEmpty();
|
||||
@Inject
|
||||
public InterfaceInjectionProcessor(String name, boolean fromDependencies) {
|
||||
this.name = name;
|
||||
this.fromDependencies = fromDependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
Preconditions.checkArgument(!isEmpty());
|
||||
return "loom:interface_injection:" + Checksum.toHex(inputHash);
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
public @Nullable InterfaceInjectionProcessor.Spec buildSpec(SpecContext context) {
|
||||
List<InjectedInterface> injectedInterfaces = new ArrayList<>();
|
||||
|
||||
injectedInterfaces.addAll(InjectedInterface.fromMods(context.localMods()));
|
||||
// Find the injected interfaces from mods that are both on the compile and runtime classpath.
|
||||
// Runtime is also required to ensure that the interface and it's impl is present when running the mc jar.
|
||||
|
||||
if (fromDependencies) {
|
||||
injectedInterfaces.addAll(InjectedInterface.fromMods(context.modDependenciesCompileRuntime()));
|
||||
}
|
||||
|
||||
if (injectedInterfaces.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Spec(injectedInterfaces);
|
||||
}
|
||||
|
||||
public record Spec(List<InjectedInterface> injectedInterfaces) implements MinecraftJarProcessor.Spec {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(File jarFile) {
|
||||
// Lazily remap from intermediary->named
|
||||
if (remappedInjectedInterfaces == null) {
|
||||
TinyRemapper tinyRemapper = createTinyRemapper();
|
||||
Remapper remapper = tinyRemapper.getEnvironment().getRemapper();
|
||||
public void processJar(Path jar, Spec spec, ProcessorContext context) throws IOException {
|
||||
// Remap from intermediary->named
|
||||
final TinyRemapper tinyRemapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED);
|
||||
final Remapper remapper = tinyRemapper.getEnvironment().getRemapper();
|
||||
final List<InjectedInterface> remappedInjectedInterfaces;
|
||||
|
||||
try {
|
||||
remappedInjectedInterfaces = new HashMap<>(injectedInterfaces.size());
|
||||
|
||||
for (Map.Entry<String, List<InjectedInterface>> entry : injectedInterfaces.entrySet()) {
|
||||
String namedClassName = remapper.map(entry.getKey());
|
||||
remappedInjectedInterfaces.put(
|
||||
namedClassName,
|
||||
entry.getValue().stream()
|
||||
.map(injectedInterface ->
|
||||
new InjectedInterface(
|
||||
injectedInterface.modId(),
|
||||
namedClassName,
|
||||
remapper.map(injectedInterface.ifaceName())
|
||||
))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
tinyRemapper.finish();
|
||||
}
|
||||
try {
|
||||
remappedInjectedInterfaces = spec.injectedInterfaces().stream()
|
||||
.map(injectedInterface -> remap(injectedInterface, remapper))
|
||||
.toList();
|
||||
} finally {
|
||||
tinyRemapper.finish();
|
||||
}
|
||||
|
||||
try {
|
||||
ZipUtils.transform(jarFile.toPath(), getTransformers());
|
||||
ZipUtils.transform(jar, getTransformers(remappedInjectedInterfaces));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to apply interface injections to " + jarFile, e);
|
||||
throw new RuntimeException("Failed to apply interface injections to " + jar, e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Pair<String, ZipUtils.UnsafeUnaryOperator<byte[]>>> getTransformers() {
|
||||
return remappedInjectedInterfaces.keySet().stream()
|
||||
.map(string -> new Pair<>(string.replaceAll("\\.", "/") + ".class", getTransformer(string)))
|
||||
.collect(Collectors.toList());
|
||||
private InjectedInterface remap(InjectedInterface in, Remapper remapper) {
|
||||
return new InjectedInterface(
|
||||
in.modId(),
|
||||
remapper.map(in.className()),
|
||||
remapper.map(in.ifaceName())
|
||||
);
|
||||
}
|
||||
|
||||
private ZipUtils.UnsafeUnaryOperator<byte[]> getTransformer(String className) {
|
||||
private List<Pair<String, ZipUtils.UnsafeUnaryOperator<byte[]>>> getTransformers(List<InjectedInterface> injectedInterfaces) {
|
||||
return injectedInterfaces.stream()
|
||||
.collect(Collectors.groupingBy(InjectedInterface::className))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(entry -> {
|
||||
final String zipEntry = entry.getKey().replaceAll("\\.", "/") + ".class";
|
||||
return new Pair<>(zipEntry, getTransformer(entry.getValue()));
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private ZipUtils.UnsafeUnaryOperator<byte[]> getTransformer(List<InjectedInterface> injectedInterfaces) {
|
||||
return input -> {
|
||||
ClassReader reader = new ClassReader(input);
|
||||
ClassWriter writer = new ClassWriter(0);
|
||||
List<InjectedInterface> ifaces = remappedInjectedInterfaces.get(className);
|
||||
ClassVisitor classVisitor = new InjectingClassVisitor(Constants.ASM_VERSION, writer, ifaces);
|
||||
|
||||
// Log which mods add which interface to the class
|
||||
project.getLogger().info("Injecting interfaces into " + className + ": "
|
||||
+ ifaces.stream().map(i -> i.ifaceName() + " [" + i.modId() + "]"
|
||||
).collect(Collectors.joining(", ")));
|
||||
|
||||
final ClassReader reader = new ClassReader(input);
|
||||
final ClassWriter writer = new ClassWriter(0);
|
||||
final ClassVisitor classVisitor = new InjectingClassVisitor(Constants.ASM_VERSION, writer, injectedInterfaces);
|
||||
reader.accept(classVisitor, 0);
|
||||
return writer.toByteArray();
|
||||
};
|
||||
}
|
||||
|
||||
private List<InjectedInterface> getInjectedInterfaces() {
|
||||
List<InjectedInterface> result = new ArrayList<>();
|
||||
|
||||
if (interfaceInjectionExtension.getEnableDependencyInterfaceInjection().get()) {
|
||||
result.addAll(getDependencyInjectedInterfaces());
|
||||
}
|
||||
|
||||
for (SourceSet sourceSet : interfaceInjectionExtension.getInterfaceInjectionSourceSets().get()) {
|
||||
result.addAll(getSourceInjectedInterface(sourceSet));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find the injected interfaces from mods that are both on the compile and runtime classpath.
|
||||
// Runtime is also required to ensure that the interface and it's impl is present when running the mc jar.
|
||||
private List<InjectedInterface> getDependencyInjectedInterfaces() {
|
||||
final Function<RemapConfigurationSettings, Stream<Path>> resolve = settings ->
|
||||
settings.getSourceConfiguration().get().resolve().stream()
|
||||
.map(File::toPath);
|
||||
|
||||
final List<Path> runtimeEntries = extension.getRuntimeRemapConfigurations().stream()
|
||||
.flatMap(resolve)
|
||||
.toList();
|
||||
|
||||
return extension.getCompileRemapConfigurations().stream()
|
||||
.flatMap(resolve)
|
||||
.filter(runtimeEntries::contains) // Use the intersection of the two configurations.
|
||||
.flatMap(path -> InjectedInterface.fromModJar(path).stream())
|
||||
.toList();
|
||||
}
|
||||
|
||||
private List<InjectedInterface> getSourceInjectedInterface(SourceSet sourceSet) {
|
||||
final File fabricModJson;
|
||||
|
||||
try {
|
||||
fabricModJson = sourceSet.getResources()
|
||||
.matching(patternFilterable -> patternFilterable.include("fabric.mod.json"))
|
||||
.getSingleFile();
|
||||
} catch (IllegalStateException e) {
|
||||
// File not found
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final String jsonString;
|
||||
|
||||
try {
|
||||
jsonString = Files.readString(fabricModJson.toPath(), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read fabric.mod.json", e);
|
||||
}
|
||||
|
||||
final JsonObject jsonObject = LoomGradlePlugin.GSON.fromJson(jsonString, JsonObject.class);
|
||||
|
||||
return InjectedInterface.fromJson(jsonObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(MemoryMappingTree mappings) {
|
||||
if (injectedInterfaces.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MappingsNamespace.INTERMEDIARY.toString().equals(mappings.getSrcNamespace())) {
|
||||
throw new IllegalStateException("Mapping tree must have intermediary src mappings not " + mappings.getSrcNamespace());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, List<InjectedInterface>> entry : injectedInterfaces.entrySet()) {
|
||||
final String className = entry.getKey();
|
||||
final List<InjectedInterface> injectedInterfaces = entry.getValue();
|
||||
|
||||
MappingTree.ClassMapping classMapping = mappings.getClass(className);
|
||||
|
||||
if (classMapping == null) {
|
||||
final String modIds = injectedInterfaces.stream().map(InjectedInterface::modId).distinct().collect(Collectors.joining(","));
|
||||
project.getLogger().warn("Failed to find class ({}) to add injected interfaces from mod(s) ({})", className, modIds);
|
||||
continue;
|
||||
public MappingsProcessor<Spec> processMappings() {
|
||||
return (mappings, spec, context) -> {
|
||||
if (!MappingsNamespace.INTERMEDIARY.toString().equals(mappings.getSrcNamespace())) {
|
||||
throw new IllegalStateException("Mapping tree must have intermediary src mappings not " + mappings.getSrcNamespace());
|
||||
}
|
||||
|
||||
classMapping.setComment(appendComment(classMapping.getComment(), injectedInterfaces));
|
||||
}
|
||||
Map<String, List<InjectedInterface>> map = spec.injectedInterfaces().stream()
|
||||
.collect(Collectors.groupingBy(InjectedInterface::className));
|
||||
|
||||
return true;
|
||||
for (Map.Entry<String, List<InjectedInterface>> entry : map.entrySet()) {
|
||||
final String className = entry.getKey();
|
||||
final List<InjectedInterface> injectedInterfaces = entry.getValue();
|
||||
|
||||
MappingTree.ClassMapping classMapping = mappings.getClass(className);
|
||||
|
||||
if (classMapping == null) {
|
||||
final String modIds = injectedInterfaces.stream().map(InjectedInterface::modId).distinct().collect(Collectors.joining(","));
|
||||
LOGGER.warn("Failed to find class ({}) to add injected interfaces from mod(s) ({})", className, modIds);
|
||||
continue;
|
||||
}
|
||||
|
||||
classMapping.setComment(appendComment(classMapping.getComment(), injectedInterfaces));
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private static String appendComment(String comment, List<InjectedInterface> injectedInterfaces) {
|
||||
@@ -267,33 +194,15 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
|
||||
}
|
||||
|
||||
private record InjectedInterface(String modId, String className, String ifaceName) {
|
||||
/**
|
||||
* Reads the injected interfaces contained in a mod jar, or returns empty if there is none.
|
||||
*/
|
||||
public static List<InjectedInterface> fromModJar(Path modJarPath) {
|
||||
final JsonObject jsonObject = ModUtils.getFabricModJson(modJarPath);
|
||||
public static List<InjectedInterface> fromMod(FabricModJson fabricModJson) {
|
||||
final String modId = fabricModJson.getId();
|
||||
final JsonElement jsonElement = fabricModJson.getCustom(Constants.CustomModJsonKeys.INJECTED_INTERFACE);
|
||||
|
||||
if (jsonObject == null) {
|
||||
if (jsonElement == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return fromJson(jsonObject);
|
||||
}
|
||||
|
||||
public static List<InjectedInterface> fromJson(JsonObject jsonObject) {
|
||||
final String modId = jsonObject.get("id").getAsString();
|
||||
|
||||
if (!jsonObject.has("custom")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final JsonObject custom = jsonObject.getAsJsonObject("custom");
|
||||
|
||||
if (!custom.has(Constants.CustomModJsonKeys.INJECTED_INTERFACE)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final JsonObject addedIfaces = custom.getAsJsonObject(Constants.CustomModJsonKeys.INJECTED_INTERFACE);
|
||||
final JsonObject addedIfaces = jsonElement.getAsJsonObject();
|
||||
|
||||
final List<InjectedInterface> result = new ArrayList<>();
|
||||
|
||||
@@ -307,6 +216,13 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<InjectedInterface> fromMods(List<FabricModJson> fabricModJsons) {
|
||||
return fabricModJsons.stream()
|
||||
.map(InjectedInterface::fromMod)
|
||||
.flatMap(List::stream)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
private static class InjectingClassVisitor extends ClassVisitor {
|
||||
@@ -344,36 +260,4 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
|
||||
super.visit(version, access, name, signature, superName, modifiedInterfaces.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private TinyRemapper createTinyRemapper() {
|
||||
try {
|
||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, "intermediary", "named");
|
||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||
|
||||
for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
tinyRemapper.readClassPath(minecraftJar);
|
||||
}
|
||||
|
||||
return tinyRemapper;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to create tiny remapper for intermediary->named", e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] hashInjectedInterfaces() {
|
||||
// Hash the interfaces we're about to inject to not have to repeat this everytime
|
||||
Hasher hasher = Hashing.sha256().newHasher();
|
||||
|
||||
for (Map.Entry<String, List<InjectedInterface>> entry : injectedInterfaces.entrySet()) {
|
||||
hasher.putString("class:", StandardCharsets.UTF_8);
|
||||
hasher.putString(entry.getKey(), StandardCharsets.UTF_8);
|
||||
|
||||
for (InjectedInterface ifaceName : entry.getValue()) {
|
||||
hasher.putString("iface:", StandardCharsets.UTF_8);
|
||||
hasher.putString(ifaceName.ifaceName(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
return hasher.hash().asBytes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,18 +25,18 @@
|
||||
package net.fabricmc.loom.configuration.mods;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
||||
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
import net.fabricmc.loom.util.fmj.ModEnvironment;
|
||||
|
||||
public class AccessWidenerUtils {
|
||||
/**
|
||||
@@ -58,16 +58,20 @@ public class AccessWidenerUtils {
|
||||
}
|
||||
|
||||
public static AccessWidenerData readAccessWidenerData(Path inputJar) throws IOException {
|
||||
byte[] modJsonBytes = ZipUtils.unpack(inputJar, "fabric.mod.json");
|
||||
JsonObject jsonObject = LoomGradlePlugin.GSON.fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class);
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZip(inputJar);
|
||||
final List<String> classTweakers = fabricModJson.getClassTweakers(ModEnvironment.UNIVERSAL);
|
||||
|
||||
if (!jsonObject.has("accessWidener")) {
|
||||
if (classTweakers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String accessWidenerPath = jsonObject.get("accessWidener").getAsString();
|
||||
byte[] accessWidener = ZipUtils.unpack(inputJar, accessWidenerPath);
|
||||
AccessWidenerReader.Header header = AccessWidenerReader.readHeader(accessWidener);
|
||||
if (classTweakers.size() != 1) {
|
||||
throw new UnsupportedOperationException("TODO: support multiple class tweakers");
|
||||
}
|
||||
|
||||
final String accessWidenerPath = classTweakers.get(0);
|
||||
final byte[] accessWidener = fabricModJson.getSource().read(accessWidenerPath);
|
||||
final AccessWidenerReader.Header header = AccessWidenerReader.readHeader(accessWidener);
|
||||
|
||||
return new AccessWidenerData(accessWidenerPath, header, accessWidener);
|
||||
}
|
||||
|
||||
@@ -55,9 +55,10 @@ import net.fabricmc.loom.configuration.mods.dependency.ModDependency;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.ModDependencyFactory;
|
||||
import net.fabricmc.loom.util.Checksum;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.OperatingSystem;
|
||||
import net.fabricmc.loom.util.SourceRemapper;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class ModConfigurationRemapper {
|
||||
@@ -65,7 +66,7 @@ public class ModConfigurationRemapper {
|
||||
// This can happen when the dependency is a FileCollectionDependency or from a flatDir repository.
|
||||
public static final String MISSING_GROUP = "unspecified";
|
||||
|
||||
public static void supplyModConfigurations(Project project, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
|
||||
public static void supplyModConfigurations(Project project, SharedServiceManager serviceManager, String mappingsSuffix, LoomGradleExtension extension, SourceRemapper sourceRemapper) {
|
||||
final DependencyHandler dependencies = project.getDependencies();
|
||||
|
||||
for (RemapConfigurationSettings entry : extension.getRemapConfigurations()) {
|
||||
@@ -88,7 +89,7 @@ public class ModConfigurationRemapper {
|
||||
final List<ModDependency> modDependencies = new ArrayList<>();
|
||||
|
||||
for (ArtifactRef artifact : resolveArtifacts(project, sourceConfig)) {
|
||||
if (!ModUtils.isMod(artifact.path())) {
|
||||
if (!FabricModJsonFactory.isModJar(artifact.path())) {
|
||||
artifact.applyToConfiguration(project, targetConfig);
|
||||
continue;
|
||||
}
|
||||
@@ -110,7 +111,7 @@ public class ModConfigurationRemapper {
|
||||
|
||||
if (!toRemap.isEmpty()) {
|
||||
try {
|
||||
new ModProcessor(project, sourceConfig).processMods(toRemap);
|
||||
new ModProcessor(project, sourceConfig, serviceManager).processMods(toRemap);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to remap mods", e);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.ModDependency;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.task.RemapJarTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
@@ -53,6 +53,7 @@ import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspathService;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.tinyremapper.InputTag;
|
||||
import net.fabricmc.tinyremapper.NonClassCopyMode;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
@@ -64,10 +65,12 @@ public class ModProcessor {
|
||||
|
||||
private final Project project;
|
||||
private final Configuration sourceConfiguration;
|
||||
private final SharedServiceManager serviceManager;
|
||||
|
||||
public ModProcessor(Project project, Configuration sourceConfiguration) {
|
||||
public ModProcessor(Project project, Configuration sourceConfiguration, SharedServiceManager serviceManager) {
|
||||
this.project = project;
|
||||
this.sourceConfiguration = sourceConfiguration;
|
||||
this.serviceManager = serviceManager;
|
||||
}
|
||||
|
||||
public void processMods(List<ModDependency> remapList) throws IOException {
|
||||
@@ -93,15 +96,15 @@ public class ModProcessor {
|
||||
|
||||
private void remapJars(List<ModDependency> remapList) throws IOException {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
final MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
|
||||
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
|
||||
.stream().map(File::toPath).toArray(Path[]::new);
|
||||
|
||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper()
|
||||
.withMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false))
|
||||
.withMappings(TinyRemapperHelper.create(mappingConfiguration.getMappingsService(serviceManager).getMappingTree(), fromM, toM, false))
|
||||
.renameInvalidLocals(false);
|
||||
|
||||
final KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(project);
|
||||
final KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(serviceManager, project);
|
||||
KotlinRemapperClassloader kotlinRemapperClassloader = null;
|
||||
|
||||
if (kotlinClasspathService != null) {
|
||||
|
||||
@@ -32,25 +32,22 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
|
||||
public final class LocalMavenHelper {
|
||||
private final String group;
|
||||
private final String name;
|
||||
private final String version;
|
||||
@Nullable
|
||||
private final String baseClassifier;
|
||||
private final Project project;
|
||||
private final Path root;
|
||||
|
||||
LocalMavenHelper(String group, String name, String version, @Nullable String classifier, Project project) {
|
||||
public LocalMavenHelper(String group, String name, String version, @Nullable String classifier, Path root) {
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
this.baseClassifier = classifier;
|
||||
this.project = project;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public Path copyToMaven(Path artifact, @Nullable String classifier) throws IOException {
|
||||
@@ -75,7 +72,7 @@ public final class LocalMavenHelper {
|
||||
return String.format("%s:%s:%s", group, name, version);
|
||||
}
|
||||
|
||||
private void savePom() {
|
||||
public void savePom() {
|
||||
try {
|
||||
String pomTemplate;
|
||||
|
||||
@@ -94,13 +91,8 @@ public final class LocalMavenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private Path getRoot() {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
return extension.getFiles().getRemappedModCache().toPath();
|
||||
}
|
||||
|
||||
private Path getDirectory() {
|
||||
return getRoot().resolve("%s/%s/%s".formatted(group.replace(".", "/"), name, version));
|
||||
return root.resolve("%s/%s/%s".formatted(group.replace(".", "/"), name, version));
|
||||
}
|
||||
|
||||
private Path getPomPath() {
|
||||
|
||||
@@ -69,7 +69,9 @@ public abstract sealed class ModDependency permits SplitModDependency, SimpleMod
|
||||
public abstract void applyToProject(Project project);
|
||||
|
||||
protected LocalMavenHelper createMaven(String name) {
|
||||
return new LocalMavenHelper(getRemappedGroup(), name, this.version, this.classifier, this.project);
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final Path root = extension.getFiles().getRemappedModCache().toPath();
|
||||
return new LocalMavenHelper(getRemappedGroup(), name, this.version, this.classifier, root);
|
||||
}
|
||||
|
||||
public ArtifactRef getInputArtifact() {
|
||||
|
||||
@@ -26,6 +26,7 @@ package net.fabricmc.loom.configuration.processors;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@Deprecated()
|
||||
public interface JarProcessor {
|
||||
/**
|
||||
* Returns a unique ID for this jar processor, containing all configuration details.
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2016-2020 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.processors;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.CharSource;
|
||||
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
|
||||
public class JarProcessorManager {
|
||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||
private static final String JAR_PROCESSOR_HASH_ATTRIBUTE = "Loom-Jar-Processor-Hash";
|
||||
private final List<JarProcessor> jarProcessors;
|
||||
|
||||
public JarProcessorManager(List<JarProcessor> jarProcessors) {
|
||||
this.jarProcessors = jarProcessors;
|
||||
}
|
||||
|
||||
public void setupProcessors() {
|
||||
jarProcessors.forEach(JarProcessor::setup);
|
||||
}
|
||||
|
||||
public boolean active() {
|
||||
return !jarProcessors.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isInvalid(File file) {
|
||||
if (!file.exists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String jarProcessorHash = getJarProcessorHash();
|
||||
|
||||
try (JarFile jar = new JarFile(file)) {
|
||||
Manifest manifest = jar.getManifest();
|
||||
|
||||
if (manifest == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
|
||||
if (!jarProcessorHash.equals(attributes.getValue(JAR_PROCESSOR_HASH_ATTRIBUTE))) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not check jar manifest of " + file, e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getJarProcessorHash() {
|
||||
String jarProcessorIds = jarProcessors.stream()
|
||||
.map(JarProcessor::getId)
|
||||
.sorted()
|
||||
.collect(Collectors.joining(";"));
|
||||
|
||||
try {
|
||||
return CharSource.wrap(jarProcessorIds)
|
||||
.asByteSource(StandardCharsets.UTF_8)
|
||||
.hash(Hashing.sha256())
|
||||
.toString();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not hash jar processor IDs", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void process(File file) {
|
||||
for (JarProcessor jarProcessor : jarProcessors) {
|
||||
jarProcessor.process(file);
|
||||
}
|
||||
|
||||
try {
|
||||
int count = ZipUtils.transform(file.toPath(), Map.of(MANIFEST_PATH, bytes -> {
|
||||
Manifest manifest = new Manifest(new ByteArrayInputStream(bytes));
|
||||
manifest.getMainAttributes().putValue(JAR_PROCESSOR_HASH_ATTRIBUTE, getJarProcessorHash());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
manifest.write(out);
|
||||
return out.toByteArray();
|
||||
}));
|
||||
|
||||
Preconditions.checkState(count > 0, "Did not add data to jar manifest in " + file);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not add data to jar manifest in " + file, e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends JarProcessor> T getByType(Class<T> tClass) {
|
||||
//noinspection unchecked
|
||||
return (T) jarProcessors.stream().filter(jarProcessor -> jarProcessor.getClass().equals(tClass)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.processors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext;
|
||||
import net.fabricmc.loom.api.processor.SpecContext;
|
||||
|
||||
/**
|
||||
* Wrapper around the deprecated API.
|
||||
*/
|
||||
public abstract class LegacyJarProcessorWrapper implements MinecraftJarProcessor<LegacyJarProcessorWrapper.Spec> {
|
||||
private final JarProcessor delegate;
|
||||
|
||||
@Inject
|
||||
public LegacyJarProcessorWrapper(JarProcessor delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public abstract Project getProject();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "legacy:" + delegate.getClass().getCanonicalName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable LegacyJarProcessorWrapper.Spec buildSpec(SpecContext context) {
|
||||
delegate.setup();
|
||||
return new Spec(delegate.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processJar(Path jar, Spec spec, ProcessorContext context) throws IOException {
|
||||
delegate.process(jar.toFile());
|
||||
}
|
||||
|
||||
public record Spec(String cacheValue) implements MinecraftJarProcessor.Spec {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.processors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.processor.MappingProcessorContext;
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext;
|
||||
import net.fabricmc.loom.api.processor.SpecContext;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class MinecraftJarProcessorManager {
|
||||
private static final String CACHE_VALUE_FILE_PATH = "META-INF/Loom-Jar-Processor-Cache";
|
||||
|
||||
private final List<ProcessorEntry<?>> jarProcessors;
|
||||
|
||||
private MinecraftJarProcessorManager(List<ProcessorEntry<?>> jarProcessors) {
|
||||
this.jarProcessors = Collections.unmodifiableList(jarProcessors);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static MinecraftJarProcessorManager create(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
List<MinecraftJarProcessor<?>> processors = new ArrayList<>(extension.getMinecraftJarProcessors().get());
|
||||
|
||||
for (JarProcessor legacyProcessor : extension.getGameJarProcessors().get()) {
|
||||
processors.add(project.getObjects().newInstance(LegacyJarProcessorWrapper.class, legacyProcessor));
|
||||
}
|
||||
|
||||
return MinecraftJarProcessorManager.create(processors, SpecContextImpl.create(project));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static MinecraftJarProcessorManager create(List<MinecraftJarProcessor<?>> processors, SpecContext context) {
|
||||
List<ProcessorEntry<?>> entries = new ArrayList<>();
|
||||
|
||||
for (MinecraftJarProcessor<?> processor : processors) {
|
||||
MinecraftJarProcessor.Spec spec = processor.buildSpec(context);
|
||||
|
||||
if (spec != null) {
|
||||
entries.add(new ProcessorEntry<>(processor, spec));
|
||||
}
|
||||
}
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MinecraftJarProcessorManager(entries);
|
||||
}
|
||||
|
||||
private String getCacheValue() {
|
||||
return jarProcessors.stream()
|
||||
.sorted(Comparator.comparing(ProcessorEntry::name))
|
||||
.map(ProcessorEntry::cacheValue)
|
||||
.collect(Collectors.joining("::"));
|
||||
}
|
||||
|
||||
public boolean requiresProcessingJar(Path jar) {
|
||||
Objects.requireNonNull(jar);
|
||||
|
||||
if (Files.notExists(jar)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[] existingCache;
|
||||
|
||||
try {
|
||||
existingCache = ZipUtils.unpackNullable(jar, CACHE_VALUE_FILE_PATH);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to unpack jar: " + jar, e);
|
||||
}
|
||||
|
||||
if (existingCache == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String existingCacheValue = new String(existingCache, StandardCharsets.UTF_8);
|
||||
return !existingCacheValue.equals(getCacheValue());
|
||||
}
|
||||
|
||||
public void processJar(Path jar, ProcessorContext context) throws IOException {
|
||||
for (ProcessorEntry<?> entry : jarProcessors) {
|
||||
try {
|
||||
entry.processJar(jar, context);
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Failed to process jar when running jar processor: %s".formatted(entry.name()), e);
|
||||
}
|
||||
}
|
||||
|
||||
ZipUtils.add(jar, CACHE_VALUE_FILE_PATH, getCacheValue());
|
||||
}
|
||||
|
||||
public boolean processMappings(MemoryMappingTree mappings, MappingProcessorContext context) {
|
||||
boolean transformed = false;
|
||||
|
||||
for (ProcessorEntry<?> entry : jarProcessors) {
|
||||
if (entry.processMappings(mappings, context)) {
|
||||
transformed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return transformed;
|
||||
}
|
||||
|
||||
record ProcessorEntry<S extends MinecraftJarProcessor.Spec>(S spec, MinecraftJarProcessor<S> processor, @Nullable MinecraftJarProcessor.MappingsProcessor<S> mappingsProcessor) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ProcessorEntry(MinecraftJarProcessor<?> processor, MinecraftJarProcessor.Spec spec) {
|
||||
this((S) Objects.requireNonNull(spec), (MinecraftJarProcessor<S>) processor, (MinecraftJarProcessor.MappingsProcessor<S>) processor.processMappings());
|
||||
}
|
||||
|
||||
private void processJar(Path jar, ProcessorContext context) throws IOException {
|
||||
processor().processJar(jar, spec, context);
|
||||
}
|
||||
|
||||
private boolean processMappings(MemoryMappingTree mappings, MappingProcessorContext context) {
|
||||
if (mappingsProcessor() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mappingsProcessor().transform(mappings, spec, context);
|
||||
}
|
||||
|
||||
private String name() {
|
||||
return processor.getName();
|
||||
}
|
||||
|
||||
private String cacheValue() {
|
||||
return processor.getName() + ":" + spec.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,66 +25,56 @@
|
||||
package net.fabricmc.loom.configuration.processors;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.Project;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext;
|
||||
import net.fabricmc.loom.api.processor.SpecContext;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.tree.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class ModJavadocProcessor implements JarProcessor, GenerateSourcesTask.MappingsProcessor {
|
||||
public abstract class ModJavadocProcessor implements MinecraftJarProcessor<ModJavadocProcessor.Spec> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ModJavadocProcessor.class);
|
||||
|
||||
private final List<ModJavadoc> javadocs;
|
||||
private final String name;
|
||||
|
||||
private ModJavadocProcessor(List<ModJavadoc> javadocs) {
|
||||
this.javadocs = javadocs;
|
||||
@Inject
|
||||
public ModJavadocProcessor(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ModJavadocProcessor create(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final List<ModJavadoc> javadocs = new ArrayList<>();
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
for (RemapConfigurationSettings entry : extension.getRemapConfigurations()) {
|
||||
final Set<File> artifacts = entry.getSourceConfiguration().get().resolve();
|
||||
@Override
|
||||
public @Nullable ModJavadocProcessor.Spec buildSpec(SpecContext context) {
|
||||
List<ModJavadoc> javadocs = new ArrayList<>();
|
||||
|
||||
for (File artifact : artifacts) {
|
||||
if (!ModUtils.isMod(artifact.toPath())) {
|
||||
continue;
|
||||
}
|
||||
for (FabricModJson fabricModJson : context.allMods()) {
|
||||
ModJavadoc javadoc = ModJavadoc.create(fabricModJson);
|
||||
|
||||
final ModJavadoc modJavadoc;
|
||||
|
||||
try {
|
||||
modJavadoc = ModJavadoc.fromModJar(artifact.toPath());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mod jar (%s)".formatted(artifact), e);
|
||||
}
|
||||
|
||||
if (modJavadoc != null) {
|
||||
javadocs.add(modJavadoc);
|
||||
}
|
||||
if (javadoc != null) {
|
||||
javadocs.add(javadoc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,54 +82,49 @@ public final class ModJavadocProcessor implements JarProcessor, GenerateSourcesT
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ModJavadocProcessor(javadocs);
|
||||
return new Spec(Collections.unmodifiableList(javadocs));
|
||||
}
|
||||
|
||||
public record Spec(List<ModJavadoc> javadocs) implements MinecraftJarProcessor.Spec {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(MemoryMappingTree mappings) {
|
||||
for (ModJavadoc javadoc : javadocs) {
|
||||
javadoc.apply(mappings);
|
||||
}
|
||||
|
||||
return true;
|
||||
public void processJar(Path jar, Spec spec, ProcessorContext context) {
|
||||
// Nothing to do for the jar
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "loom:interface_injection:" + javadocs.hashCode();
|
||||
}
|
||||
public @Nullable MappingsProcessor<Spec> processMappings() {
|
||||
return (mappings, spec, context) -> {
|
||||
for (ModJavadoc javadoc : spec.javadocs()) {
|
||||
javadoc.apply(mappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(File file) {
|
||||
// No need to actually process anything, we need to be a JarProcessor to ensure that the jar is cached correctly.
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
public record ModJavadoc(String modId, MemoryMappingTree mappingTree) {
|
||||
@Nullable
|
||||
public static ModJavadoc fromModJar(Path path) throws IOException {
|
||||
JsonObject jsonObject = ModUtils.getFabricModJson(path);
|
||||
public static ModJavadoc create(FabricModJson fabricModJson) {
|
||||
final String modId = fabricModJson.getId();
|
||||
final JsonElement customElement = fabricModJson.getCustom(Constants.CustomModJsonKeys.PROVIDED_JAVADOC);
|
||||
|
||||
if (jsonObject == null || !jsonObject.has("custom")) {
|
||||
if (customElement == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String modId = jsonObject.get("id").getAsString();
|
||||
final JsonObject custom = jsonObject.getAsJsonObject("custom");
|
||||
|
||||
if (!custom.has(Constants.CustomModJsonKeys.PROVIDED_JAVADOC)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String javaDocPath = custom.getAsJsonPrimitive(Constants.CustomModJsonKeys.PROVIDED_JAVADOC).getAsString();
|
||||
final byte[] data = ZipUtils.unpack(path, javaDocPath);
|
||||
final String javaDocPath = customElement.getAsString();
|
||||
final MemoryMappingTree mappings = new MemoryMappingTree();
|
||||
|
||||
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(data))) {
|
||||
MappingReader.read(reader, mappings);
|
||||
try {
|
||||
final byte[] data = fabricModJson.getSource().read(javaDocPath);
|
||||
|
||||
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(data))) {
|
||||
MappingReader.read(reader, mappings);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read javadoc from mod: " + modId, e);
|
||||
}
|
||||
|
||||
if (!mappings.getSrcNamespace().equals(MappingsNamespace.INTERMEDIARY.toString())) {
|
||||
|
||||
@@ -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.configuration.processors;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public record ProcessorContextImpl(ConfigContext configContext, MinecraftJar minecraftJar) implements ProcessorContext {
|
||||
@Override
|
||||
public MinecraftJarConfiguration getJarConfiguration() {
|
||||
return configContext.extension().getMinecraftJarConfiguration().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMerged() {
|
||||
return minecraftJar.isMerged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includesClient() {
|
||||
return minecraftJar.includesClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includesServer() {
|
||||
return minecraftJar.includesServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TinyRemapper createRemapper(MappingsNamespace from, MappingsNamespace to) {
|
||||
try {
|
||||
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(configContext().project(), configContext().serviceManager(), from.toString(), to.toString());
|
||||
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(configContext.project()));
|
||||
|
||||
for (Path minecraftJar : configContext.extension().getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
|
||||
tinyRemapper.readClassPath(minecraftJar);
|
||||
}
|
||||
|
||||
return tinyRemapper;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to create tiny remapper", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.processors;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.processor.SpecContext;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
|
||||
/**
|
||||
* @param modDependencies External mods that are depended on
|
||||
* @param localMods The main mod being built. In the future this may also include other mods.
|
||||
*/
|
||||
public record SpecContextImpl(List<FabricModJson> modDependencies, List<FabricModJson> localMods, List<FabricModJson> compileRuntimeMods) implements SpecContext {
|
||||
public static SpecContextImpl create(Project project) {
|
||||
return new SpecContextImpl(getDependentMods(project), getMods(project), getCompileRuntimeMods(project));
|
||||
}
|
||||
|
||||
private static List<FabricModJson> getDependentMods(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
var mods = new ArrayList<FabricModJson>();
|
||||
|
||||
for (RemapConfigurationSettings entry : extension.getRemapConfigurations()) {
|
||||
final Set<File> artifacts = entry.getSourceConfiguration().get().resolve();
|
||||
|
||||
for (File artifact : artifacts) {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(artifact.toPath());
|
||||
|
||||
if (fabricModJson != null) {
|
||||
mods.add(fabricModJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO supporting projects here should magically allow TAWs and what not to work across project deps :)
|
||||
|
||||
return sorted(mods);
|
||||
}
|
||||
|
||||
private static List<FabricModJson> getMods(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
var sourceSets = new ArrayList<SourceSet>();
|
||||
sourceSets.add(SourceSetHelper.getMainSourceSet(project));
|
||||
|
||||
if (extension.areEnvironmentSourceSetsSplit()) {
|
||||
sourceSets.add(SourceSetHelper.getSourceSetByName("client", project));
|
||||
}
|
||||
|
||||
try {
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(sourceSets.toArray(SourceSet[]::new));
|
||||
|
||||
if (fabricModJson != null) {
|
||||
return List.of(fabricModJson);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<FabricModJson> getCompileRuntimeMods(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final Function<RemapConfigurationSettings, Stream<Path>> resolve = settings ->
|
||||
settings.getSourceConfiguration().get().resolve().stream()
|
||||
.map(File::toPath);
|
||||
|
||||
final List<Path> runtimeEntries = extension.getRuntimeRemapConfigurations().stream()
|
||||
.flatMap(resolve)
|
||||
.toList();
|
||||
|
||||
return extension.getCompileRemapConfigurations().stream()
|
||||
.flatMap(resolve)
|
||||
.filter(runtimeEntries::contains) // Use the intersection of the two configurations.
|
||||
.map(FabricModJsonFactory::createFromZipOptional)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.sorted(Comparator.comparing(FabricModJson::getId))
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Sort to ensure stable caching
|
||||
private static List<FabricModJson> sorted(List<FabricModJson> mods) {
|
||||
return mods.stream().sorted(Comparator.comparing(FabricModJson::getId)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FabricModJson> modDependenciesCompileRuntime() {
|
||||
return compileRuntimeMods;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.util.download.DownloadBuilder;
|
||||
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public class GradleMappingContext implements MappingContext {
|
||||
@@ -66,7 +67,11 @@ public class GradleMappingContext implements MappingContext {
|
||||
|
||||
@Override
|
||||
public Supplier<MemoryMappingTree> intermediaryTree() {
|
||||
return () -> IntermediateMappingsService.getInstance(project, minecraftProvider()).getMemoryMappingTree();
|
||||
return () -> {
|
||||
try (var serviceManager = new ScopedSharedServiceManager()) {
|
||||
return IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider()).getMemoryMappingTree();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,7 +63,7 @@ public abstract class IntermediaryMappingsProvider extends IntermediateMappingsP
|
||||
.defaultCache()
|
||||
.downloadPath(intermediaryJarPath);
|
||||
|
||||
MappingsProviderImpl.extractMappings(intermediaryJarPath, tinyMappings);
|
||||
MappingConfiguration.extractMappings(intermediaryJarPath, tinyMappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,12 +56,12 @@ public final class IntermediateMappingsService implements SharedService {
|
||||
this.intermediaryTiny = intermediaryTiny;
|
||||
}
|
||||
|
||||
public static synchronized IntermediateMappingsService getInstance(Project project, MinecraftProvider minecraftProvider) {
|
||||
public static synchronized IntermediateMappingsService getInstance(SharedServiceManager sharedServiceManager, Project project, MinecraftProvider minecraftProvider) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final IntermediateMappingsProvider intermediateProvider = extension.getIntermediateMappingsProvider();
|
||||
final String id = "IntermediateMappingsService:%s:%s".formatted(intermediateProvider.getName(), intermediateProvider.getMinecraftVersion().get());
|
||||
|
||||
return SharedServiceManager.get(project).getOrCreateService(id, () -> create(intermediateProvider, minecraftProvider));
|
||||
return sharedServiceManager.getOrCreateService(id, () -> create(intermediateProvider, minecraftProvider));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
||||
@@ -38,9 +38,7 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.tools.ant.util.StringUtils;
|
||||
import org.gradle.api.Project;
|
||||
@@ -58,18 +56,15 @@ import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.DeletingFileVisitor;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.format.MappingFormat;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
import net.fabricmc.stitch.Command;
|
||||
import net.fabricmc.stitch.commands.CommandProposeFieldNames;
|
||||
|
||||
public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MappingsProviderImpl.class);
|
||||
public class MappingConfiguration {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MappingConfiguration.class);
|
||||
|
||||
private Supplier<MemoryMappingTree> mappingTree;
|
||||
public final String mappingsIdentifier;
|
||||
|
||||
private final Path mappingsWorkingDir;
|
||||
@@ -84,9 +79,7 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
private UnpickMetadata unpickMetadata;
|
||||
private Map<String, String> signatureFixes;
|
||||
|
||||
private final Supplier<IntermediateMappingsService> intermediaryService;
|
||||
|
||||
private MappingsProviderImpl(String mappingsIdentifier, Path mappingsWorkingDir, Supplier<IntermediateMappingsService> intermediaryService) {
|
||||
private MappingConfiguration(String mappingsIdentifier, Path mappingsWorkingDir) {
|
||||
this.mappingsIdentifier = mappingsIdentifier;
|
||||
|
||||
this.mappingsWorkingDir = mappingsWorkingDir;
|
||||
@@ -94,22 +87,9 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
this.tinyMappings = mappingsWorkingDir.resolve("mappings.tiny");
|
||||
this.tinyMappingsJar = mappingsWorkingDir.resolve("mappings.jar");
|
||||
this.unpickDefinitions = mappingsWorkingDir.resolve("mappings.unpick");
|
||||
|
||||
this.intermediaryService = intermediaryService;
|
||||
}
|
||||
|
||||
public static synchronized MappingsProviderImpl getInstance(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
|
||||
return SharedServiceManager.get(project).getOrCreateService("MappingsProvider:%s:%s".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()), () -> {
|
||||
Supplier<IntermediateMappingsService> intermediaryService = Suppliers.memoize(() -> IntermediateMappingsService.getInstance(project, minecraftProvider));
|
||||
return create(dependency, minecraftProvider, intermediaryService);
|
||||
});
|
||||
}
|
||||
|
||||
public MemoryMappingTree getMappings() throws IOException {
|
||||
return Objects.requireNonNull(mappingTree, "Cannot get mappings before they have been read").get();
|
||||
}
|
||||
|
||||
private static MappingsProviderImpl create(DependencyInfo dependency, MinecraftProvider minecraftProvider, Supplier<IntermediateMappingsService> intermediaryService) {
|
||||
public static MappingConfiguration create(Project project, SharedServiceManager serviceManager, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
|
||||
final String version = dependency.getResolvedVersion();
|
||||
final Path inputJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not resolve mappings: " + dependency)).toPath();
|
||||
final String mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged");
|
||||
@@ -124,10 +104,10 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
final String mappingsIdentifier = createMappingsIdentifier(mappingsName, version, getMappingsClassifier(dependency, jarInfo.v2()), minecraftProvider.minecraftVersion());
|
||||
final Path workingDir = minecraftProvider.dir(mappingsIdentifier).toPath();
|
||||
|
||||
var mappingProvider = new MappingsProviderImpl(mappingsIdentifier, workingDir, intermediaryService);
|
||||
var mappingProvider = new MappingConfiguration(mappingsIdentifier, workingDir);
|
||||
|
||||
try {
|
||||
mappingProvider.setup(minecraftProvider, inputJar);
|
||||
mappingProvider.setup(project, serviceManager, minecraftProvider, inputJar);
|
||||
} catch (IOException e) {
|
||||
cleanWorkingDirectory(workingDir);
|
||||
throw new UncheckedIOException("Failed to setup mappings: " + dependency.getDepString(), e);
|
||||
@@ -136,13 +116,17 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
return mappingProvider;
|
||||
}
|
||||
|
||||
private void setup(MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||
public TinyMappingsService getMappingsService(SharedServiceManager serviceManager) {
|
||||
return TinyMappingsService.create(serviceManager, Objects.requireNonNull(tinyMappings));
|
||||
}
|
||||
|
||||
private void setup(Project project, SharedServiceManager serviceManager, MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||
if (minecraftProvider.refreshDeps()) {
|
||||
cleanWorkingDirectory(mappingsWorkingDir);
|
||||
}
|
||||
|
||||
if (Files.notExists(tinyMappings) || minecraftProvider.refreshDeps()) {
|
||||
storeMappings(minecraftProvider, inputJar);
|
||||
storeMappings(project, serviceManager, minecraftProvider, inputJar);
|
||||
} else {
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(inputJar, (ClassLoader) null)) {
|
||||
extractExtras(fileSystem);
|
||||
@@ -153,8 +137,6 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
Files.deleteIfExists(tinyMappingsJar);
|
||||
ZipUtils.add(tinyMappingsJar, "mappings/mappings.tiny", Files.readAllBytes(tinyMappings));
|
||||
}
|
||||
|
||||
mappingTree = Suppliers.memoize(this::readMappings);
|
||||
}
|
||||
|
||||
public void applyToProject(Project project, DependencyInfo dependency) {
|
||||
@@ -182,7 +164,7 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
return isV2 ? "-v2" : "";
|
||||
}
|
||||
|
||||
private void storeMappings(MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||
private void storeMappings(Project project, SharedServiceManager serviceManager, MinecraftProvider minecraftProvider, Path inputJar) throws IOException {
|
||||
LOGGER.info(":extracting " + inputJar.getFileName());
|
||||
|
||||
try (FileSystemUtil.Delegate delegate = FileSystemUtil.getJarFileSystem(inputJar)) {
|
||||
@@ -192,7 +174,9 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
|
||||
if (areMappingsV2(baseTinyMappings)) {
|
||||
// These are unmerged v2 mappings
|
||||
MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, intermediaryService.get());
|
||||
IntermediateMappingsService intermediateMappingsService = IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider);
|
||||
|
||||
MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, intermediateMappingsService);
|
||||
} else {
|
||||
final List<Path> minecraftJars = minecraftProvider.getMinecraftJars();
|
||||
|
||||
@@ -207,16 +191,6 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryMappingTree readMappings() {
|
||||
try {
|
||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||
MappingReader.read(tinyMappings, mappingTree);
|
||||
return mappingTree;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mappings", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areMappingsV2(Path path) throws IOException {
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
return MappingReader.detectFormat(reader) == MappingFormat.TINY_2;
|
||||
@@ -326,16 +300,10 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path mappingsWorkingDir() {
|
||||
return mappingsWorkingDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File intermediaryTinyFile() {
|
||||
return intermediaryService.get().getIntermediaryTiny().toFile();
|
||||
}
|
||||
|
||||
private static String createMappingsIdentifier(String mappingsName, String version, String classifier, String minecraftVersion) {
|
||||
// mappingsName . mcVersion . version classifier
|
||||
// Example: net.fabricmc.yarn . 1_16_5 . 1.16.5+build.5 -v2
|
||||
@@ -365,9 +333,4 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
|
||||
public record UnpickMetadata(String unpickGroup, String unpickVersion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mappingTree = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.mappings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class TinyMappingsService implements SharedService {
|
||||
private final MemoryMappingTree mappingTree;
|
||||
|
||||
public TinyMappingsService(Path tinyMappings) {
|
||||
try {
|
||||
this.mappingTree = new MemoryMappingTree();
|
||||
MappingReader.read(tinyMappings, mappingTree);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mappings", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized TinyMappingsService create(SharedServiceManager serviceManager, Path tinyMappings) {
|
||||
return serviceManager.getOrCreateService("TinyMappingsService:" + tinyMappings.toAbsolutePath(), () -> new TinyMappingsService(tinyMappings));
|
||||
}
|
||||
|
||||
public MemoryMappingTree getMappingTree() {
|
||||
return mappingTree;
|
||||
}
|
||||
}
|
||||
@@ -31,15 +31,14 @@ import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.stitch.merge.JarMerger;
|
||||
|
||||
public final class MergedMinecraftProvider extends MinecraftProvider {
|
||||
private Path minecraftMergedJar;
|
||||
|
||||
public MergedMinecraftProvider(Project project) {
|
||||
super(project);
|
||||
public MergedMinecraftProvider(ConfigContext configContext) {
|
||||
super(configContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract sealed class MinecraftJar permits MinecraftJar.Merged, MinecraftJar.Common, MinecraftJar.ServerOnly, MinecraftJar.ClientOnly {
|
||||
private final Path path;
|
||||
private final boolean merged, client, server;
|
||||
private final String name;
|
||||
|
||||
protected MinecraftJar(Path path, boolean merged, boolean client, boolean server, String name) {
|
||||
this.path = Objects.requireNonNull(path);
|
||||
this.merged = merged;
|
||||
this.client = client;
|
||||
this.server = server;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Path getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public File toFile() {
|
||||
return getPath().toFile();
|
||||
}
|
||||
|
||||
public boolean isMerged() {
|
||||
return merged;
|
||||
}
|
||||
|
||||
public boolean includesClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public boolean includesServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public abstract MinecraftJar forPath(Path path);
|
||||
|
||||
public static final class Merged extends MinecraftJar {
|
||||
public Merged(Path path) {
|
||||
super(path, true, true, true, "merged");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftJar forPath(Path path) {
|
||||
return new Merged(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Common extends MinecraftJar {
|
||||
public Common(Path path) {
|
||||
super(path, false, false, true, "common");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftJar forPath(Path path) {
|
||||
return new Common(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnly extends MinecraftJar {
|
||||
public ServerOnly(Path path) {
|
||||
super(path, false, false, true, "serverOnly");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftJar forPath(Path path) {
|
||||
return new ServerOnly(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ClientOnly extends MinecraftJar {
|
||||
public ClientOnly(Path path) {
|
||||
super(path, false, true, false, "clientOnly");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftJar forPath(Path path) {
|
||||
return new ClientOnly(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,11 @@ import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.decompile.DecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.decompile.SingleJarDecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.decompile.SplitDecompileConfiguration;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
||||
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;
|
||||
@@ -73,47 +72,47 @@ public enum MinecraftJarConfiguration {
|
||||
List.of("client", "server")
|
||||
);
|
||||
|
||||
private final Function<Project, MinecraftProvider> minecraftProviderFunction;
|
||||
private final BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
|
||||
private final BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
|
||||
private final BiFunction<NamedMinecraftProvider<?>, JarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> processedNamedMinecraftProviderBiFunction;
|
||||
private final BiFunction<Project, MappedMinecraftProvider, DecompileConfiguration<?>> decompileConfigurationBiFunction;
|
||||
private final Function<ConfigContext, MinecraftProvider> minecraftProviderFunction;
|
||||
private final BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>> intermediaryMinecraftProviderBiFunction;
|
||||
private final BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>> namedMinecraftProviderBiFunction;
|
||||
private final BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> processedNamedMinecraftProviderBiFunction;
|
||||
private final BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>> decompileConfigurationBiFunction;
|
||||
private final List<String> supportedEnvironments;
|
||||
|
||||
@SuppressWarnings("unchecked") // Just a bit of a generic mess :)
|
||||
<M extends MinecraftProvider, P extends NamedMinecraftProvider<M>, Q extends MappedMinecraftProvider> MinecraftJarConfiguration(
|
||||
Function<Project, M> minecraftProviderFunction,
|
||||
BiFunction<Project, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
|
||||
BiFunction<Project, M, P> namedMinecraftProviderBiFunction,
|
||||
BiFunction<P, JarProcessorManager, ProcessedNamedMinecraftProvider<M, P>> processedNamedMinecraftProviderBiFunction,
|
||||
BiFunction<Project, Q, DecompileConfiguration<?>> decompileConfigurationBiFunction,
|
||||
Function<ConfigContext, M> minecraftProviderFunction,
|
||||
BiFunction<ConfigContext, M, IntermediaryMinecraftProvider<M>> intermediaryMinecraftProviderBiFunction,
|
||||
BiFunction<ConfigContext, M, P> namedMinecraftProviderBiFunction,
|
||||
BiFunction<P, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<M, P>> processedNamedMinecraftProviderBiFunction,
|
||||
BiFunction<ConfigContext, Q, DecompileConfiguration<?>> decompileConfigurationBiFunction,
|
||||
List<String> supportedEnvironments
|
||||
) {
|
||||
this.minecraftProviderFunction = (Function<Project, MinecraftProvider>) minecraftProviderFunction;
|
||||
this.intermediaryMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
|
||||
this.namedMinecraftProviderBiFunction = (BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
|
||||
this.processedNamedMinecraftProviderBiFunction = (BiFunction<NamedMinecraftProvider<?>, JarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>>) (Object) processedNamedMinecraftProviderBiFunction;
|
||||
this.decompileConfigurationBiFunction = (BiFunction<Project, MappedMinecraftProvider, DecompileConfiguration<?>>) decompileConfigurationBiFunction;
|
||||
this.minecraftProviderFunction = (Function<ConfigContext, MinecraftProvider>) minecraftProviderFunction;
|
||||
this.intermediaryMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>>) (Object) intermediaryMinecraftProviderBiFunction;
|
||||
this.namedMinecraftProviderBiFunction = (BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>>) namedMinecraftProviderBiFunction;
|
||||
this.processedNamedMinecraftProviderBiFunction = (BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>>) (Object) processedNamedMinecraftProviderBiFunction;
|
||||
this.decompileConfigurationBiFunction = (BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>>) decompileConfigurationBiFunction;
|
||||
this.supportedEnvironments = supportedEnvironments;
|
||||
}
|
||||
|
||||
public Function<Project, MinecraftProvider> getMinecraftProviderFunction() {
|
||||
public Function<ConfigContext, MinecraftProvider> getMinecraftProviderFunction() {
|
||||
return minecraftProviderFunction;
|
||||
}
|
||||
|
||||
public BiFunction<Project, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
|
||||
public BiFunction<ConfigContext, MinecraftProvider, IntermediaryMinecraftProvider<?>> getIntermediaryMinecraftProviderBiFunction() {
|
||||
return intermediaryMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<Project, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
|
||||
public BiFunction<ConfigContext, MinecraftProvider, NamedMinecraftProvider<?>> getNamedMinecraftProviderBiFunction() {
|
||||
return namedMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<NamedMinecraftProvider<?>, JarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> getProcessedNamedMinecraftProviderBiFunction() {
|
||||
public BiFunction<NamedMinecraftProvider<?>, MinecraftJarProcessorManager, ProcessedNamedMinecraftProvider<?, ?>> getProcessedNamedMinecraftProviderBiFunction() {
|
||||
return processedNamedMinecraftProviderBiFunction;
|
||||
}
|
||||
|
||||
public BiFunction<Project, MappedMinecraftProvider, DecompileConfiguration<?>> getDecompileConfigurationBiFunction() {
|
||||
public BiFunction<ConfigContext, MappedMinecraftProvider, DecompileConfiguration<?>> getDecompileConfigurationBiFunction() {
|
||||
return decompileConfigurationBiFunction;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.DependencyInfo;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
@@ -67,8 +68,8 @@ public abstract class MinecraftProvider {
|
||||
|
||||
private final Project project;
|
||||
|
||||
public MinecraftProvider(Project project) {
|
||||
this.project = project;
|
||||
public MinecraftProvider(ConfigContext configContext) {
|
||||
this.project = configContext.project();
|
||||
}
|
||||
|
||||
protected boolean provideClient() {
|
||||
|
||||
@@ -220,8 +220,6 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
|
||||
// The client only sources to the combined sources jar.
|
||||
jar.from(clientOnlySourceSet.getAllSource());
|
||||
});
|
||||
|
||||
extension.getInterfaceInjection().getInterfaceInjectionSourceSets().add(clientOnlySourceSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,9 +34,10 @@ import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
import net.fabricmc.tinyremapper.api.TrClass;
|
||||
|
||||
@@ -55,24 +56,24 @@ public record SignatureFixerApplyVisitor(Map<String, String> signatureFixes) imp
|
||||
};
|
||||
}
|
||||
|
||||
public static Map<String, String> getRemappedSignatures(boolean toIntermediary, MappingsProviderImpl mappingsProvider, Project project, String targetNamespace) throws IOException {
|
||||
if (mappingsProvider.getSignatureFixes() == null) {
|
||||
public static Map<String, String> getRemappedSignatures(boolean toIntermediary, MappingConfiguration mappingConfiguration, Project project, SharedServiceManager serviceManager, String targetNamespace) throws IOException {
|
||||
if (mappingConfiguration.getSignatureFixes() == null) {
|
||||
// No fixes
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
if (toIntermediary) {
|
||||
// No need to remap, as these are already intermediary
|
||||
return mappingsProvider.getSignatureFixes();
|
||||
return mappingConfiguration.getSignatureFixes();
|
||||
}
|
||||
|
||||
// Remap the sig fixes from intermediary to the target namespace
|
||||
final Map<String, String> remapped = new HashMap<>();
|
||||
final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(project, MappingsNamespace.INTERMEDIARY.toString(), targetNamespace);
|
||||
final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(project, serviceManager, MappingsNamespace.INTERMEDIARY.toString(), targetNamespace);
|
||||
final Remapper sigAsmRemapper = sigTinyRemapper.getEnvironment().getRemapper();
|
||||
|
||||
// Remap the class names and the signatures using a new tiny remapper instance.
|
||||
for (Map.Entry<String, String> entry : mappingsProvider.getSignatureFixes().entrySet()) {
|
||||
for (Map.Entry<String, String> entry : mappingConfiguration.getSignatureFixes().entrySet()) {
|
||||
remapped.put(
|
||||
sigAsmRemapper.map(entry.getKey()),
|
||||
sigAsmRemapper.mapSignature(entry.getValue(), false)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.minecraft;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Function;
|
||||
|
||||
public enum SingleJarEnvType {
|
||||
CLIENT(MinecraftJar.ClientOnly::new),
|
||||
SERVER(MinecraftJar.ServerOnly::new);
|
||||
|
||||
private final Function<Path, MinecraftJar> jarFunction;
|
||||
|
||||
SingleJarEnvType(Function<Path, MinecraftJar> jarFunction) {
|
||||
this.jarFunction = jarFunction;
|
||||
}
|
||||
|
||||
public Function<Path, MinecraftJar> getJar() {
|
||||
return jarFunction;
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.tinyremapper.NonClassCopyMode;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
@@ -40,24 +39,24 @@ public final class SingleJarMinecraftProvider extends MinecraftProvider {
|
||||
|
||||
private Path minecraftEnvOnlyJar;
|
||||
|
||||
private SingleJarMinecraftProvider(Project project, Environment environment) {
|
||||
super(project);
|
||||
private SingleJarMinecraftProvider(ConfigContext configContext, Environment environment) {
|
||||
super(configContext);
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public static SingleJarMinecraftProvider server(Project project) {
|
||||
return new SingleJarMinecraftProvider(project, new Server());
|
||||
public static SingleJarMinecraftProvider server(ConfigContext configContext) {
|
||||
return new SingleJarMinecraftProvider(configContext, new Server());
|
||||
}
|
||||
|
||||
public static SingleJarMinecraftProvider client(Project project) {
|
||||
return new SingleJarMinecraftProvider(project, new Client());
|
||||
public static SingleJarMinecraftProvider client(ConfigContext configContext) {
|
||||
return new SingleJarMinecraftProvider(configContext, new Client());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFiles() {
|
||||
super.initFiles();
|
||||
|
||||
minecraftEnvOnlyJar = path("minecraft-%s-only.jar".formatted(environment.name()));
|
||||
minecraftEnvOnlyJar = path("minecraft-%s-only.jar".formatted(environment.type()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,7 +91,7 @@ public final class SingleJarMinecraftProvider extends MinecraftProvider {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Files.deleteIfExists(minecraftEnvOnlyJar);
|
||||
throw new RuntimeException("Failed to process %s only jar".formatted(environment.name()), e);
|
||||
throw new RuntimeException("Failed to process %s only jar".formatted(environment.type()), e);
|
||||
} finally {
|
||||
if (remapper != null) {
|
||||
remapper.finish();
|
||||
@@ -115,15 +114,15 @@ public final class SingleJarMinecraftProvider extends MinecraftProvider {
|
||||
}
|
||||
|
||||
private interface Environment {
|
||||
String name();
|
||||
SingleJarEnvType type();
|
||||
|
||||
Path getInputJar(SingleJarMinecraftProvider provider) throws Exception;
|
||||
}
|
||||
|
||||
private static final class Server implements Environment {
|
||||
@Override
|
||||
public String name() {
|
||||
return "server";
|
||||
public SingleJarEnvType type() {
|
||||
return SingleJarEnvType.SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,8 +140,8 @@ public final class SingleJarMinecraftProvider extends MinecraftProvider {
|
||||
|
||||
private static final class Client implements Environment {
|
||||
@Override
|
||||
public String name() {
|
||||
return "client";
|
||||
public SingleJarEnvType type() {
|
||||
return SingleJarEnvType.CLIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,16 +28,15 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
|
||||
public final class SplitMinecraftProvider extends MinecraftProvider {
|
||||
private Path minecraftClientOnlyJar;
|
||||
private Path minecraftCommonJar;
|
||||
|
||||
public SplitMinecraftProvider(Project project) {
|
||||
super(project);
|
||||
public SplitMinecraftProvider(ConfigContext configContext) {
|
||||
super(configContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,34 +24,41 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.minecraft.mapped;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.mods.dependency.LocalMavenHelper;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SignatureFixerApplyVisitor;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
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 ConfigContext configContext;
|
||||
protected final LoomGradleExtension extension;
|
||||
|
||||
public AbstractMappedMinecraftProvider(Project project, M minecraftProvider) {
|
||||
this.project = project;
|
||||
public AbstractMappedMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
|
||||
this.configContext = configContext;
|
||||
this.minecraftProvider = minecraftProvider;
|
||||
this.extension = LoomGradleExtension.get(project);
|
||||
this.extension = configContext.extension();
|
||||
}
|
||||
|
||||
public abstract MappingsNamespace getTargetNamespace();
|
||||
@@ -90,24 +97,53 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Path getDirectory();
|
||||
|
||||
@Override
|
||||
public Path getJar(String name) {
|
||||
return getDirectory().resolve(getName(name) + ".jar");
|
||||
return getMavenHelper(name).getOutputFile(null);
|
||||
}
|
||||
|
||||
public enum MavenScope {
|
||||
// Output files will be stored per project
|
||||
LOCAL(LoomFiles::getLocalMinecraftRepo),
|
||||
// Output files will be stored globally
|
||||
GLOBAL(LoomFiles::getGlobalMinecraftRepo);
|
||||
|
||||
private final Function<LoomFiles, File> fileFunction;
|
||||
|
||||
MavenScope(Function<LoomFiles, File> fileFunction) {
|
||||
this.fileFunction = fileFunction;
|
||||
}
|
||||
|
||||
public Path getRoot(LoomGradleExtension extension) {
|
||||
return fileFunction.apply(extension.getFiles()).toPath();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract MavenScope getMavenScope();
|
||||
|
||||
public LocalMavenHelper getMavenHelper(String name) {
|
||||
return new LocalMavenHelper("net.minecraft", getName(name), getVersion(), null, getMavenScope().getRoot(extension));
|
||||
}
|
||||
|
||||
protected String getName(String name) {
|
||||
return "minecraft-%s-%s".formatted(name, getTargetNamespace().toString());
|
||||
if (getTargetNamespace() != MappingsNamespace.NAMED) {
|
||||
name = getTargetNamespace().name().toLowerCase(Locale.ROOT) + "-" + name;
|
||||
}
|
||||
|
||||
return "minecraft-" + name;
|
||||
}
|
||||
|
||||
protected String getVersion() {
|
||||
return "%s-%s".formatted(extension.getMinecraftProvider().minecraftVersion(), extension.getMappingConfiguration().mappingsIdentifier());
|
||||
}
|
||||
|
||||
protected String getDependencyNotation(String name) {
|
||||
return "net.minecraft:%s:%s/%s".formatted(getName(name), extension.getMinecraftProvider().minecraftVersion(), extension.getMappingsProvider().mappingsIdentifier());
|
||||
return "net.minecraft:%s:%s".formatted(getName(name), getVersion());
|
||||
}
|
||||
|
||||
private boolean areOutputsValid(List<RemappedJars> remappedJars) {
|
||||
for (RemappedJars remappedJar : remappedJars) {
|
||||
if (!Files.exists(remappedJar.outputJar())) {
|
||||
if (!getMavenHelper(remappedJar.name()).exists(null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -124,21 +160,21 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
|
||||
private void remapJar(RemappedJars remappedJars) throws IOException {
|
||||
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
final MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
|
||||
final String fromM = remappedJars.sourceNamespace().toString();
|
||||
final String toM = getTargetNamespace().toString();
|
||||
|
||||
Files.deleteIfExists(remappedJars.outputJar());
|
||||
Files.deleteIfExists(remappedJars.outputJarPath());
|
||||
|
||||
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingsProvider, project, toM);
|
||||
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(project, fromM, toM, true, (builder) -> {
|
||||
final Map<String, String> remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingConfiguration, getProject(), configContext.serviceManager(), toM);
|
||||
TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), configContext.serviceManager(), fromM, toM, true, (builder) -> {
|
||||
builder.extraPostApplyVisitor(new SignatureFixerApplyVisitor(remappedSignatures));
|
||||
configureRemapper(remappedJars, builder);
|
||||
});
|
||||
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(remappedJars.outputJar()).build()) {
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(remappedJars.outputJarPath()).build()) {
|
||||
outputConsumer.addNonClassFiles(remappedJars.inputJar());
|
||||
remapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project));
|
||||
remapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(getProject()));
|
||||
|
||||
for (Path path : remappedJars.remapClasspath()) {
|
||||
remapper.readClassPath(path);
|
||||
@@ -147,10 +183,12 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
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);
|
||||
throw new RuntimeException("Failed to remap JAR " + remappedJars.inputJar() + " with mappings from " + mappingConfiguration.tinyMappings, e);
|
||||
} finally {
|
||||
remapper.finish();
|
||||
}
|
||||
|
||||
getMavenHelper(remappedJars.name()).savePom();
|
||||
}
|
||||
|
||||
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
|
||||
@@ -158,18 +196,29 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
|
||||
private void cleanOutputs(List<RemappedJars> remappedJars) throws IOException {
|
||||
for (RemappedJars remappedJar : remappedJars) {
|
||||
Files.deleteIfExists(remappedJar.outputJar());
|
||||
Files.deleteIfExists(remappedJar.outputJarPath());
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigContext getConfigContext() {
|
||||
return configContext;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
return getConfigContext().project();
|
||||
}
|
||||
|
||||
public M getMinecraftProvider() {
|
||||
return minecraftProvider;
|
||||
}
|
||||
|
||||
public record RemappedJars(Path inputJar, Path outputJar, MappingsNamespace sourceNamespace, Path... remapClasspath) {
|
||||
public record RemappedJars(Path inputJar, MinecraftJar outputJar, MappingsNamespace sourceNamespace, Path... remapClasspath) {
|
||||
public Path outputJarPath() {
|
||||
return outputJar().getPath();
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return outputJar().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,27 +24,21 @@
|
||||
|
||||
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.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl {
|
||||
public IntermediaryMinecraftProvider(Project project, M minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path getDirectory() {
|
||||
return extension.getMinecraftProvider().workingDir().toPath();
|
||||
public IntermediaryMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,9 +46,14 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
return MappingsNamespace.INTERMEDIARY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenScope getMavenScope() {
|
||||
return MavenScope.GLOBAL;
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends IntermediaryMinecraftProvider<MergedMinecraftProvider> implements Merged {
|
||||
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
public MergedImpl(ConfigContext configContext, MergedMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,8 +65,8 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends IntermediaryMinecraftProvider<SplitMinecraftProvider> implements Split {
|
||||
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
public SplitImpl(ConfigContext configContext, SplitMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,19 +86,19 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
}
|
||||
|
||||
public static final class SingleJarImpl extends IntermediaryMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
|
||||
private final String env;
|
||||
private final SingleJarEnvType env;
|
||||
|
||||
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, String env) {
|
||||
super(project, minecraftProvider);
|
||||
private SingleJarImpl(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
|
||||
super(configContext, minecraftProvider);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "server");
|
||||
public static SingleJarImpl server(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.SERVER);
|
||||
}
|
||||
|
||||
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "client");
|
||||
public static SingleJarImpl client(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,7 +109,7 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
}
|
||||
|
||||
@Override
|
||||
public String env() {
|
||||
public SingleJarEnvType env() {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,15 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
|
||||
|
||||
public interface MappedMinecraftProvider {
|
||||
List<Path> getMinecraftJars();
|
||||
default List<Path> getMinecraftJarPaths() {
|
||||
return getMinecraftJars().stream().map(MinecraftJar::getPath).toList();
|
||||
}
|
||||
|
||||
List<MinecraftJar> getMinecraftJars();
|
||||
|
||||
interface ProviderImpl extends MappedMinecraftProvider {
|
||||
Path getJar(String name);
|
||||
@@ -37,12 +44,12 @@ public interface MappedMinecraftProvider {
|
||||
interface Merged extends ProviderImpl {
|
||||
String MERGED = "merged";
|
||||
|
||||
default Path getMergedJar() {
|
||||
return getJar(MERGED);
|
||||
default MinecraftJar getMergedJar() {
|
||||
return new MinecraftJar.Merged(getJar(MERGED));
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
default List<MinecraftJar> getMinecraftJars() {
|
||||
return List.of(getMergedJar());
|
||||
}
|
||||
}
|
||||
@@ -51,33 +58,33 @@ public interface MappedMinecraftProvider {
|
||||
String COMMON = "common";
|
||||
String CLIENT_ONLY = "clientOnly";
|
||||
|
||||
default Path getCommonJar() {
|
||||
return getJar(COMMON);
|
||||
default MinecraftJar getCommonJar() {
|
||||
return new MinecraftJar.Common(getJar(COMMON));
|
||||
}
|
||||
|
||||
default Path getClientOnlyJar() {
|
||||
return getJar(CLIENT_ONLY);
|
||||
default MinecraftJar getClientOnlyJar() {
|
||||
return new MinecraftJar.ClientOnly(getJar(CLIENT_ONLY));
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
default List<MinecraftJar> getMinecraftJars() {
|
||||
return List.of(getCommonJar(), getClientOnlyJar());
|
||||
}
|
||||
}
|
||||
|
||||
interface SingleJar extends ProviderImpl {
|
||||
String env();
|
||||
SingleJarEnvType env();
|
||||
|
||||
default String envName() {
|
||||
return "%sOnly".formatted(env());
|
||||
}
|
||||
|
||||
default Path getEnvOnlyJar() {
|
||||
return getJar(envName());
|
||||
default MinecraftJar getEnvOnlyJar() {
|
||||
return env().getJar().apply(getJar(envName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
default List<MinecraftJar> getMinecraftJars() {
|
||||
return List.of(getEnvOnlyJar());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,27 +24,21 @@
|
||||
|
||||
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.ConfigContext;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
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();
|
||||
public NamedMinecraftProvider(ConfigContext configContext, M minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,9 +46,14 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
return MappingsNamespace.NAMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenScope getMavenScope() {
|
||||
return MavenScope.GLOBAL;
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends NamedMinecraftProvider<MergedMinecraftProvider> implements Merged {
|
||||
public MergedImpl(Project project, MergedMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
public MergedImpl(ConfigContext configContext, MergedMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,8 +70,8 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends NamedMinecraftProvider<SplitMinecraftProvider> implements Split {
|
||||
public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
public SplitImpl(ConfigContext configContext, SplitMinecraftProvider minecraftProvider) {
|
||||
super(configContext, minecraftProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,19 +96,19 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
public static final class SingleJarImpl extends NamedMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
|
||||
private final String env;
|
||||
private final SingleJarEnvType env;
|
||||
|
||||
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, String env) {
|
||||
super(project, minecraftProvider);
|
||||
private SingleJarImpl(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider, SingleJarEnvType env) {
|
||||
super(configContext, minecraftProvider);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "server");
|
||||
public static SingleJarImpl server(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.SERVER);
|
||||
}
|
||||
|
||||
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "client");
|
||||
public static SingleJarImpl client(ConfigContext configContext, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(configContext, minecraftProvider, SingleJarEnvType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,7 +124,7 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
@Override
|
||||
public String env() {
|
||||
public SingleJarEnvType env() {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,83 +25,89 @@
|
||||
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 java.util.Objects;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.mods.dependency.LocalMavenHelper;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.processors.ProcessorContextImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider;
|
||||
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;
|
||||
private final MinecraftJarProcessorManager jarProcessorManager;
|
||||
|
||||
public ProcessedNamedMinecraftProvider(P parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide.getProject(), parentMinecraftProvide.getMinecraftProvider());
|
||||
public ProcessedNamedMinecraftProvider(P parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide.getConfigContext(), 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());
|
||||
this.jarProcessorManager = Objects.requireNonNull(jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide(boolean applyDependencies) throws Exception {
|
||||
parentMinecraftProvider.provide(false);
|
||||
|
||||
final List<Path> inputJars = parentMinecraftProvider.getMinecraftJars();
|
||||
boolean requiresProcessing = extension.refreshDeps() || inputJars.stream()
|
||||
.map(this::getProcessedPath)
|
||||
.map(Path::toFile)
|
||||
.anyMatch(jarProcessorManager::isInvalid);
|
||||
boolean requiresProcessing = parentMinecraftProvider.getMinecraftJarPaths().stream()
|
||||
.anyMatch(jarProcessorManager::requiresProcessingJar);
|
||||
|
||||
if (requiresProcessing) {
|
||||
try {
|
||||
Files.createDirectories(projectMappedDir);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to create project mapped dir", e);
|
||||
}
|
||||
|
||||
for (Path inputJar : inputJars) {
|
||||
final Path outputJar = getProcessedPath(inputJar);
|
||||
deleteSimilarJars(outputJar);
|
||||
|
||||
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
|
||||
jarProcessorManager.process(outputJar.toFile());
|
||||
}
|
||||
processJars();
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
final List<String> dependencyTargets = parentMinecraftProvider.getDependencyTargets();
|
||||
|
||||
if (dependencyTargets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftSourceSets.get(getProject()).applyDependencies(
|
||||
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
|
||||
dependencyTargets
|
||||
);
|
||||
applyDependencies();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MavenScope getMavenScope() {
|
||||
return MavenScope.LOCAL;
|
||||
}
|
||||
|
||||
private void processJars() throws IOException {
|
||||
for (MinecraftJar minecraftJar : parentMinecraftProvider.getMinecraftJars()) {
|
||||
final MinecraftJar outputJar = getProcessedPath(minecraftJar);
|
||||
deleteSimilarJars(outputJar.getPath());
|
||||
|
||||
final LocalMavenHelper mavenHelper = getMavenHelper(minecraftJar.getName());
|
||||
final Path outputPath = mavenHelper.copyToMaven(minecraftJar.getPath(), null);
|
||||
|
||||
jarProcessorManager.processJar(outputPath, new ProcessorContextImpl(configContext, minecraftJar));
|
||||
}
|
||||
}
|
||||
|
||||
private void applyDependencies() {
|
||||
final List<String> dependencyTargets = parentMinecraftProvider.getDependencyTargets();
|
||||
|
||||
if (dependencyTargets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftSourceSets.get(getProject()).applyDependencies(
|
||||
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
|
||||
dependencyTargets
|
||||
);
|
||||
}
|
||||
|
||||
private void deleteSimilarJars(Path jar) throws IOException {
|
||||
Files.deleteIfExists(jar);
|
||||
final Path parent = jar.getParent();
|
||||
|
||||
for (Path path : Files.list(jar.getParent()).filter(Files::isRegularFile)
|
||||
if (Files.notExists(parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Path path : Files.list(parent).filter(Files::isRegularFile)
|
||||
.filter(path -> path.getFileName().startsWith(jar.getFileName().toString().replace(".jar", ""))).toList()) {
|
||||
Files.deleteIfExists(path);
|
||||
}
|
||||
@@ -109,7 +115,14 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
|
||||
@Override
|
||||
protected String getName(String name) {
|
||||
return "%s%s-%s".formatted(projectMappedName, name, getTargetNamespace().toString());
|
||||
final Project project = getProject();
|
||||
|
||||
if (project.getRootProject() == project) {
|
||||
return "minecraft-%s-project-root".formatted(name);
|
||||
}
|
||||
|
||||
final String projectPath = project.getPath().replace(':', '@');
|
||||
return "minecraft-%s-project-%s".formatted(name, projectPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,7 +137,7 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftJars() {
|
||||
public List<MinecraftJar> getMinecraftJars() {
|
||||
return getParentMinecraftProvider().getMinecraftJars().stream()
|
||||
.map(this::getProcessedPath)
|
||||
.toList();
|
||||
@@ -134,60 +147,61 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
return parentMinecraftProvider;
|
||||
}
|
||||
|
||||
public Path getProcessedPath(Path input) {
|
||||
return projectMappedDir.resolve(input.getFileName().toString().replace("minecraft-", projectMappedName));
|
||||
public MinecraftJar getProcessedPath(MinecraftJar minecraftJar) {
|
||||
final Path path = getMavenHelper(minecraftJar.getName()).getOutputFile(null);
|
||||
return minecraftJar.forPath(path);
|
||||
}
|
||||
|
||||
public static final class MergedImpl extends ProcessedNamedMinecraftProvider<MergedMinecraftProvider, NamedMinecraftProvider.MergedImpl> implements Merged {
|
||||
public MergedImpl(NamedMinecraftProvider.MergedImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
public MergedImpl(NamedMinecraftProvider.MergedImpl parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getMergedJar() {
|
||||
public MinecraftJar getMergedJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getMergedJar());
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SplitImpl extends ProcessedNamedMinecraftProvider<SplitMinecraftProvider, NamedMinecraftProvider.SplitImpl> implements Split {
|
||||
public SplitImpl(NamedMinecraftProvider.SplitImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
public SplitImpl(NamedMinecraftProvider.SplitImpl parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getCommonJar() {
|
||||
public MinecraftJar getCommonJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getCommonJar());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getClientOnlyJar() {
|
||||
public MinecraftJar getClientOnlyJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getClientOnlyJar());
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SingleJarImpl extends ProcessedNamedMinecraftProvider<SingleJarMinecraftProvider, NamedMinecraftProvider.SingleJarImpl> implements SingleJar {
|
||||
private final String env;
|
||||
private final SingleJarEnvType env;
|
||||
|
||||
private SingleJarImpl(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager, String env) {
|
||||
private SingleJarImpl(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager, SingleJarEnvType env) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static ProcessedNamedMinecraftProvider.SingleJarImpl server(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
return new ProcessedNamedMinecraftProvider.SingleJarImpl(parentMinecraftProvide, jarProcessorManager, "server");
|
||||
public static ProcessedNamedMinecraftProvider.SingleJarImpl server(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
|
||||
return new ProcessedNamedMinecraftProvider.SingleJarImpl(parentMinecraftProvide, jarProcessorManager, SingleJarEnvType.SERVER);
|
||||
}
|
||||
|
||||
public static ProcessedNamedMinecraftProvider.SingleJarImpl client(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
return new ProcessedNamedMinecraftProvider.SingleJarImpl(parentMinecraftProvide, jarProcessorManager, "client");
|
||||
public static ProcessedNamedMinecraftProvider.SingleJarImpl client(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) {
|
||||
return new ProcessedNamedMinecraftProvider.SingleJarImpl(parentMinecraftProvide, jarProcessorManager, SingleJarEnvType.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getEnvOnlyJar() {
|
||||
public MinecraftJar getEnvOnlyJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getEnvOnlyJar());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String env() {
|
||||
public SingleJarEnvType env() {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,4 +48,6 @@ public interface LoomFiles {
|
||||
File getDevLauncherConfig();
|
||||
File getUnpickLoggingConfigFile();
|
||||
File getRemapClasspathFile();
|
||||
File getGlobalMinecraftRepo();
|
||||
File getLocalMinecraftRepo();
|
||||
}
|
||||
|
||||
@@ -97,4 +97,14 @@ public abstract class LoomFilesBaseImpl implements LoomFiles {
|
||||
public File getRemapClasspathFile() {
|
||||
return new File(getProjectPersistentCache(), "remapClasspath.txt");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getGlobalMinecraftRepo() {
|
||||
return new File(getUserCache(), "minecraftMaven");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getLocalMinecraftRepo() {
|
||||
return new File(getRootProjectPersistentCache(), "minecraftMaven");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor;
|
||||
import net.fabricmc.loom.configuration.RemapConfigurations;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
@@ -65,6 +66,7 @@ import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
*/
|
||||
public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionAPI {
|
||||
protected final DeprecationHelper deprecationHelper;
|
||||
@Deprecated()
|
||||
protected final ListProperty<JarProcessor> jarProcessors;
|
||||
protected final ConfigurableFileCollection log4jConfigs;
|
||||
protected final RegularFileProperty accessWidener;
|
||||
@@ -85,6 +87,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
private final NamedDomainObjectContainer<DecompilerOptions> decompilers;
|
||||
private final NamedDomainObjectContainer<ModSettings> mods;
|
||||
private final NamedDomainObjectList<RemapConfigurationSettings> remapConfigurations;
|
||||
private final ListProperty<MinecraftJarProcessor<?>> minecraftJarProcessors;
|
||||
|
||||
// A common mistake with layered mappings is to call the wrong `officialMojangMappings` method, use this to keep track of when we are building a layered mapping spec.
|
||||
protected final ThreadLocal<Boolean> layeredSpecBuilderScope = ThreadLocal.withInitial(() -> false);
|
||||
@@ -116,6 +119,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
this.decompilers = project.getObjects().domainObjectContainer(DecompilerOptions.class);
|
||||
this.mods = project.getObjects().domainObjectContainer(ModSettings.class);
|
||||
this.remapConfigurations = project.getObjects().namedDomainObjectList(RemapConfigurationSettings.class);
|
||||
//noinspection unchecked
|
||||
this.minecraftJarProcessors = (ListProperty<MinecraftJarProcessor<?>>) (Object) project.getObjects().listProperty(MinecraftJarProcessor.class);
|
||||
this.minecraftJarProcessors.finalizeValueOnRead();
|
||||
|
||||
this.minecraftJarConfiguration = project.getObjects().property(MinecraftJarConfiguration.class).convention(MinecraftJarConfiguration.MERGED);
|
||||
this.minecraftJarConfiguration.finalizeValueOnRead();
|
||||
@@ -130,6 +136,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
this.splitModDependencies.finalizeValueOnRead();
|
||||
|
||||
this.interfaceInjectionExtension = project.getObjects().newInstance(InterfaceInjectionExtensionAPI.class);
|
||||
this.interfaceInjectionExtension.getIsEnabled().convention(true);
|
||||
|
||||
this.splitEnvironmentalSourceSet = project.getObjects().property(Boolean.class).convention(false);
|
||||
this.splitEnvironmentalSourceSet.finalizeValueOnRead();
|
||||
@@ -169,6 +176,16 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
return jarProcessors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListProperty<MinecraftJarProcessor<?>> getMinecraftJarProcessors() {
|
||||
return minecraftJarProcessors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMinecraftJarProcessor(Class<? extends MinecraftJarProcessor<?>> clazz, Object... parameters) {
|
||||
getMinecraftJarProcessors().add(getProject().getObjects().newInstance(clazz, parameters));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dependency officialMojangMappings() {
|
||||
if (layeredSpecBuilderScope.get()) {
|
||||
@@ -259,7 +276,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
|
||||
@Override
|
||||
public File getMappingsFile() {
|
||||
return LoomGradleExtension.get(getProject()).getMappingsProvider().tinyMappings.toFile();
|
||||
return LoomGradleExtension.get(getProject()).getMappingConfiguration().tinyMappings.toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,9 +43,8 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
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;
|
||||
@@ -63,9 +62,8 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
private final List<AccessWidenerFile> transitiveAccessWideners = new ArrayList<>();
|
||||
|
||||
private LoomDependencyManager dependencyManager;
|
||||
private JarProcessorManager jarProcessorManager;
|
||||
private MinecraftProvider minecraftProvider;
|
||||
private MappingsProviderImpl mappingsProvider;
|
||||
private MappingConfiguration mappingConfiguration;
|
||||
private NamedMinecraftProvider<?> namedMinecraftProvider;
|
||||
private IntermediaryMinecraftProvider<?> intermediaryMinecraftProvider;
|
||||
private InstallerData installerData;
|
||||
@@ -115,16 +113,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
return Objects.requireNonNull(dependencyManager, "Cannot get LoomDependencyManager before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJarProcessorManager(JarProcessorManager jarProcessorManager) {
|
||||
this.jarProcessorManager = jarProcessorManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JarProcessorManager getJarProcessorManager() {
|
||||
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");
|
||||
@@ -136,13 +124,13 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingsProviderImpl getMappingsProvider() {
|
||||
return Objects.requireNonNull(mappingsProvider, "Cannot get MappingsProvider before it has been setup");
|
||||
public MappingConfiguration getMappingConfiguration() {
|
||||
return Objects.requireNonNull(mappingConfiguration, "Cannot get MappingsProvider before it has been setup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMappingsProvider(MappingsProviderImpl mappingsProvider) {
|
||||
this.mappingsProvider = mappingsProvider;
|
||||
public void setMappingConfiguration(MappingConfiguration mappingConfiguration) {
|
||||
this.mappingConfiguration = mappingConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,10 +45,12 @@ import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFile;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.build.event.BuildEventsListenerRegistry;
|
||||
import org.gradle.jvm.tasks.Jar;
|
||||
import org.gradle.workers.WorkAction;
|
||||
import org.gradle.workers.WorkParameters;
|
||||
@@ -89,15 +91,23 @@ public abstract class AbstractRemapJarTask extends Jar {
|
||||
@Inject
|
||||
protected abstract WorkerExecutor getWorkerExecutor();
|
||||
|
||||
@Inject
|
||||
protected abstract BuildEventsListenerRegistry getBuildEventsListenerRegistry();
|
||||
|
||||
@Input
|
||||
public abstract Property<Boolean> getIncludesClientOnlyClasses();
|
||||
|
||||
private final Provider<JarManifestService> jarManifestServiceProvider;
|
||||
|
||||
@Inject
|
||||
public AbstractRemapJarTask() {
|
||||
getSourceNamespace().convention(MappingsNamespace.NAMED.toString()).finalizeValueOnRead();
|
||||
getTargetNamespace().convention(MappingsNamespace.INTERMEDIARY.toString()).finalizeValueOnRead();
|
||||
getRemapperIsolation().convention(false).finalizeValueOnRead();
|
||||
getIncludesClientOnlyClasses().convention(false).finalizeValueOnRead();
|
||||
|
||||
jarManifestServiceProvider = JarManifestService.get(getProject());
|
||||
usesService(jarManifestServiceProvider);
|
||||
}
|
||||
|
||||
public final <P extends AbstractRemapParams> void submitWork(Class<? extends AbstractRemapAction<P>> workAction, Action<P> action) {
|
||||
@@ -113,7 +123,7 @@ public abstract class AbstractRemapJarTask extends Jar {
|
||||
params.getArchivePreserveFileTimestamps().set(isPreserveFileTimestamps());
|
||||
params.getArchiveReproducibleFileOrder().set(isReproducibleFileOrder());
|
||||
|
||||
params.getJarManifestService().set(JarManifestService.get(getProject()));
|
||||
params.getJarManifestService().set(jarManifestServiceProvider);
|
||||
|
||||
if (getIncludesClientOnlyClasses().get()) {
|
||||
final List<String> clientOnlyEntries = getClientOnlyEntries();
|
||||
|
||||
@@ -64,9 +64,9 @@ import net.fabricmc.loom.api.decompilers.DecompilationMetadata;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.api.processor.MappingProcessorContext;
|
||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerMappingsProcessor;
|
||||
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
||||
import net.fabricmc.loom.configuration.processors.ModJavadocProcessor;
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager;
|
||||
import net.fabricmc.loom.decompilers.LineNumberRemapper;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
@@ -318,7 +318,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
}
|
||||
|
||||
private Path getMappings() {
|
||||
Path inputMappings = getExtension().getMappingsProvider().tinyMappings;
|
||||
Path inputMappings = getExtension().getMappingConfiguration().tinyMappings;
|
||||
|
||||
MemoryMappingTree mappingTree = new MemoryMappingTree();
|
||||
|
||||
@@ -334,14 +334,10 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
mappingsProcessors.add(new TransitiveAccessWidenerMappingsProcessor(getProject()));
|
||||
}
|
||||
|
||||
if (getExtension().getInterfaceInjection().isEnabled()) {
|
||||
mappingsProcessors.add(new InterfaceInjectionProcessor(getProject()));
|
||||
}
|
||||
MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(getProject());
|
||||
|
||||
final ModJavadocProcessor javadocProcessor = ModJavadocProcessor.create(getProject());
|
||||
|
||||
if (javadocProcessor != null) {
|
||||
mappingsProcessors.add(javadocProcessor);
|
||||
if (minecraftJarProcessorManager != null) {
|
||||
mappingsProcessors.add(mappings -> minecraftJarProcessorManager.processMappings(mappings, new MappingProcessorContextImpl()));
|
||||
}
|
||||
|
||||
if (mappingsProcessors.isEmpty()) {
|
||||
@@ -392,4 +388,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MappingProcessorContextImpl implements MappingProcessorContext {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,10 @@ import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.SourceRemapper;
|
||||
import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsJoiner;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
@@ -105,10 +106,10 @@ public abstract class MigrateMappingsTask extends AbstractLoomTask {
|
||||
Files.createDirectories(outputDir);
|
||||
|
||||
File mappings = loadMappings();
|
||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
|
||||
|
||||
try {
|
||||
MemoryMappingTree currentMappings = mappingsProvider.getMappings();
|
||||
try (var serviceManager = new ScopedSharedServiceManager()) {
|
||||
MemoryMappingTree currentMappings = mappingConfiguration.getMappingsService(serviceManager).getMappingTree();
|
||||
MemoryMappingTree targetMappings = getMappings(mappings);
|
||||
migrateMappings(project, extension, inputDir, outputDir, currentMappings, targetMappings);
|
||||
project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath());
|
||||
|
||||
@@ -78,7 +78,7 @@ public abstract class PrepareJarRemapTask extends AbstractLoomTask {
|
||||
final WorkQueue workQueue = getWorkerExecutor().noIsolation();
|
||||
|
||||
workQueue.submit(ReadInputsAction.class, params -> {
|
||||
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), remapJarTask.getTinyRemapperService()));
|
||||
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(remapJarTask.getTinyRemapperService()));
|
||||
params.getInputFile().set(getInputFile());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,11 +46,13 @@ import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.Internal;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -58,7 +60,6 @@ import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||
import net.fabricmc.accesswidener.AccessWidenerRemapper;
|
||||
import net.fabricmc.accesswidener.AccessWidenerWriter;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.build.MixinRefmapHelper;
|
||||
import net.fabricmc.loom.build.nesting.IncludedJarFactory;
|
||||
import net.fabricmc.loom.build.nesting.JarNester;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
@@ -67,10 +68,12 @@ import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.service.TinyRemapperService;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ExceptionUtil;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson;
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory;
|
||||
import net.fabricmc.loom.util.service.BuildSharedServiceManager;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
@@ -82,11 +85,18 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
@Input
|
||||
public abstract Property<Boolean> getAddNestedDependencies();
|
||||
|
||||
private Supplier<TinyRemapperService> tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(this));
|
||||
@Input
|
||||
@ApiStatus.Internal
|
||||
public abstract Property<Boolean> getUseMixinAP();
|
||||
|
||||
private final Provider<BuildSharedServiceManager> serviceManagerProvider;
|
||||
private final Supplier<TinyRemapperService> tinyRemapperService;
|
||||
|
||||
@Inject
|
||||
public RemapJarTask() {
|
||||
super();
|
||||
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
|
||||
tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(serviceManagerProvider.get().get(), this));
|
||||
|
||||
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||
getAddNestedDependencies().convention(true).finalizeValueOnRead();
|
||||
@@ -94,6 +104,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE);
|
||||
getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration));
|
||||
|
||||
getUseMixinAP().set(LoomGradleExtension.get(getProject()).getMixin().getUseLegacyMixinAp());
|
||||
|
||||
setupPreparationTask();
|
||||
}
|
||||
|
||||
@@ -115,20 +127,18 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
|
||||
@TaskAction
|
||||
public void run() {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
|
||||
submitWork(RemapAction.class, params -> {
|
||||
if (getAddNestedDependencies().get()) {
|
||||
params.getNestedJars().from(getNestedJars());
|
||||
}
|
||||
|
||||
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), tinyRemapperService.get()));
|
||||
params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(tinyRemapperService.get()));
|
||||
params.getRemapClasspath().from(getClasspath());
|
||||
|
||||
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||
params.getUseMixinExtension().set(!legacyMixin);
|
||||
final boolean mixinAp = getUseMixinAP().get();
|
||||
params.getUseMixinExtension().set(!mixinAp);
|
||||
|
||||
if (legacyMixin) {
|
||||
if (mixinAp) {
|
||||
setupLegacyMixinRefmapRemapping(params);
|
||||
}
|
||||
});
|
||||
@@ -138,14 +148,13 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(getProject());
|
||||
final MixinExtension mixinExtension = extension.getMixin();
|
||||
|
||||
final JsonObject fabricModJson = ModUtils.getFabricModJson(getInputFile().getAsFile().get().toPath());
|
||||
final FabricModJson fabricModJson = FabricModJsonFactory.createFromZipNullable(getInputFile().getAsFile().get().toPath());
|
||||
|
||||
if (fabricModJson == null) {
|
||||
getProject().getLogger().warn("Could not find fabric.mod.json file in: " + getInputFile().getAsFile().get().getName());
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<String> allMixinConfigs = MixinRefmapHelper.getMixinConfigurationFiles(fabricModJson);
|
||||
final Collection<String> allMixinConfigs = fabricModJson.getMixinConfigurations();
|
||||
|
||||
for (SourceSet sourceSet : mixinExtension.getMixinSourceSets()) {
|
||||
MixinExtension.MixinInformationContainer container = Objects.requireNonNull(
|
||||
|
||||
@@ -32,6 +32,7 @@ import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.slf4j.Logger;
|
||||
@@ -39,12 +40,16 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.task.service.SourceRemapperService;
|
||||
import net.fabricmc.loom.util.service.BuildSharedServiceManager;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
|
||||
public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||
private final Provider<BuildSharedServiceManager> serviceManagerProvider;
|
||||
|
||||
@Inject
|
||||
public RemapSourcesJarTask() {
|
||||
super();
|
||||
serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry());
|
||||
|
||||
getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME));
|
||||
}
|
||||
@@ -52,7 +57,7 @@ public abstract class RemapSourcesJarTask extends AbstractRemapJarTask {
|
||||
@TaskAction
|
||||
public void run() {
|
||||
submitWork(RemapSourcesAction.class, params -> {
|
||||
params.getSourcesRemapperServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), SourceRemapperService.create(this)));
|
||||
params.getSourcesRemapperServiceUuid().set(UnsafeWorkQueueHelper.create(SourceRemapperService.create(serviceManagerProvider.get().get(), this)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
MappedMinecraftProvider.Split split = (MappedMinecraftProvider.Split) getExtension().getNamedMinecraftProvider();
|
||||
|
||||
return switch (env) {
|
||||
case "client" -> split.getClientOnlyJar().toAbsolutePath().toString();
|
||||
case "common" -> split.getCommonJar().toAbsolutePath().toString();
|
||||
case "client" -> split.getClientOnlyJar().getPath().toAbsolutePath().toString();
|
||||
case "common" -> split.getCommonJar().getPath().toAbsolutePath().toString();
|
||||
default -> throw new UnsupportedOperationException();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.gradle.util.GradleVersion;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
@@ -63,10 +64,10 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
|
||||
params.getGradleVersion().set(GradleVersion.current().getVersion());
|
||||
params.getLoomVersion().set(LoomGradlePlugin.LOOM_VERSION);
|
||||
params.getMCEVersion().set(Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS);
|
||||
params.getMinecraftVersion().set(extension.getMinecraftProvider().minecraftVersion());
|
||||
params.getMinecraftVersion().set(project.provider(() -> extension.getMinecraftProvider().minecraftVersion()));
|
||||
params.getTinyRemapperVersion().set(tinyRemapperVersion.orElse("unknown"));
|
||||
params.getFabricLoaderVersion().set(getLoaderVersion(project).orElse("unknown"));
|
||||
params.getMixinVersion().set(getMixinVersion(project).orElse(new MixinVersion("unknown", "unknown")));
|
||||
params.getFabricLoaderVersion().set(project.provider(() -> Optional.ofNullable(extension.getInstallerData()).map(InstallerData::version).orElse("unknown")));
|
||||
params.getMixinVersion().set(getMixinVersion(project));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -98,31 +99,23 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> getLoaderVersion(Project project) {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (extension.getInstallerData() == null) {
|
||||
project.getLogger().warn("Could not determine fabric loader version for jar manifest");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(extension.getInstallerData().version());
|
||||
}
|
||||
|
||||
private record MixinVersion(String group, String version) implements Serializable { }
|
||||
|
||||
private static Optional<MixinVersion> getMixinVersion(Project project) {
|
||||
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
|
||||
Optional<Dependency> dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES)
|
||||
.getDependencies()
|
||||
.stream()
|
||||
.filter(dep -> "sponge-mixin".equals(dep.getName()))
|
||||
.findFirst();
|
||||
private static Provider<MixinVersion> getMixinVersion(Project project) {
|
||||
return project.getConfigurations().named(Constants.Configurations.LOADER_DEPENDENCIES).map(configuration -> {
|
||||
// Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint
|
||||
Optional<Dependency> dependency = configuration
|
||||
.getDependencies()
|
||||
.stream()
|
||||
.filter(dep -> "sponge-mixin".equals(dep.getName()))
|
||||
.findFirst();
|
||||
|
||||
if (dependency.isEmpty()) {
|
||||
project.getLogger().warn("Could not determine Mixin version for jar manifest");
|
||||
}
|
||||
if (dependency.isEmpty()) {
|
||||
project.getLogger().warn("Could not determine Mixin version for jar manifest");
|
||||
}
|
||||
|
||||
return dependency.map(d -> new MixinVersion(d.getGroup(), d.getVersion()));
|
||||
return dependency.map(d -> new MixinVersion(d.getGroup(), d.getVersion()))
|
||||
.orElse(new MixinVersion("unknown", "unknown"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.nio.file.Path;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
@@ -42,21 +42,17 @@ import net.fabricmc.tinyremapper.IMappingProvider;
|
||||
public final class MappingsService implements SharedService {
|
||||
private record Options(Path mappingsFile, String from, String to, boolean remapLocals) { }
|
||||
|
||||
public static MappingsService create(Project project, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
|
||||
return create(SharedServiceManager.get(project), name, mappingsFile, from, to, remapLocals);
|
||||
}
|
||||
|
||||
public static synchronized MappingsService create(SharedServiceManager sharedServiceManager, String name, Path mappingsFile, String from, String to, boolean remapLocals) {
|
||||
final Options options = new Options(mappingsFile, from, to, remapLocals);
|
||||
final String id = name + options.hashCode();
|
||||
return sharedServiceManager.getOrCreateService(id, () -> new MappingsService(options));
|
||||
}
|
||||
|
||||
public static MappingsService createDefault(Project project, String from, String to) {
|
||||
final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider();
|
||||
public static MappingsService createDefault(Project project, SharedServiceManager serviceManager, String from, String to) {
|
||||
final MappingConfiguration mappingConfiguration = LoomGradleExtension.get(project).getMappingConfiguration();
|
||||
|
||||
final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to);
|
||||
return MappingsService.create(project, name, mappingsProvider.tinyMappings, from, to, false);
|
||||
final String name = mappingConfiguration.getBuildServiceName("mappingsProvider", from, to);
|
||||
return MappingsService.create(serviceManager, name, mappingConfiguration.tinyMappings, from, to, false);
|
||||
}
|
||||
|
||||
private final Options options;
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.task.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.tinyremapper.IMappingProvider;
|
||||
|
||||
public final class MixinMappingsService implements SharedService {
|
||||
private final SharedServiceManager sharedServiceManager;
|
||||
private final HashSet<File> mixinMappings = new HashSet<>();
|
||||
|
||||
private MixinMappingsService(SharedServiceManager sharedServiceManager) {
|
||||
this.sharedServiceManager = sharedServiceManager;
|
||||
}
|
||||
|
||||
public static File getMixinMappingFile(Project project, SourceSet sourceSet) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
File mixinMapping = new File(extension.getFiles().getProjectBuildCache(), "mixin-map-" + extension.getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny");
|
||||
|
||||
getService(SharedServiceManager.get(project), extension.getMappingsProvider()).mixinMappings.add(mixinMapping);
|
||||
|
||||
return mixinMapping;
|
||||
}
|
||||
|
||||
static synchronized MixinMappingsService getService(SharedServiceManager sharedServiceManager, MappingsProviderImpl mappingsProvider) {
|
||||
return sharedServiceManager.getOrCreateService("MixinMappings-" + mappingsProvider.mappingsIdentifier(), () -> new MixinMappingsService(sharedServiceManager));
|
||||
}
|
||||
|
||||
IMappingProvider getMappingProvider(String from, String to) {
|
||||
return out -> {
|
||||
for (File mixinMapping : mixinMappings) {
|
||||
if (!mixinMapping.exists()) continue;
|
||||
|
||||
MappingsService service = MappingsService.create(sharedServiceManager, mixinMapping.getAbsolutePath(), mixinMapping.toPath(), from, to, false);
|
||||
service.getMappingsProvider().load(out);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -52,16 +52,15 @@ import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||
|
||||
public final class SourceRemapperService implements SharedService {
|
||||
public static synchronized SourceRemapperService create(RemapSourcesJarTask task) {
|
||||
public static synchronized SourceRemapperService create(SharedServiceManager serviceManager, RemapSourcesJarTask task) {
|
||||
final Project project = task.getProject();
|
||||
final String to = task.getTargetNamespace().get();
|
||||
final String from = task.getSourceNamespace().get();
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
final String id = extension.getMappingsProvider().getBuildServiceName("sourceremapper", from, to);
|
||||
final String id = extension.getMappingConfiguration().getBuildServiceName("sourceremapper", from, to);
|
||||
|
||||
return sharedServiceManager.getOrCreateService(id, () ->
|
||||
new SourceRemapperService(MappingsService.createDefault(project, from, to), task.getClasspath()
|
||||
return serviceManager.getOrCreateService(id, () ->
|
||||
new SourceRemapperService(MappingsService.createDefault(project, serviceManager, from, to), task.getClasspath()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,10 +37,15 @@ import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.build.mixin.AnnotationProcessorInvoker;
|
||||
import net.fabricmc.loom.task.AbstractRemapJarTask;
|
||||
import net.fabricmc.loom.util.gradle.GradleUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspath;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspathService;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader;
|
||||
@@ -51,18 +56,17 @@ import net.fabricmc.tinyremapper.InputTag;
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public class TinyRemapperService implements SharedService {
|
||||
public static synchronized TinyRemapperService getOrCreate(AbstractRemapJarTask remapJarTask) {
|
||||
public static synchronized TinyRemapperService getOrCreate(SharedServiceManager serviceManager, AbstractRemapJarTask remapJarTask) {
|
||||
final Project project = remapJarTask.getProject();
|
||||
final String to = remapJarTask.getTargetNamespace().get();
|
||||
final String from = remapJarTask.getSourceNamespace().get();
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||
final @Nullable KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(project);
|
||||
final @Nullable KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(serviceManager, project);
|
||||
|
||||
// Generates an id that is used to share the remapper across projects. This tasks in the remap jar task name to handle custom remap jar tasks separately.
|
||||
final var joiner = new StringJoiner(":");
|
||||
joiner.add(extension.getMappingsProvider().getBuildServiceName("remapJarService", from, to));
|
||||
joiner.add(extension.getMappingConfiguration().getBuildServiceName("remapJarService", from, to));
|
||||
joiner.add(remapJarTask.getName());
|
||||
|
||||
if (kotlinClasspathService != null) {
|
||||
@@ -75,12 +79,12 @@ public class TinyRemapperService implements SharedService {
|
||||
|
||||
final String id = joiner.toString();
|
||||
|
||||
TinyRemapperService service = sharedServiceManager.getOrCreateService(id, () -> {
|
||||
TinyRemapperService service = serviceManager.getOrCreateService(id, () -> {
|
||||
List<IMappingProvider> mappings = new ArrayList<>();
|
||||
mappings.add(MappingsService.createDefault(project, from, to).getMappingsProvider());
|
||||
mappings.add(MappingsService.createDefault(project, serviceManager, from, to).getMappingsProvider());
|
||||
|
||||
if (legacyMixin) {
|
||||
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project), extension.getMappingsProvider()).getMappingProvider(from, to));
|
||||
mappings.add(gradleMixinMappingProvider(serviceManager, project.getGradle(), extension.getMappingConfiguration().mappingsIdentifier, from, to));
|
||||
}
|
||||
|
||||
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService);
|
||||
@@ -91,6 +95,29 @@ public class TinyRemapperService implements SharedService {
|
||||
return service;
|
||||
}
|
||||
|
||||
// Add all of the mixin mappings from all loom projects.
|
||||
private static IMappingProvider gradleMixinMappingProvider(SharedServiceManager serviceManager, Gradle gradle, String mappingId, String from, String to) {
|
||||
return out -> GradleUtils.allLoomProjects(gradle, project -> {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
if (!mappingId.equals(extension.getMappingConfiguration().mappingsIdentifier)) {
|
||||
// Only find mixin mappings that are from other projects with the same mapping id.
|
||||
return;
|
||||
}
|
||||
|
||||
for (SourceSet sourceSet : SourceSetHelper.getSourceSets(project)) {
|
||||
final File mixinMappings = AnnotationProcessorInvoker.getMixinMappingsForSourceSet(project, sourceSet);
|
||||
|
||||
if (!mixinMappings.exists()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MappingsService service = MappingsService.create(serviceManager, mixinMappings.getAbsolutePath(), mixinMappings.toPath(), from, to, false);
|
||||
service.getMappingsProvider().load(out);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private TinyRemapper tinyRemapper;
|
||||
@Nullable
|
||||
private KotlinRemapperClassloader kotlinRemapperClassloader;
|
||||
|
||||
@@ -31,8 +31,8 @@ import org.gradle.api.logging.LogLevel;
|
||||
import org.gradle.api.logging.configuration.WarningMode;
|
||||
|
||||
public interface DeprecationHelper {
|
||||
default void replaceWithInLoom0_12(String currentName, String newName) {
|
||||
toBeRemovedIn(currentName, newName, "Loom 0.12");
|
||||
default void replaceWithInLoom2_0(String currentName, String newName) {
|
||||
toBeRemovedIn(currentName, newName, "Loom 2.0");
|
||||
}
|
||||
|
||||
default void toBeRemovedIn(String currentName, String newName, String removalVersion) {
|
||||
@@ -49,13 +49,6 @@ public interface DeprecationHelper {
|
||||
|
||||
public ProjectBased(Project project) {
|
||||
this.project = project;
|
||||
|
||||
project.getGradle().buildFinished(buildResult -> {
|
||||
if (usingDeprecatedApi.get()) {
|
||||
project.getLogger().lifecycle("Deprecated Loom APIs were used in this build, making it incompatible with future versions of Loom. "
|
||||
+ "Use Gradle warning modes to control the verbosity of the warnings.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,19 +45,22 @@ import org.slf4j.Logger;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.RemapConfigurationSettings;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public class SourceRemapper {
|
||||
private final Project project;
|
||||
private final SharedServiceManager serviceManager;
|
||||
private final boolean toNamed;
|
||||
private final List<Consumer<ProgressLogger>> remapTasks = new ArrayList<>();
|
||||
|
||||
private Mercury mercury;
|
||||
|
||||
public SourceRemapper(Project project, boolean toNamed) {
|
||||
public SourceRemapper(Project project, SharedServiceManager serviceManager, boolean toNamed) {
|
||||
this.project = project;
|
||||
this.serviceManager = serviceManager;
|
||||
this.toNamed = toNamed;
|
||||
}
|
||||
|
||||
@@ -158,11 +161,11 @@ public class SourceRemapper {
|
||||
}
|
||||
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
|
||||
|
||||
MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> {
|
||||
try {
|
||||
MemoryMappingTree m = mappingsProvider.getMappings();
|
||||
MemoryMappingTree m = mappingConfiguration.getMappingsService(serviceManager).getMappingTree();
|
||||
project.getLogger().info(":loading " + (toNamed ? "intermediary -> named" : "named -> intermediary") + " source mappings");
|
||||
return new TinyMappingsReader(m, toNamed ? MappingsNamespace.INTERMEDIARY.toString() : MappingsNamespace.NAMED.toString(), toNamed ? MappingsNamespace.NAMED.toString() : MappingsNamespace.INTERMEDIARY.toString()).read();
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.tree.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
@@ -60,13 +61,13 @@ public final class TinyRemapperHelper {
|
||||
private TinyRemapperHelper() {
|
||||
}
|
||||
|
||||
public static TinyRemapper getTinyRemapper(Project project, String fromM, String toM) throws IOException {
|
||||
return getTinyRemapper(project, fromM, toM, false, (builder) -> { });
|
||||
public static TinyRemapper getTinyRemapper(Project project, SharedServiceManager serviceManager, String fromM, String toM) throws IOException {
|
||||
return getTinyRemapper(project, serviceManager, fromM, toM, false, (builder) -> { });
|
||||
}
|
||||
|
||||
public static TinyRemapper getTinyRemapper(Project project, String fromM, String toM, boolean fixRecords, Consumer<TinyRemapper.Builder> builderConsumer) throws IOException {
|
||||
public static TinyRemapper getTinyRemapper(Project project, SharedServiceManager serviceManager, String fromM, String toM, boolean fixRecords, Consumer<TinyRemapper.Builder> builderConsumer) throws IOException {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
MemoryMappingTree mappingTree = extension.getMappingsProvider().getMappings();
|
||||
MemoryMappingTree mappingTree = extension.getMappingConfiguration().getMappingsService(serviceManager).getMappingTree();
|
||||
|
||||
if (fixRecords && !mappingTree.getSrcNamespace().equals(fromM)) {
|
||||
throw new IllegalStateException("Mappings src namespace must match remap src namespace");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2018-2022 FabricMC
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,40 +22,40 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.build;
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import static net.fabricmc.loom.util.fmj.FabricModJsonUtils.readString;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class MixinRefmapHelper {
|
||||
private MixinRefmapHelper() { }
|
||||
public abstract sealed class FabricModJson permits FabricModJsonV0, FabricModJsonV1, FabricModJsonV2 {
|
||||
protected final JsonObject jsonObject;
|
||||
private final FabricModJsonSource source;
|
||||
|
||||
private static final String FABRIC_MOD_JSON = "fabric.mod.json";
|
||||
protected FabricModJson(JsonObject jsonObject, FabricModJsonSource source) {
|
||||
this.jsonObject = Objects.requireNonNull(jsonObject);
|
||||
this.source = Objects.requireNonNull(source);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Collection<String> getMixinConfigurationFiles(JsonObject fabricModJson) {
|
||||
JsonArray mixins = fabricModJson.getAsJsonArray("mixins");
|
||||
public abstract int getVersion();
|
||||
|
||||
if (mixins == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
public String getId() {
|
||||
return readString(jsonObject, "id");
|
||||
}
|
||||
|
||||
return StreamSupport.stream(mixins.spliterator(), false)
|
||||
.map(e -> {
|
||||
if (e instanceof JsonPrimitive str) {
|
||||
return str.getAsString();
|
||||
} else if (e instanceof JsonObject obj) {
|
||||
return obj.get("config").getAsString();
|
||||
} else {
|
||||
throw new RuntimeException("Incorrect fabric.mod.json format");
|
||||
}
|
||||
}).collect(Collectors.toSet());
|
||||
@Nullable
|
||||
public abstract JsonElement getCustom(String key);
|
||||
|
||||
public abstract List<String> getMixinConfigurations();
|
||||
|
||||
public abstract List<String> getClassTweakers(ModEnvironment modEnvironment);
|
||||
|
||||
public final FabricModJsonSource getSource() {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import static net.fabricmc.loom.util.fmj.FabricModJsonUtils.readInt;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
|
||||
public final class FabricModJsonFactory {
|
||||
private static final String FABRIC_MOD_JSON = "fabric.mod.json";
|
||||
|
||||
private FabricModJsonFactory() {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static FabricModJson create(JsonObject jsonObject, FabricModJsonSource source) {
|
||||
int schemaVersion = 0;
|
||||
|
||||
if (jsonObject.has("schemaVersion")) {
|
||||
// V0 had no schemaVersion key.
|
||||
schemaVersion = readInt(jsonObject, "schemaVersion");
|
||||
}
|
||||
|
||||
return switch (schemaVersion) {
|
||||
case 0 -> new FabricModJsonV0(jsonObject, source);
|
||||
case 1 -> new FabricModJsonV1(jsonObject, source);
|
||||
case 2 -> new FabricModJsonV2(jsonObject, source);
|
||||
default -> throw new UnsupportedOperationException(String.format("This version of fabric-loom doesn't support the newer fabric.mod.json schema version of (%s) Please update fabric-loom to be able to read this.", schemaVersion));
|
||||
};
|
||||
}
|
||||
|
||||
public static FabricModJson createFromZip(Path zipPath) {
|
||||
try {
|
||||
return create(ZipUtils.unpackGson(zipPath, FABRIC_MOD_JSON, JsonObject.class), new FabricModJsonSource.ZipSource(zipPath));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read fabric.mod.json file in zip: " + zipPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FabricModJson createFromZipNullable(Path zipPath) {
|
||||
JsonObject jsonObject;
|
||||
|
||||
try {
|
||||
jsonObject = ZipUtils.unpackGsonNullable(zipPath, FABRIC_MOD_JSON, JsonObject.class);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read zip: " + zipPath, e);
|
||||
}
|
||||
|
||||
if (jsonObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return create(jsonObject, new FabricModJsonSource.ZipSource(zipPath));
|
||||
}
|
||||
|
||||
public static Optional<FabricModJson> createFromZipOptional(Path zipPath) {
|
||||
return Optional.ofNullable(createFromZipNullable(zipPath));
|
||||
}
|
||||
|
||||
public static FabricModJson createFromDirectory(Path directory) throws IOException {
|
||||
final Path path = directory.resolve(FABRIC_MOD_JSON);
|
||||
|
||||
try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
|
||||
return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new FabricModJsonSource.DirectorySource(directory));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FabricModJson createFromSourceSetsNullable(SourceSet... sourceSets) throws IOException {
|
||||
final File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, sourceSets);
|
||||
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (Reader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
return create(LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class), new FabricModJsonSource.SourceSetSource(sourceSets));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isModJar(File file) {
|
||||
return isModJar(file.toPath());
|
||||
}
|
||||
|
||||
public static boolean isModJar(Path input) {
|
||||
return ZipUtils.contains(input, FABRIC_MOD_JSON);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
|
||||
/**
|
||||
* A mod may be a zip, directory or Gradle {@link SourceSet}
|
||||
* This abstraction allows easily reading a contained file from the mod.
|
||||
*/
|
||||
public interface FabricModJsonSource {
|
||||
byte[] read(String path) throws IOException;
|
||||
|
||||
record ZipSource(Path zipPath) implements FabricModJsonSource {
|
||||
@Override
|
||||
public byte[] read(String path) throws IOException {
|
||||
return ZipUtils.unpack(zipPath, path);
|
||||
}
|
||||
}
|
||||
|
||||
record DirectorySource(Path directoryPath) implements FabricModJsonSource {
|
||||
@Override
|
||||
public byte[] read(String path) throws IOException {
|
||||
return Files.readAllBytes(directoryPath.resolve(path));
|
||||
}
|
||||
}
|
||||
|
||||
record SourceSetSource(SourceSet... sourceSets) implements FabricModJsonSource {
|
||||
@Override
|
||||
public byte[] read(String path) throws IOException {
|
||||
final File file = SourceSetHelper.findFirstFileInResource(path, sourceSets);
|
||||
|
||||
if (file == null) {
|
||||
throw new FileNotFoundException("Could not find: " + path);
|
||||
}
|
||||
|
||||
return Files.readAllBytes(file.toPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
final class FabricModJsonUtils {
|
||||
private FabricModJsonUtils() {
|
||||
}
|
||||
|
||||
public static String readString(JsonObject jsonObject, String key) {
|
||||
final JsonElement element = getElement(jsonObject, key);
|
||||
ensurePrimitive(element, JsonPrimitive::isString, key);
|
||||
|
||||
return element.getAsString();
|
||||
}
|
||||
|
||||
public static int readInt(JsonObject jsonObject, String key) {
|
||||
final JsonElement element = getElement(jsonObject, key);
|
||||
ensurePrimitive(element, JsonPrimitive::isNumber, key);
|
||||
|
||||
return element.getAsInt();
|
||||
}
|
||||
|
||||
private static JsonElement getElement(JsonObject jsonObject, String key) {
|
||||
final JsonElement element = jsonObject.get(key);
|
||||
|
||||
if (element == null) {
|
||||
throw new ParseException("Unable to find json element for key (%s)", key);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private static void ensurePrimitive(JsonElement jsonElement, Predicate<JsonPrimitive> predicate, String key) {
|
||||
if (!jsonElement.isJsonPrimitive() || !predicate.test(jsonElement.getAsJsonPrimitive())) {
|
||||
throw new ParseException("Unexpected primitive type for key (%s)", key);
|
||||
}
|
||||
}
|
||||
|
||||
static class ParseException extends RuntimeException {
|
||||
ParseException(String message, Object... args) {
|
||||
super(String.format(Locale.ROOT, message, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Deprecated
|
||||
public final class FabricModJsonV0 extends FabricModJson {
|
||||
FabricModJsonV0(JsonObject jsonObject, FabricModJsonSource source) {
|
||||
super(jsonObject, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JsonElement getCustom(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixinConfigurations() {
|
||||
final JsonObject mixinsObject = jsonObject.getAsJsonObject("mixins");
|
||||
|
||||
if (mixinsObject == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<String> mixins = new ArrayList<>();
|
||||
|
||||
for (String key : mixinsObject.keySet()) {
|
||||
final JsonElement jsonElement = mixinsObject.get(key);
|
||||
|
||||
if (jsonElement instanceof JsonArray jsonArray) {
|
||||
for (JsonElement arrayElement : jsonArray) {
|
||||
if (arrayElement instanceof JsonPrimitive jsonPrimitive && jsonPrimitive.isString()) {
|
||||
mixins.add(jsonPrimitive.getAsString());
|
||||
} else {
|
||||
throw new FabricModJsonUtils.ParseException("Expected entries in mixin %s to be an array of strings", key);
|
||||
}
|
||||
}
|
||||
} else if (jsonElement instanceof JsonPrimitive jsonPrimitive && jsonPrimitive.isString()) {
|
||||
mixins.add(jsonPrimitive.getAsString());
|
||||
} else {
|
||||
throw new FabricModJsonUtils.ParseException("Expected mixin %s to be a string or an array of strings", key);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(mixins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getClassTweakers(ModEnvironment modEnvironment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
101
src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonV1.java
Normal file
101
src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonV1.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import static net.fabricmc.loom.util.fmj.FabricModJsonUtils.readString;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public final class FabricModJsonV1 extends FabricModJson {
|
||||
FabricModJsonV1(JsonObject jsonObject, FabricModJsonSource source) {
|
||||
super(jsonObject, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JsonElement getCustom(String key) {
|
||||
return getCustom(jsonObject, key);
|
||||
}
|
||||
|
||||
static JsonElement getCustom(JsonObject jsonObject, String key) {
|
||||
if (!jsonObject.has("custom")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final JsonObject custom = jsonObject.getAsJsonObject("custom");
|
||||
|
||||
if (!custom.has(key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return custom.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixinConfigurations() {
|
||||
final JsonArray mixinArray = jsonObject.getAsJsonArray("mixins");
|
||||
|
||||
if (mixinArray == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return StreamSupport.stream(mixinArray.spliterator(), false)
|
||||
.map(FabricModJsonV1::readMixinElement)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static String readMixinElement(JsonElement jsonElement) {
|
||||
if (jsonElement instanceof JsonPrimitive str) {
|
||||
return str.getAsString();
|
||||
} else if (jsonElement instanceof JsonObject obj) {
|
||||
return obj.get("config").getAsString();
|
||||
} else {
|
||||
throw new FabricModJsonUtils.ParseException("Expected mixin element to be an object or string");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getClassTweakers(ModEnvironment modEnvironment) {
|
||||
if (!jsonObject.has("accessWidener")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return List.of(readString(jsonObject, "accessWidener"));
|
||||
}
|
||||
}
|
||||
133
src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonV2.java
Normal file
133
src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonV2.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public final class FabricModJsonV2 extends FabricModJson {
|
||||
FabricModJsonV2(JsonObject jsonObject, FabricModJsonSource source) {
|
||||
super(jsonObject, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JsonElement getCustom(String key) {
|
||||
return FabricModJsonV1.getCustom(jsonObject, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixinConfigurations() {
|
||||
if (!jsonObject.has("mixins")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return getConditionalConfigs(jsonObject.get("mixins"), ModEnvironment.UNIVERSAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getClassTweakers(ModEnvironment modEnvironment) {
|
||||
if (!jsonObject.has("classTweakers")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return getConditionalConfigs(jsonObject.get("classTweakers"), modEnvironment);
|
||||
}
|
||||
|
||||
private List<String> getConditionalConfigs(JsonElement jsonElement, ModEnvironment modEnvironment) {
|
||||
final List<String> values = new ArrayList<>();
|
||||
|
||||
if (jsonElement instanceof JsonArray jsonArray) {
|
||||
for (JsonElement arrayElement : jsonArray) {
|
||||
final String value = readConditionalConfig(arrayElement, modEnvironment);
|
||||
|
||||
if (value != null) {
|
||||
values.add(value);
|
||||
}
|
||||
}
|
||||
} else if (jsonElement instanceof JsonPrimitive jsonPrimitive && jsonPrimitive.isString()) {
|
||||
final String value = readConditionalConfig(jsonPrimitive, modEnvironment);
|
||||
|
||||
if (value != null) {
|
||||
values.add(value);
|
||||
}
|
||||
} else {
|
||||
throw new FabricModJsonUtils.ParseException("Must be a string or array of strings");
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String readConditionalConfig(JsonElement jsonElement, ModEnvironment modEnvironment) {
|
||||
if (jsonElement instanceof JsonPrimitive jsonPrimitive && jsonPrimitive.isString()) {
|
||||
return jsonElement.getAsString();
|
||||
} else if (jsonElement instanceof JsonObject jsonObject) {
|
||||
final String config = FabricModJsonUtils.readString(jsonObject, "config");
|
||||
|
||||
if (!validForEnvironment(jsonObject, modEnvironment)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return config;
|
||||
} else {
|
||||
throw new FabricModJsonUtils.ParseException("Must be a string or an object");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validForEnvironment(JsonObject jsonObject, ModEnvironment modEnvironment) {
|
||||
if (!jsonObject.has("environment")) {
|
||||
// Default enabled for all envs.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(jsonObject.get("environment") instanceof JsonPrimitive jsonPrimitive) || !jsonPrimitive.isString()) {
|
||||
throw new FabricModJsonUtils.ParseException("Environment must be a string");
|
||||
}
|
||||
|
||||
final String environment = jsonPrimitive.getAsString();
|
||||
|
||||
return switch (environment) {
|
||||
case "*" -> true;
|
||||
case "client" -> modEnvironment.isClient();
|
||||
case "server" -> modEnvironment.isServer();
|
||||
default -> throw new FabricModJsonUtils.ParseException("Invalid environment type: " + environment);
|
||||
};
|
||||
}
|
||||
}
|
||||
47
src/main/java/net/fabricmc/loom/util/fmj/ModEnvironment.java
Normal file
47
src/main/java/net/fabricmc/loom/util/fmj/ModEnvironment.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.fmj;
|
||||
|
||||
public enum ModEnvironment {
|
||||
UNIVERSAL(true, true),
|
||||
CLIENT(true, false),
|
||||
SERVER(false, true);
|
||||
|
||||
private final boolean client;
|
||||
private final boolean server;
|
||||
|
||||
ModEnvironment(boolean client, boolean server) {
|
||||
this.client = client;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public boolean isClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,10 @@
|
||||
|
||||
package net.fabricmc.loom.util.gradle;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
|
||||
public final class GradleUtils {
|
||||
private GradleUtils() {
|
||||
@@ -41,4 +44,12 @@ public final class GradleUtils {
|
||||
afterEvaluate.run();
|
||||
});
|
||||
}
|
||||
|
||||
public static void allLoomProjects(Gradle gradle, Consumer<Project> consumer) {
|
||||
gradle.allprojects(project -> {
|
||||
if (project.getPluginManager().hasPlugin("fabric-loom")) {
|
||||
consumer.accept(project);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -42,6 +43,7 @@ import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.api.tasks.SourceSetOutput;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -59,20 +61,23 @@ public final class SourceSetHelper {
|
||||
private SourceSetHelper() {
|
||||
}
|
||||
|
||||
public static SourceSetContainer getSourceSets(Project project) {
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
return javaExtension.getSourceSets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the provided project contains the {@link SourceSet}.
|
||||
*/
|
||||
public static boolean isSourceSetOfProject(SourceSet sourceSet, Project project) {
|
||||
if (System.getProperty("fabric-loom.unit.testing") != null) return true;
|
||||
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
return javaExtension.getSourceSets().stream()
|
||||
return getSourceSets(project).stream()
|
||||
.anyMatch(test -> test == sourceSet); // Ensure we have an identical reference
|
||||
}
|
||||
|
||||
public static SourceSet getSourceSetByName(String name, Project project) {
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
return javaExtension.getSourceSets().getByName(name);
|
||||
return getSourceSets(project).getByName(name);
|
||||
}
|
||||
|
||||
public static SourceSet getMainSourceSet(Project project) {
|
||||
@@ -80,8 +85,7 @@ public final class SourceSetHelper {
|
||||
}
|
||||
|
||||
public static SourceSet createSourceSet(String name, Project project) {
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
return javaExtension.getSourceSets().create(name);
|
||||
return getSourceSets(project).create(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,4 +230,32 @@ public final class SourceSetHelper {
|
||||
|
||||
return Collections.singletonList(new File(binDir, reference.sourceSet().getName()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File findFileInResource(SourceSet sourceSet, String path) {
|
||||
Objects.requireNonNull(sourceSet);
|
||||
Objects.requireNonNull(path);
|
||||
|
||||
try {
|
||||
return sourceSet.getResources()
|
||||
.matching(patternFilterable -> patternFilterable.include(path))
|
||||
.getSingleFile();
|
||||
} catch (IllegalStateException e) {
|
||||
// File not found
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File findFirstFileInResource(String path, SourceSet... sourceSets) {
|
||||
for (SourceSet sourceSet : sourceSets) {
|
||||
File file = findFileInResource(sourceSet, path);
|
||||
|
||||
if (file != null) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,17 +39,16 @@ import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
public record KotlinClasspathService(Set<URL> classpath, String version) implements KotlinClasspath, SharedService {
|
||||
@Nullable
|
||||
public static KotlinClasspathService getOrCreateIfRequired(Project project) {
|
||||
public static KotlinClasspathService getOrCreateIfRequired(SharedServiceManager sharedServiceManager, Project project) {
|
||||
if (!KotlinPluginUtils.hasKotlinPlugin(project)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getOrCreate(project, KotlinPluginUtils.getKotlinPluginVersion(project), KotlinPluginUtils.getKotlinMetadataVersion());
|
||||
return getOrCreate(sharedServiceManager, project, KotlinPluginUtils.getKotlinPluginVersion(project), KotlinPluginUtils.getKotlinMetadataVersion());
|
||||
}
|
||||
|
||||
public static synchronized KotlinClasspathService getOrCreate(Project project, String kotlinVersion, String kotlinMetadataVersion) {
|
||||
public static synchronized KotlinClasspathService getOrCreate(SharedServiceManager sharedServiceManager, Project project, String kotlinVersion, String kotlinMetadataVersion) {
|
||||
final String id = "kotlinclasspath:%s:%s".formatted(kotlinVersion, kotlinMetadataVersion);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
return sharedServiceManager.getOrCreateService(id, () -> create(project, kotlinVersion, kotlinMetadataVersion));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.service;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.services.BuildService;
|
||||
import org.gradle.api.services.BuildServiceParameters;
|
||||
import org.gradle.build.event.BuildEventsListenerRegistry;
|
||||
import org.gradle.tooling.events.OperationCompletionListener;
|
||||
import org.gradle.tooling.events.task.TaskOperationDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class BuildSharedServiceManager implements BuildService<BuildServiceParameters.None> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BuildSharedServiceManager.class);
|
||||
private static final String NAME = "loom:sharedServiceManager";
|
||||
|
||||
private SharedServiceManager sharedServiceManager = new BuildSharedServiceManagerImpl();
|
||||
private final AtomicInteger refCount = new AtomicInteger(0);
|
||||
|
||||
public static Provider<BuildSharedServiceManager> createForTask(Task task, BuildEventsListenerRegistry buildEventsListenerRegistry) {
|
||||
Provider<BuildSharedServiceManager> provider = task.getProject().getGradle().getSharedServices().registerIfAbsent(NAME, BuildSharedServiceManager.class, spec -> {
|
||||
});
|
||||
task.usesService(provider);
|
||||
|
||||
final BuildSharedServiceManager serviceManager = provider.get();
|
||||
buildEventsListenerRegistry.onTaskCompletion(registerTaskCompletion(task, serviceManager::onFinish));
|
||||
int count = serviceManager.refCount.incrementAndGet();
|
||||
LOGGER.debug("Creating shared service manager provider for task: {} count: {}", task.getName(), count);
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
public BuildSharedServiceManager() {
|
||||
LOGGER.debug("New BuildSharedServiceManager instance");
|
||||
}
|
||||
|
||||
public SharedServiceManager get() {
|
||||
LOGGER.debug("Shared build service get");
|
||||
return Objects.requireNonNull(sharedServiceManager);
|
||||
}
|
||||
|
||||
private void onFinish() {
|
||||
int count = refCount.decrementAndGet();
|
||||
|
||||
LOGGER.debug("Build service finish. count: {}", count);
|
||||
|
||||
if (count == 0) {
|
||||
sharedServiceManager.onFinish();
|
||||
sharedServiceManager = null;
|
||||
} else if (count < 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
private static Provider<OperationCompletionListener> registerTaskCompletion(Task task, Runnable runnable) {
|
||||
return task.getProject().provider(() -> event -> {
|
||||
if (event.getDescriptor() instanceof TaskOperationDescriptor taskDescriptor) {
|
||||
if (taskDescriptor.getTaskPath().equals(task.getPath())) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static final class BuildSharedServiceManagerImpl extends SharedServiceManager {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.util.service;
|
||||
|
||||
public final class ScopedSharedServiceManager extends SharedServiceManager implements AutoCloseable {
|
||||
public ScopedSharedServiceManager() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
onFinish();
|
||||
}
|
||||
}
|
||||
@@ -26,38 +26,26 @@ package net.fabricmc.loom.util.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.gradle.BuildResult;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.invocation.Gradle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple manager for {@link SharedService} to be used across gradle (sub) projects.
|
||||
* This is a basic replacement for gradle's build service api.
|
||||
*/
|
||||
public final class SharedServiceManager {
|
||||
private static final Map<Gradle, SharedServiceManager> SERVICE_FACTORY_MAP = new ConcurrentHashMap<>();
|
||||
private final Gradle gradle;
|
||||
|
||||
private final Map<String, SharedService> sharedServiceMap = new ConcurrentHashMap<>();
|
||||
public abstract class SharedServiceManager {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BuildSharedServiceManager.class);
|
||||
private final Map<String, SharedService> sharedServiceMap = new HashMap<>();
|
||||
|
||||
private boolean shutdown = false;
|
||||
|
||||
private SharedServiceManager(Gradle gradle) {
|
||||
this.gradle = gradle;
|
||||
this.gradle.buildFinished(this::onFinish);
|
||||
}
|
||||
|
||||
public static SharedServiceManager get(Project project) {
|
||||
return get(project.getGradle());
|
||||
}
|
||||
|
||||
public static SharedServiceManager get(Gradle gradle) {
|
||||
return SERVICE_FACTORY_MAP.computeIfAbsent(gradle, SharedServiceManager::new);
|
||||
SharedServiceManager() {
|
||||
LOGGER.info("Creating new SharedServiceManager({})", hashCode());
|
||||
}
|
||||
|
||||
public <S extends SharedService> S getOrCreateService(String id, Supplier<S> function) {
|
||||
@@ -70,6 +58,7 @@ public final class SharedServiceManager {
|
||||
S sharedService = (S) sharedServiceMap.get(id);
|
||||
|
||||
if (sharedService == null) {
|
||||
LOGGER.debug("Creating service for {}", id);
|
||||
sharedService = function.get();
|
||||
sharedServiceMap.put(id, sharedService);
|
||||
}
|
||||
@@ -78,12 +67,12 @@ public final class SharedServiceManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void onFinish(BuildResult buildResult) {
|
||||
protected void onFinish() {
|
||||
synchronized (sharedServiceMap) {
|
||||
shutdown = true;
|
||||
}
|
||||
|
||||
SERVICE_FACTORY_MAP.remove(gradle);
|
||||
LOGGER.info("Closing SharedServiceManager({})", hashCode());
|
||||
|
||||
final List<IOException> exceptionList = new ArrayList<>();
|
||||
|
||||
@@ -97,14 +86,14 @@ public final class SharedServiceManager {
|
||||
|
||||
sharedServiceMap.clear();
|
||||
|
||||
// This is required to ensure that mercury releases all of the file handles.
|
||||
System.gc();
|
||||
|
||||
if (!exceptionList.isEmpty()) {
|
||||
// Done to try and close all the services.
|
||||
RuntimeException exception = new RuntimeException("Failed to close all shared services");
|
||||
exceptionList.forEach(exception::addSuppressed);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
// This is required to ensure that mercury releases all of the file handles.
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
// Massive hack to work around WorkerExecutor.noIsolation() doing isolation checks.
|
||||
@@ -38,12 +37,10 @@ public final class UnsafeWorkQueueHelper {
|
||||
private UnsafeWorkQueueHelper() {
|
||||
}
|
||||
|
||||
public static String create(Project project, SharedService service) {
|
||||
public static String create(SharedService service) {
|
||||
final String uuid = UUID.randomUUID().toString();
|
||||
SERVICE_MAP.put(uuid, service);
|
||||
|
||||
// Ensure we don't make a mess if things go wrong.
|
||||
project.getGradle().buildFinished(buildResult -> SERVICE_MAP.remove(uuid));
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ package net.fabricmc.loom.test
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
class LoomTestConstants {
|
||||
private final static String NIGHTLY_VERSION = "8.0-20221001011953+0000"
|
||||
private final static String NIGHTLY_VERSION = "8.0-20221022221212+0000"
|
||||
private final static boolean NIGHTLY_EXISTS = nightlyExists(NIGHTLY_VERSION)
|
||||
|
||||
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
|
||||
|
||||
@@ -43,7 +43,7 @@ class FabricAPIBenchmark implements GradleProjectTestTrait {
|
||||
allowExistingRepo: true,
|
||||
|
||||
repo: "https://github.com/FabricMC/fabric.git",
|
||||
commit: "71b634e5b7845296b11be3fa6545f4fbfacc017f",
|
||||
commit: "5f243a8b7849eac4b30cd876a22a127797a1c406",
|
||||
patch: "fabric_api"
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.unit.fmj
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import net.fabricmc.loom.util.Constants
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonSource
|
||||
import net.fabricmc.loom.util.fmj.ModEnvironment
|
||||
import org.intellij.lang.annotations.Language
|
||||
import spock.lang.Specification
|
||||
|
||||
class FabricModJsonV0Test extends Specification {
|
||||
// I think this is the old v0 format ¯\_(ツ)_/¯
|
||||
@Language("json")
|
||||
static String JSON = """
|
||||
{
|
||||
"id": "example-mod-id",
|
||||
"name": "Example mod name for testing",
|
||||
"version": "1.0.0",
|
||||
"side": "universal",
|
||||
"initializers": [
|
||||
],
|
||||
"mixins": {
|
||||
"client": "mixins.client.json",
|
||||
"common": [
|
||||
"mixins.common.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
static JsonObject JSON_OBJECT = new Gson().fromJson(JSON, JsonObject.class)
|
||||
|
||||
def "version"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.version == 0
|
||||
}
|
||||
|
||||
def "id"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.id == "example-mod-id"
|
||||
}
|
||||
|
||||
def "mixins"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.mixinConfigurations == ["mixins.client.json", "mixins.common.json"]
|
||||
}
|
||||
|
||||
// Not supported in this version
|
||||
def "injected interfaces"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
def jsonObject = fmj.getCustom(Constants.CustomModJsonKeys.INJECTED_INTERFACE)
|
||||
then:
|
||||
jsonObject == null
|
||||
}
|
||||
|
||||
// Not supported in this version
|
||||
def "class tweaker"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.getClassTweakers(ModEnvironment.UNIVERSAL) == []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit.fmj
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import net.fabricmc.loom.util.Constants
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonSource
|
||||
import net.fabricmc.loom.util.fmj.ModEnvironment
|
||||
import org.intellij.lang.annotations.Language
|
||||
import spock.lang.Specification
|
||||
|
||||
class FabricModJsonV1Test extends Specification {
|
||||
@Language("json")
|
||||
static String JSON = """
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "example-mod-id",
|
||||
"name": "Example mod name for testing",
|
||||
"version": "1.0.0",
|
||||
"environment": "client",
|
||||
"license": "Apache-2.0",
|
||||
"mixins": [
|
||||
{
|
||||
"config": "test.client.mixins.json",
|
||||
"environment": "client"
|
||||
},
|
||||
"test.mixins.json"
|
||||
],
|
||||
"accessWidener" : "modid.accesswidener",
|
||||
"custom": {
|
||||
"loom:injected_interfaces": {
|
||||
"net/minecraft/class_123": ["net/test/TestClass"]
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
static JsonObject JSON_OBJECT = new Gson().fromJson(JSON, JsonObject.class)
|
||||
|
||||
def "version"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.version == 1
|
||||
}
|
||||
|
||||
def "id"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.id == "example-mod-id"
|
||||
}
|
||||
|
||||
def "mixins"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.mixinConfigurations == ["test.client.mixins.json", "test.mixins.json"]
|
||||
}
|
||||
|
||||
def "injected interfaces"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
def jsonObject = fmj.getCustom(Constants.CustomModJsonKeys.INJECTED_INTERFACE)
|
||||
then:
|
||||
jsonObject instanceof JsonObject
|
||||
jsonObject.has("net/minecraft/class_123")
|
||||
}
|
||||
|
||||
def "access widener"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.getClassTweakers(ModEnvironment.SERVER) == ["modid.accesswidener"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.unit.fmj
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import net.fabricmc.loom.util.Constants
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonFactory
|
||||
import net.fabricmc.loom.util.fmj.FabricModJsonSource
|
||||
import net.fabricmc.loom.util.fmj.ModEnvironment
|
||||
import org.intellij.lang.annotations.Language
|
||||
import spock.lang.Specification
|
||||
|
||||
class FabricModJsonV2Test extends Specification {
|
||||
@Language("json")
|
||||
static String JSON = """
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"id": "example-mod-id",
|
||||
"name": "Example mod name for testing",
|
||||
"version": "1.0.0",
|
||||
"environment": "client",
|
||||
"license": "Apache-2.0",
|
||||
"mixins": [
|
||||
{
|
||||
"config": "test.client.mixins.json",
|
||||
"environment": "client"
|
||||
},
|
||||
{
|
||||
"config": "test.server.mixins.json",
|
||||
"environment": "server"
|
||||
},
|
||||
"test.mixins.json"
|
||||
],
|
||||
"classTweakers": [
|
||||
{
|
||||
"config": "client.ct",
|
||||
"environment": "client"
|
||||
},
|
||||
{
|
||||
"config": "server.ct",
|
||||
"environment": "server"
|
||||
},
|
||||
"universal.ct"
|
||||
],
|
||||
"custom": {
|
||||
"loom:injected_interfaces": {
|
||||
"net/minecraft/class_123": ["net/test/TestClass"]
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
static JsonObject JSON_OBJECT = new Gson().fromJson(JSON, JsonObject.class)
|
||||
|
||||
def "version"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.version == 2
|
||||
}
|
||||
|
||||
def "id"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.id == "example-mod-id"
|
||||
}
|
||||
|
||||
def "mixins"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.mixinConfigurations == ["test.client.mixins.json", "test.server.mixins.json", "test.mixins.json"]
|
||||
}
|
||||
|
||||
def "injected interfaces"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
def jsonObject = fmj.getCustom(Constants.CustomModJsonKeys.INJECTED_INTERFACE)
|
||||
then:
|
||||
jsonObject instanceof JsonObject
|
||||
jsonObject.has("net/minecraft/class_123")
|
||||
}
|
||||
|
||||
def "universal class tweakers"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.getClassTweakers(ModEnvironment.UNIVERSAL) == ["client.ct", "server.ct", "universal.ct"]
|
||||
}
|
||||
|
||||
def "client class tweakers"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.getClassTweakers(ModEnvironment.CLIENT) == ["client.ct", "universal.ct"]
|
||||
}
|
||||
|
||||
def "server class tweakers"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.getClassTweakers(ModEnvironment.SERVER) == ["server.ct", "universal.ct"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user