Rewrite Minecraft Library handling. (#857)

This PR rewrites the Minecraft library processing with a more structured and testable set of "library processors". The old code is a mess of special cases and work arounds for various issues on various platforms.

Previously this was only really used on lesser used platforms/versions so wasnt a major issue if things broke, however current shipping Minecraft versions (1.19.4) use an LWJGL version that does not work well on Java versions new than 19. With this change LWJGL is upgraded when using Java 19 or later.

Upgraded libraries are also now only placed on the runtime classpath, this prevents you from using newer library features in your mod.
This commit is contained in:
modmuss50
2023-04-17 00:07:52 +01:00
committed by GitHub
parent 95a260d923
commit c16303b9b2
50 changed files with 2523 additions and 480 deletions

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2022 FabricMC
* Copyright (c) 2016-2023 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
@@ -74,9 +74,11 @@ public class LoomGradlePlugin implements BootstrappedPlugin {
project.getExtensions().create(LoomGradleExtensionAPI.class, "loom", LoomGradleExtensionImpl.class, project, LoomFiles.create(project));
project.getExtensions().create("fabricApi", FabricApiExtension.class, project);
CompileConfiguration.setupConfigurations(project);
final CompileConfiguration compileConfiguration = new CompileConfiguration(project);
compileConfiguration.setupConfigurations();
IdeConfiguration.setup(project);
CompileConfiguration.configureCompile(project);
compileConfiguration.configureCompile();
MavenPublication.configure(project);
LoomTasks.registerTasks(project);
DecompilerConfiguration.setup(project);

View File

@@ -109,9 +109,9 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
});
}
public static void setupForLegacyVersions(Project project) {
public static void setupForLegacyVersions(RepositoryHandler repositories) {
// 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version.
project.getRepositories().named("Mojang", MavenArtifactRepository.class, repo -> {
repositories.named("Mojang", MavenArtifactRepository.class, repo -> {
repo.metadataSources(sources -> {
// Only use the maven artifact and not the pom or gradle metadata.
sources.artifact();
@@ -120,9 +120,14 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
});
}
public static void forceLWJGLFromMavenCentral(Project project) {
public static void forceLWJGLFromMavenCentral(RepositoryHandler repositories) {
if (repositories.findByName("MavenCentralLWJGL") != null) {
// Already applied.
return;
}
// Force LWJGL from central, as it contains all the platform natives.
MavenArtifactRepository central = project.getRepositories().maven(repo -> {
MavenArtifactRepository central = repositories.maven(repo -> {
repo.setName("MavenCentralLWJGL");
repo.setUrl(ArtifactRepositoryContainer.MAVEN_CENTRAL_URL);
repo.content(content -> {
@@ -130,7 +135,7 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
});
});
project.getRepositories().exclusiveContent(repository -> {
repositories.exclusiveContent(repository -> {
repository.forRepositories(central);
repository.filter(filter -> {
filter.includeGroup("org.lwjgl");

View File

@@ -24,12 +24,13 @@
package net.fabricmc.loom.configuration;
import static net.fabricmc.loom.util.Constants.Configurations;
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.List;
import java.util.function.Consumer;
import org.gradle.api.NamedDomainObjectProvider;
@@ -68,60 +69,83 @@ import net.fabricmc.loom.util.service.ScopedSharedServiceManager;
import net.fabricmc.loom.util.service.SharedServiceManager;
public final class CompileConfiguration {
private CompileConfiguration() {
private final Project project;
private final ConfigurationContainer configurations;
public CompileConfiguration(Project project) {
this.project = project;
this.configurations = project.getConfigurations();
}
public static void setupConfigurations(Project project) {
final ConfigurationContainer configurations = project.getConfigurations();
public void setupConfigurations() {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
configurations.register(Constants.Configurations.MOD_COMPILE_CLASSPATH, configuration -> configuration.setTransitive(true));
configurations.register(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED, configuration -> configuration.setTransitive(false));
NamedDomainObjectProvider<Configuration> serverDeps = configurations.register(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, configuration -> configuration.setTransitive(false));
configurations.register(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, configuration -> configuration.setTransitive(false));
configurations.register(Constants.Configurations.MINECRAFT_DEPENDENCIES, configuration -> {
configuration.extendsFrom(serverDeps.get());
configuration.setTransitive(false);
configurations.register(Configurations.MOD_COMPILE_CLASSPATH);
createNonTransitive(Configurations.MOD_COMPILE_CLASSPATH_MAPPED);
// Set up the Minecraft compile configurations.
var minecraftClientCompile = createNonTransitive(Configurations.MINECRAFT_CLIENT_COMPILE_LIBRARIES);
var minecraftServerCompile = createNonTransitive(Configurations.MINECRAFT_SERVER_COMPILE_LIBRARIES);
var minecraftCompile = createNonTransitive(Configurations.MINECRAFT_COMPILE_LIBRARIES);
minecraftCompile.configure(configuration -> {
configuration.extendsFrom(minecraftClientCompile.get());
configuration.extendsFrom(minecraftServerCompile.get());
});
configurations.register(Constants.Configurations.LOADER_DEPENDENCIES, configuration -> configuration.setTransitive(false));
configurations.register(Constants.Configurations.MINECRAFT, configuration -> configuration.setTransitive(false));
configurations.register(Constants.Configurations.INCLUDE, configuration -> configuration.setTransitive(false)); // Dont get transitive deps
configurations.register(Constants.Configurations.MAPPING_CONSTANTS);
configurations.register(Constants.Configurations.NAMED_ELEMENTS, configuration -> {
// Set up the minecraft runtime configurations, this extends from the compile configurations.
var minecraftClientRuntime = createNonTransitive(Configurations.MINECRAFT_CLIENT_RUNTIME_LIBRARIES);
var minecraftServerRuntime = createNonTransitive(Configurations.MINECRAFT_SERVER_RUNTIME_LIBRARIES);
// Runtime extends from compile
minecraftClientRuntime.configure(configuration -> configuration.extendsFrom(minecraftClientCompile.get()));
minecraftServerRuntime.configure(configuration -> configuration.extendsFrom(minecraftServerCompile.get()));
createNonTransitive(Configurations.MINECRAFT_RUNTIME_LIBRARIES).configure(minecraftRuntime -> {
minecraftRuntime.extendsFrom(minecraftClientRuntime.get());
minecraftRuntime.extendsFrom(minecraftServerRuntime.get());
});
createNonTransitive(Configurations.MINECRAFT_NATIVES);
createNonTransitive(Configurations.LOADER_DEPENDENCIES);
createNonTransitive(Configurations.MINECRAFT);
createNonTransitive(Configurations.INCLUDE);
createNonTransitive(Configurations.MAPPING_CONSTANTS);
configurations.register(Configurations.NAMED_ELEMENTS, configuration -> {
configuration.setCanBeConsumed(true);
configuration.setCanBeResolved(false);
configuration.extendsFrom(configurations.getByName(JavaPlugin.API_CONFIGURATION_NAME));
});
extendsFrom(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, Constants.Configurations.MAPPING_CONSTANTS, project);
extendsFrom(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, Configurations.MAPPING_CONSTANTS);
configurations.register(Constants.Configurations.MAPPINGS);
configurations.register(Constants.Configurations.MAPPINGS_FINAL);
configurations.register(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES);
configurations.register(Constants.Configurations.UNPICK_CLASSPATH);
configurations.register(Constants.Configurations.LOCAL_RUNTIME);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOCAL_RUNTIME, project);
configurations.register(Configurations.MAPPINGS);
configurations.register(Configurations.MAPPINGS_FINAL);
configurations.register(Configurations.LOOM_DEVELOPMENT_DEPENDENCIES);
configurations.register(Configurations.UNPICK_CLASSPATH);
configurations.register(Configurations.LOCAL_RUNTIME);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Configurations.LOCAL_RUNTIME);
extension.createRemapConfigurations(SourceSetHelper.getMainSourceSet(project));
extendsFrom(Constants.Configurations.LOADER_DEPENDENCIES, Constants.Configurations.MINECRAFT_DEPENDENCIES, project);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Configurations.MAPPINGS_FINAL);
extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Configurations.MAPPINGS_FINAL);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL, project);
extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL, project);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project);
extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, project);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, project);
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Configurations.MINECRAFT_RUNTIME_LIBRARIES);
// Add the dev time dependencies
project.getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR);
project.getDependencies().add(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER);
project.getDependencies().add(Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR);
project.getDependencies().add(Configurations.LOOM_DEVELOPMENT_DEPENDENCIES, Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER);
project.getDependencies().add(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME, Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS);
project.getDependencies().add(JavaPlugin.TEST_COMPILE_ONLY_CONFIGURATION_NAME, Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS);
}
public static void configureCompile(Project project) {
private NamedDomainObjectProvider<Configuration> createNonTransitive(String name) {
return configurations.register(name, configuration -> configuration.setTransitive(false));
}
public void configureCompile() {
LoomGradleExtension extension = LoomGradleExtension.get(project);
project.getTasks().named(JavaPlugin.JAVADOC_TASK_NAME, Javadoc.class).configure(javadoc -> {
@@ -136,7 +160,7 @@ public final class CompileConfiguration {
final boolean previousRefreshDeps = extension.refreshDeps();
if (getAndLock(project)) {
if (getAndLock()) {
project.getLogger().lifecycle("Found existing cache lock file, rebuilding loom cache. This may have been caused by a failed or canceled build.");
extension.setRefreshDeps(true);
}
@@ -151,24 +175,24 @@ public final class CompileConfiguration {
extension.setDependencyManager(dependencyManager);
dependencyManager.handleDependencies(project, serviceManager);
releaseLock(project);
releaseLock();
extension.setRefreshDeps(previousRefreshDeps);
MixinExtension mixin = LoomGradleExtension.get(project).getMixin();
if (mixin.getUseLegacyMixinAp().get()) {
setupMixinAp(project, mixin);
setupMixinAp(mixin);
}
configureDecompileTasks(configContext);
});
finalizedBy(project, "idea", "genIdeaWorkspace");
finalizedBy(project, "eclipse", "genEclipseRuns");
finalizedBy(project, "cleanEclipse", "cleanEclipseRuns");
finalizedBy("idea", "genIdeaWorkspace");
finalizedBy("eclipse", "genEclipseRuns");
finalizedBy("cleanEclipse", "cleanEclipseRuns");
// Add the "dev" jar to the "namedElements" configuration
project.artifacts(artifactHandler -> artifactHandler.add(Constants.Configurations.NAMED_ELEMENTS, project.getTasks().named("jar")));
project.artifacts(artifactHandler -> artifactHandler.add(Configurations.NAMED_ELEMENTS, project.getTasks().named("jar")));
// Ensure that the encoding is set to UTF-8, no matter what the system default is
// this fixes some edge cases with special characters not displaying correctly
@@ -183,7 +207,7 @@ 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(ConfigContext configContext) throws Exception {
private synchronized void setupMinecraft(ConfigContext configContext) throws Exception {
final Project project = configContext.project();
final LoomGradleExtension extension = configContext.extension();
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
@@ -193,7 +217,7 @@ public final class CompileConfiguration {
extension.setMinecraftProvider(minecraftProvider);
minecraftProvider.provide();
final DependencyInfo mappingsDep = DependencyInfo.create(project, Constants.Configurations.MAPPINGS);
final DependencyInfo mappingsDep = DependencyInfo.create(project, Configurations.MAPPINGS);
final MappingConfiguration mappingConfiguration = MappingConfiguration.create(project, configContext.serviceManager(), mappingsDep, minecraftProvider);
extension.setMappingConfiguration(mappingConfiguration);
mappingConfiguration.applyToProject(project, mappingsDep);
@@ -217,7 +241,7 @@ public final class CompileConfiguration {
namedMinecraftProvider.provide(true);
}
private static void registerGameProcessors(ConfigContext configContext) {
private void registerGameProcessors(ConfigContext configContext) {
final LoomGradleExtension extension = configContext.extension();
final boolean enableTransitiveAccessWideners = extension.getEnableTransitiveAccessWideners().get();
@@ -234,7 +258,7 @@ public final class CompileConfiguration {
}
}
private static void setupMixinAp(Project project, MixinExtension mixin) {
private void setupMixinAp(MixinExtension mixin) {
mixin.init();
// Disable some things used by log4j via the mixin AP that prevent it from being garbage collected
@@ -262,22 +286,22 @@ public final class CompileConfiguration {
}
}
private static void configureDecompileTasks(ConfigContext configContext) {
private void configureDecompileTasks(ConfigContext configContext) {
final LoomGradleExtension extension = configContext.extension();
extension.getMinecraftJarConfiguration().get().getDecompileConfigurationBiFunction()
.apply(configContext, extension.getNamedMinecraftProvider()).afterEvaluation();
}
private static Path getLockFile(Project project) {
private Path getLockFile() {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final Path cacheDirectory = extension.getFiles().getUserCache().toPath();
final String pathHash = Checksum.projectHash(project);
return cacheDirectory.resolve("." + pathHash + ".lock");
}
private static boolean getAndLock(Project project) {
final Path lock = getLockFile(project);
private boolean getAndLock() {
final Path lock = getLockFile();
if (Files.exists(lock)) {
return true;
@@ -292,8 +316,8 @@ public final class CompileConfiguration {
return false;
}
private static void releaseLock(Project project) {
final Path lock = getLockFile(project);
private void releaseLock() {
final Path lock = getLockFile();
if (!Files.exists(lock)) {
return;
@@ -315,17 +339,11 @@ public final class CompileConfiguration {
}
}
public static void extendsFrom(List<String> parents, String b, Project project) {
for (String parent : parents) {
extendsFrom(parent, b, project);
}
}
public static void extendsFrom(String a, String b, Project project) {
public void extendsFrom(String a, String b) {
project.getConfigurations().getByName(a, configuration -> configuration.extendsFrom(project.getConfigurations().getByName(b)));
}
private static void finalizedBy(Project project, String a, String b) {
private void finalizedBy(String a, String b) {
project.getTasks().named(a).configure(task -> task.finalizedBy(project.getTasks().named(b)));
}

View File

@@ -29,6 +29,7 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -286,11 +287,11 @@ public class RunConfig {
return Collections.emptyList();
}
final Set<ResolvedArtifact> allLibraries = getArtifacts(project, Constants.Configurations.MINECRAFT_DEPENDENCIES);
final Set<ResolvedArtifact> serverLibraries = getArtifacts(project, Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES);
final Set<ResolvedArtifact> clientLibraries = getArtifacts(project, Constants.Configurations.MINECRAFT_CLIENT_RUNTIME_LIBRARIES);
final Set<ResolvedArtifact> serverLibraries = getArtifacts(project, Constants.Configurations.MINECRAFT_SERVER_RUNTIME_LIBRARIES);
final List<String> clientOnlyLibraries = new LinkedList<>();
for (ResolvedArtifact library : allLibraries) {
for (ResolvedArtifact library : clientLibraries) {
if (!containsLibrary(serverLibraries, library.getModuleVersion().getId())) {
clientOnlyLibraries.add(library.getFile().getAbsolutePath());
}
@@ -300,9 +301,11 @@ public class RunConfig {
}
private static Set<ResolvedArtifact> getArtifacts(Project project, String configuration) {
return project.getConfigurations().getByName(configuration)
.getResolvedConfiguration()
.getResolvedArtifacts();
return project.getConfigurations().getByName(configuration).getHierarchy()
.stream()
.map(c -> c.getResolvedConfiguration().getResolvedArtifacts())
.flatMap(Collection::stream)
.collect(Collectors.toSet());
}
private static boolean containsLibrary(Set<ResolvedArtifact> artifacts, ModuleVersionIdentifier identifier) {

View File

@@ -40,7 +40,7 @@ import org.gradle.api.tasks.SourceSet;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
import net.fabricmc.loom.util.Platform;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
public final class RunConfigSettings implements Named {
@@ -256,7 +256,7 @@ public final class RunConfigSettings implements Named {
* Add the {@code -XstartOnFirstThread} JVM argument when on OSX.
*/
public void startFirstThread() {
if (OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS)) {
if (Platform.CURRENT.getOperatingSystem().isMacOS()) {
vmArg("-XstartOnFirstThread");
}
}

View File

@@ -101,12 +101,10 @@ public abstract class IdeaSyncTask extends AbstractLoomTask {
final List<String> excludedLibraryPaths = config.getExcludedLibraryPaths(getProject());
if (!excludedLibraryPaths.isEmpty()) {
try {
setClasspathModifications(runConfigs.toPath(), excludedLibraryPaths);
} catch (Exception e) {
getProject().getLogger().error("Failed to modify run configuration xml", e);
}
try {
setClasspathModifications(runConfigs.toPath(), excludedLibraryPaths);
} catch (Exception e) {
getProject().getLogger().error("Failed to modify run configuration xml", e);
}
}
}

View File

@@ -63,7 +63,6 @@ import net.fabricmc.loom.configuration.mods.dependency.ModDependencyFactory;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
import net.fabricmc.loom.util.Checksum;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.loom.util.gradle.SourceSetHelper;
import net.fabricmc.loom.util.service.SharedServiceManager;
@@ -275,7 +274,7 @@ public class ModConfigurationRemapper {
}
private static void scheduleSourcesRemapping(Project project, SourceRemapper sourceRemapper, ModDependency dependency) {
if (OperatingSystem.isCIBuild()) {
if (isCIBuild()) {
return;
}
@@ -301,4 +300,15 @@ public class ModConfigurationRemapper {
public static String replaceIfNullOrEmpty(@Nullable String s, Supplier<String> fallback) {
return s == null || s.isEmpty() ? fallback.get() : s;
}
private static boolean isCIBuild() {
final String loomProperty = System.getProperty("fabric.loom.ci");
if (loomProperty != null) {
return loomProperty.equalsIgnoreCase("true");
}
// CI seems to be set by most popular CI services
return System.getenv("CI") != null;
}
}

View File

@@ -129,7 +129,7 @@ public class ModProcessor {
private void remapJars(List<ModDependency> remapList) throws IOException {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final MappingConfiguration mappingConfiguration = extension.getMappingConfiguration();
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES).getFiles()
.stream().map(File::toPath).toArray(Path[]::new);
TinyRemapper.Builder builder = TinyRemapper.newRemapper()

View File

@@ -42,7 +42,7 @@ public final class ContextImplHelper {
return new LazyCloseable<>(() -> {
try {
TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(configContext.project(), configContext.serviceManager(), from.toString(), to.toString());
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(configContext.project()));
tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftCompileLibraries(configContext.project()));
for (Path minecraftJar : configContext.extension().getMinecraftJars(MappingsNamespace.INTERMEDIARY)) {
tinyRemapper.readClassPath(minecraftJar);

View File

@@ -1,143 +0,0 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* 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
* 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 static net.fabricmc.loom.util.OperatingSystem.LINUX;
import static net.fabricmc.loom.util.OperatingSystem.MAC_OS;
import static net.fabricmc.loom.util.OperatingSystem.WINDOWS;
import java.util.List;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.util.Architecture;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
public class LWJGLVersionOverride {
public static final String LWJGL_VERSION = "3.3.1";
@Nullable
public static final String NATIVE_CLASSIFIER = getNativesClassifier();
public static final List<String> DEPENDENCIES = List.of(
"org.lwjgl:lwjgl:" + LWJGL_VERSION,
"org.lwjgl:lwjgl-glfw:" + LWJGL_VERSION,
"org.lwjgl:lwjgl-jemalloc:" + LWJGL_VERSION,
"org.lwjgl:lwjgl-openal:" + LWJGL_VERSION,
"org.lwjgl:lwjgl-opengl:" + LWJGL_VERSION,
"org.lwjgl:lwjgl-stb:" + LWJGL_VERSION,
"org.lwjgl:lwjgl-tinyfd:" + LWJGL_VERSION
);
public static final List<String> NATIVES = DEPENDENCIES.stream().map(s -> s + ":" + NATIVE_CLASSIFIER).toList();
public static final List<String> MACOS_DEPENDENCIES = List.of(
"ca.weblite:java-objc-bridge:1.1"
);
// Same for now, as java-objc-bridge includes the natives in the main jar.
public static final List<String> MACOS_NATIVES = MACOS_DEPENDENCIES;
/**
* Update lwjgl by default when running on arm and a supported configuration.
*/
public static boolean overrideByDefault(MinecraftVersionMeta versionMeta) {
if (NATIVE_CLASSIFIER == null || !Architecture.CURRENT.isArm()) {
return false;
}
boolean supportedLwjglVersion = versionMeta.libraries().stream()
.anyMatch(library -> library.name().startsWith("org.lwjgl:lwjgl:3"));
boolean hasExistingNatives = versionMeta.libraries().stream()
.filter(library -> library.name().startsWith("org.lwjgl:lwjgl"))
.anyMatch(MinecraftVersionMeta.Library::hasNativesForOS);
// Is LWJGL 3, and doesn't have any existing compatible LWGL natives.
return supportedLwjglVersion && !hasExistingNatives;
}
public static boolean forceOverride(Project project) {
return project.getProperties().get("fabric.loom.override-lwjgl") != null;
}
public static void applyOverrides(Project project, boolean isMacOS) {
DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s));
NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s));
if (isMacOS) {
MACOS_DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s));
MACOS_NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s));
}
// Add the native support mod that fixes a handful of issues related to the LWJGL update at runtime.
ExternalModuleDependency dependency = (ExternalModuleDependency) project.getDependencies().create(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION);
dependency.setTransitive(false);
project.getDependencies().add("modLocalRuntime", dependency);
}
@Nullable
private static String getNativesClassifier() {
return switch (OperatingSystem.CURRENT_OS) {
case WINDOWS -> getWindowsClassifier();
case MAC_OS -> getMacOSClassifier();
case LINUX -> getLinuxClassifier();
default -> null;
};
}
private static String getWindowsClassifier() {
if (Architecture.CURRENT.is64Bit()) {
if (Architecture.CURRENT.isArm()) {
// Arm 64 bit
return "natives-windows-arm64";
}
// None arm 64bit
return "natives-windows";
}
// All 32bit, including arm
return "natives-windows-x86";
}
private static String getMacOSClassifier() {
if (Architecture.CURRENT.isArm()) {
// Apple silicone arm
return "natives-macos-arm64";
}
// Intel 64bit.
return "natives-macos";
}
private static String getLinuxClassifier() {
if (Architecture.CURRENT.isArm()) {
return Architecture.CURRENT.is64Bit() ? "natives-linux-arm64" : "natives-linux-arm32";
}
return "natives-linux";
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2018-2022 FabricMC
* Copyright (c) 2018-2023 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,74 +24,70 @@
package net.fabricmc.loom.configuration.providers.minecraft;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.gradle.api.JavaVersion;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.ModuleDependency;
import org.gradle.api.provider.Provider;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomRepositoryPlugin;
import net.fabricmc.loom.configuration.providers.BundleMetadata;
import net.fabricmc.loom.util.Architecture;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager;
import net.fabricmc.loom.configuration.providers.minecraft.library.MinecraftLibraryHelper;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.RuntimeLog4jLibraryProcessor;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.OperatingSystem;
import net.fabricmc.loom.util.Platform;
public class MinecraftLibraryProvider {
private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-(\\k<version>)-)(?<classifier>.*).jar$");
private static final boolean IS_MACOS = OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS);
private static final Platform platform = Platform.CURRENT;
private final Project project;
private final MinecraftVersionMeta versionInfo;
private final BundleMetadata serverBundleMetadata;
private final boolean runtimeOnlyLog4j;
private final boolean provideClient;
private final boolean provideServer;
private final MinecraftProvider minecraftProvider;
private final LibraryProcessorManager processorManager;
public MinecraftLibraryProvider(MinecraftProvider minecraftProvider, Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
this.project = project;
this.versionInfo = minecraftProvider.getVersionInfo();
this.serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
this.runtimeOnlyLog4j = extension.getRuntimeOnlyLog4j().get();
this.provideClient = jarConfiguration.getSupportedEnvironments().contains("client");
this.provideServer = jarConfiguration.getSupportedEnvironments().contains("server");
assert provideClient || provideServer;
this.minecraftProvider = minecraftProvider;
this.processorManager = new LibraryProcessorManager(platform, project.getRepositories(), getEnabledProcessors());
}
private void addDependency(String configuration, Object dependency) {
Dependency created = project.getDependencies().add(configuration, dependency);
private List<String> getEnabledProcessors() {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
// The launcher doesn't download transitive deps, so neither will we.
// This will also prevent a LaunchWrapper library dependency from pulling in outdated ASM jars.
if (created instanceof ModuleDependency md) {
md.setTransitive(false);
var enabledProcessors = new ArrayList<String>();
if (extension.getRuntimeOnlyLog4j().get()) {
enabledProcessors.add(RuntimeLog4jLibraryProcessor.class.getSimpleName());
}
final Provider<String> libraryProcessorsProperty = project.getProviders().gradleProperty(Constants.Properties.LIBRARY_PROCESSORS);
if (libraryProcessorsProperty.isPresent()) {
String[] split = libraryProcessorsProperty.get().split(":");
enabledProcessors.addAll(Arrays.asList(split));
}
return Collections.unmodifiableList(enabledProcessors);
}
public void provide() {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get();
final boolean provideClient = jarConfiguration.getSupportedEnvironments().contains("client");
final boolean provideServer = jarConfiguration.getSupportedEnvironments().contains("server");
assert provideClient || provideServer;
if (provideClient) {
// Modern 1.19 version put the natives on the classpath.
final boolean hasNativesToExtract = versionInfo.hasNativesToExtract();
final boolean overrideLWJGL = hasNativesToExtract && (LWJGLVersionOverride.overrideByDefault(versionInfo) || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride"));
if (overrideLWJGL) {
project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION);
}
if (hasNativesToExtract) {
// Create a configuration for
project.getConfigurations().register(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false));
}
provideClientLibraries(overrideLWJGL, hasNativesToExtract);
if (overrideLWJGL) {
LWJGLVersionOverride.applyOverrides(project, IS_MACOS);
}
provideClientLibraries();
}
if (provideServer) {
@@ -99,96 +95,76 @@ public class MinecraftLibraryProvider {
}
}
private void provideClientLibraries(boolean overrideLWJGL, boolean hasNativesToExtract) {
final boolean isArm = Architecture.CURRENT.isArm();
final boolean classpathArmNatives = !hasNativesToExtract && isArm && !IS_MACOS;
private void provideClientLibraries() {
final List<Library> libraries = MinecraftLibraryHelper.getLibrariesForPlatform(minecraftProvider.getVersionInfo(), platform);
final List<Library> processLibraries = processLibraries(libraries);
processLibraries.forEach(this::applyClientLibrary);
if (classpathArmNatives) {
LoomRepositoryPlugin.forceLWJGLFromMavenCentral(project);
}
for (MinecraftVersionMeta.Library library : versionInfo.libraries()) {
if (overrideLWJGL && library.name().startsWith("org.lwjgl")) {
// Skip over Minecraft's LWJGL version, will will replace this with a newer version later.
continue;
}
if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) {
final String name = library.name();
if ("org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3".equals(name) || "org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20131017".equals(name)) {
// 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version.
LoomRepositoryPlugin.setupForLegacyVersions(project);
}
if (name.startsWith("org.ow2.asm:asm-all")) {
// Don't want asm-all, use the modern split version.
continue;
}
if (runtimeOnlyLog4j && name.startsWith("org.apache.logging.log4j")) {
// Make log4j a runtime only dep to force slf4j.
addDependency(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, name);
continue;
}
if (classpathArmNatives && name.startsWith("org.lwjgl:")
&& (name.endsWith("natives-windows") || name.endsWith("natives-linux"))) {
// Add windows and Linux arm64 natives for modern classpath native MC versions.
addDependency(Constants.Configurations.MINECRAFT_DEPENDENCIES, name + "-arm64");
}
addDependency(Constants.Configurations.MINECRAFT_DEPENDENCIES, name);
}
if (library.hasNativesForOS()) {
provideNativesForLibrary(library, overrideLWJGL, IS_MACOS);
}
// After Minecraft 1.19-pre1 the natives should be on the runtime classpath.
if (!minecraftProvider.getVersionInfo().hasNativesToExtract()) {
project.getConfigurations().named(Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES, configuration -> configuration.extendsFrom(project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_NATIVES)));
}
}
private void provideServerLibraries() {
if (serverBundleMetadata != null) {
for (BundleMetadata.Entry library : serverBundleMetadata.libraries()) {
if (runtimeOnlyLog4j && library.name().startsWith("org.apache.logging.log4j")) {
// Make log4j a runtime only dep to force slf4j.
addDependency(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, library.name());
continue;
}
final BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata();
addDependency(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, library.name());
}
if (serverBundleMetadata == null) {
return;
}
final List<Library> libraries = MinecraftLibraryHelper.getServerLibraries(serverBundleMetadata);
final List<Library> processLibraries = processLibraries(libraries);
processLibraries.forEach(this::applyServerLibrary);
}
private List<Library> processLibraries(List<Library> libraries) {
final LibraryContext libraryContext = new LibraryContext(minecraftProvider.getVersionInfo(), JavaVersion.current());
return processorManager.processLibraries(libraries, libraryContext);
}
private void applyClientLibrary(Library library) {
switch (library.target()) {
case COMPILE -> {
addLibrary(Constants.Configurations.MINECRAFT_CLIENT_COMPILE_LIBRARIES, library);
}
case RUNTIME -> {
addLibrary(Constants.Configurations.MINECRAFT_CLIENT_RUNTIME_LIBRARIES, library);
}
case NATIVES -> {
addLibrary(Constants.Configurations.MINECRAFT_NATIVES, library);
}
case LOCAL_MOD -> {
ExternalModuleDependency dependency = (ExternalModuleDependency) project.getDependencies().create(library.mavenNotation());
dependency.setTransitive(false);
project.getDependencies().add("modLocalRuntime", dependency);
}
}
}
private void provideNativesForLibrary(MinecraftVersionMeta.Library library, boolean overrideLWJGL, boolean isMacOS) {
MinecraftVersionMeta.Download nativeDownload = library.classifierForOS();
if (nativeDownload == null) {
return;
private void applyServerLibrary(Library library) {
switch (library.target()) {
case COMPILE -> {
addLibrary(Constants.Configurations.MINECRAFT_SERVER_COMPILE_LIBRARIES, library);
}
final String path = nativeDownload.path();
final Matcher matcher = NATIVES_PATTERN.matcher(path);
if (!matcher.find()) {
project.getLogger().warn("Failed to match regex for natives path : " + path);
return;
case RUNTIME -> {
addLibrary(Constants.Configurations.MINECRAFT_SERVER_RUNTIME_LIBRARIES, library);
}
final String group = matcher.group("group").replace("/", ".");
final String name = matcher.group("name");
final String version = matcher.group("version");
final String classifier = matcher.group("classifier");
final String dependencyNotation = "%s:%s:%s:%s".formatted(group, name, version, classifier);
if (overrideLWJGL && isMacOS && "java-objc-bridge".equals(name)) {
// Mojang split out the natives into their own jar, skip over Mojang's jar and use the official jar later on.
return;
default -> throw new IllegalStateException("Target not supported for server library");
}
}
project.getLogger().debug("Add native dependency '{}'", dependencyNotation);
addDependency(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation);
private void addLibrary(String configuration, Library library) {
addDependency(configuration, library.mavenNotation());
}
private void addDependency(String configuration, Object dependency) {
final Dependency created = project.getDependencies().add(configuration, dependency);
// The launcher doesn't download transitive deps, so neither will we.
// This will also prevent a LaunchWrapper library dependency from pulling in outdated ASM jars.
if (created instanceof ModuleDependency md) {
md.setTransitive(false);
}
}
}

View File

@@ -24,13 +24,12 @@
package net.fabricmc.loom.configuration.providers.minecraft;
import static net.fabricmc.loom.configuration.CompileConfiguration.extendsFrom;
import java.util.List;
import java.util.function.BiConsumer;
import com.google.common.base.Preconditions;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.SourceSet;
import org.gradle.jvm.tasks.Jar;
@@ -48,11 +47,9 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
public abstract void applyDependencies(BiConsumer<String, String> consumer, List<String> targets);
public abstract String getCombinedSourceSetName();
public abstract String getSourceSetForEnv(String env);
protected abstract List<String> getAllSourceSetNames();
protected abstract List<ConfigurationName> getConfigurations();
public void evaluateSplit(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
@@ -63,58 +60,72 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
public abstract void afterEvaluate(Project project);
protected void createSourceSets(Project project) {
for (String name : getAllSourceSetNames()) {
project.getConfigurations().register(name, configuration -> configuration.setTransitive(false));
protected void createConfigurations(Project project) {
final ConfigurationContainer configurations = project.getConfigurations();
// All the configurations extend the loader deps.
extendsFrom(name, Constants.Configurations.LOADER_DEPENDENCIES, project);
for (ConfigurationName configurationName : getConfigurations()) {
configurations.register(configurationName.runtime(), configuration -> {
configuration.setTransitive(false);
configuration.extendsFrom(configurations.getByName(configurationName.mcLibsRuntimeName()));
configuration.extendsFrom(configurations.getByName(Constants.Configurations.LOADER_DEPENDENCIES));
configuration.extendsFrom(configurations.getByName(Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES));
});
configurations.register(configurationName.compile(), configuration -> {
configuration.setTransitive(false);
configuration.extendsFrom(configurations.getByName(configurationName.mcLibsCompileName()));
configuration.extendsFrom(configurations.getByName(Constants.Configurations.LOADER_DEPENDENCIES));
});
}
}
protected void extendsFrom(Project project, String name, String extendsFrom) {
final ConfigurationContainer configurations = project.getConfigurations();
configurations.named(name, configuration -> {
configuration.extendsFrom(configurations.getByName(extendsFrom));
});
}
/**
* Used when we have a single source set, either with split or merged jars.
*/
public static final class Single extends MinecraftSourceSets {
private static final String MINECRAFT_NAMED = "minecraftNamed";
private static final ConfigurationName MINECRAFT_NAMED = new ConfigurationName(
"minecraftNamed",
Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES,
Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES
);
private static final Single INSTANCE = new Single();
@Override
public void applyDependencies(BiConsumer<String, String> consumer, List<String> targets) {
for (String target : targets) {
consumer.accept(MINECRAFT_NAMED, target);
consumer.accept(MINECRAFT_NAMED.compile(), target);
consumer.accept(MINECRAFT_NAMED.runtime(), target);
}
}
@Override
public String getCombinedSourceSetName() {
return MINECRAFT_NAMED;
}
@Override
public String getSourceSetForEnv(String env) {
return SourceSet.MAIN_SOURCE_SET_NAME;
}
@Override
protected List<String> getAllSourceSetNames() {
protected List<ConfigurationName> getConfigurations() {
return List.of(MINECRAFT_NAMED);
}
@Override
public void afterEvaluate(Project project) {
// This is done in afterEvaluate as we need to be sure that split source sets was not enabled.
createSourceSets(project);
createConfigurations(project);
// Default compile and runtime sourcesets.
extendsFrom(List.of(
JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME,
JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME,
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME,
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME),
MINECRAFT_NAMED, project
);
extendsFrom(project, JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME, MINECRAFT_NAMED.compile());
extendsFrom(project, JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, MINECRAFT_NAMED.runtime());
extendsFrom(project, JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME, MINECRAFT_NAMED.compile());
extendsFrom(project, JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, MINECRAFT_NAMED.runtime());
}
}
@@ -122,9 +133,17 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
* Used when we have a split client/common source set and split jars.
*/
public static final class Split extends MinecraftSourceSets {
private static final String MINECRAFT_COMMON_NAMED = "minecraftCommonNamed";
private static final String MINECRAFT_CLIENT_ONLY_NAMED = "minecraftClientOnlyNamed";
private static final String MINECRAFT_COMBINED_NAMED = "minecraftCombinedNamed";
private static final ConfigurationName MINECRAFT_COMMON_NAMED = new ConfigurationName(
"minecraftCommonNamed",
Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES,
Constants.Configurations.MINECRAFT_RUNTIME_LIBRARIES
);
// Depends on the Minecraft client libraries.
private static final ConfigurationName MINECRAFT_CLIENT_ONLY_NAMED = new ConfigurationName(
"minecraftClientOnlyNamed",
Constants.Configurations.MINECRAFT_CLIENT_COMPILE_LIBRARIES,
Constants.Configurations.MINECRAFT_CLIENT_RUNTIME_LIBRARIES
);
public static final String CLIENT_ONLY_SOURCE_SET_NAME = "client";
@@ -136,13 +155,10 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
Preconditions.checkArgument(targets.contains("common"));
Preconditions.checkArgument(targets.contains("clientOnly"));
consumer.accept(MINECRAFT_COMMON_NAMED, "common");
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED, "clientOnly");
}
@Override
public String getCombinedSourceSetName() {
return MINECRAFT_COMBINED_NAMED;
consumer.accept(MINECRAFT_COMMON_NAMED.runtime(), "common");
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.runtime(), "clientOnly");
consumer.accept(MINECRAFT_COMMON_NAMED.compile(), "common");
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED.compile(), "clientOnly");
}
@Override
@@ -151,37 +167,29 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
}
@Override
protected List<String> getAllSourceSetNames() {
return List.of(MINECRAFT_COMMON_NAMED, MINECRAFT_CLIENT_ONLY_NAMED, MINECRAFT_COMBINED_NAMED);
protected List<ConfigurationName> getConfigurations() {
return List.of(MINECRAFT_COMMON_NAMED, MINECRAFT_CLIENT_ONLY_NAMED);
}
// Called during evaluation, when the loom extension method is called.
private void evaluate(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
createSourceSets(project);
// Combined extends from the 2 environments.
extendsFrom(MINECRAFT_COMBINED_NAMED, MINECRAFT_COMMON_NAMED, project);
extendsFrom(MINECRAFT_COMBINED_NAMED, MINECRAFT_CLIENT_ONLY_NAMED, project);
createConfigurations(project);
final ConfigurationContainer configurations = project.getConfigurations();
// Register our new client only source set, main becomes common only, with their respective jars.
SourceSet mainSourceSet = SourceSetHelper.getMainSourceSet(project);
SourceSet clientOnlySourceSet = SourceSetHelper.createSourceSet(CLIENT_ONLY_SOURCE_SET_NAME, project);
final SourceSet mainSourceSet = SourceSetHelper.getMainSourceSet(project);
final SourceSet clientOnlySourceSet = SourceSetHelper.createSourceSet(CLIENT_ONLY_SOURCE_SET_NAME, project);
extendsFrom(List.of(
mainSourceSet.getCompileClasspathConfigurationName(),
mainSourceSet.getRuntimeClasspathConfigurationName()
), MINECRAFT_COMMON_NAMED, project
);
// Add Minecraft to the main and client source sets.
extendsFrom(project, mainSourceSet.getCompileClasspathConfigurationName(), MINECRAFT_COMMON_NAMED.compile());
extendsFrom(project, mainSourceSet.getRuntimeClasspathConfigurationName(), MINECRAFT_COMMON_NAMED.runtime());
extendsFrom(project, clientOnlySourceSet.getCompileClasspathConfigurationName(), MINECRAFT_CLIENT_ONLY_NAMED.compile());
extendsFrom(project, clientOnlySourceSet.getRuntimeClasspathConfigurationName(), MINECRAFT_CLIENT_ONLY_NAMED.runtime());
extendsFrom(List.of(
clientOnlySourceSet.getCompileClasspathConfigurationName(),
clientOnlySourceSet.getRuntimeClasspathConfigurationName()
), MINECRAFT_CLIENT_ONLY_NAMED, project
);
// Client source set depends on common.
extendsFrom(project, MINECRAFT_CLIENT_ONLY_NAMED.runtime(), MINECRAFT_COMMON_NAMED.runtime());
extendsFrom(project, MINECRAFT_CLIENT_ONLY_NAMED.compile(), MINECRAFT_COMMON_NAMED.compile());
// Client depends on common.
extendsFrom(MINECRAFT_CLIENT_ONLY_NAMED, MINECRAFT_COMMON_NAMED, project);
clientOnlySourceSet.setCompileClasspath(
clientOnlySourceSet.getCompileClasspath()
.plus(mainSourceSet.getCompileClasspath())
@@ -231,4 +239,14 @@ public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Sin
public void afterEvaluate(Project project) {
}
}
private record ConfigurationName(String baseName, String mcLibsCompileName, String mcLibsRuntimeName) {
private String runtime() {
return baseName + "Runtime";
}
private String compile() {
return baseName + "Compile";
}
}
}

View File

@@ -29,8 +29,9 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import net.fabricmc.loom.util.Architecture;
import net.fabricmc.loom.util.OperatingSystem;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.util.Platform;
@SuppressWarnings("unused")
public record MinecraftVersionMeta(
@@ -48,6 +49,12 @@ public record MinecraftVersionMeta(
String time,
String type
) {
private static Map<Platform.OperatingSystem, String> OS_NAMES = Map.of(
Platform.OperatingSystem.WINDOWS, "windows",
Platform.OperatingSystem.MAC_OS, "osx",
Platform.OperatingSystem.LINUX, "linux"
);
public Download download(String key) {
return downloads().get(key);
}
@@ -67,7 +74,7 @@ public record MinecraftVersionMeta(
}
public record Library(Downloads downloads, String name, Map<String, String> natives, List<Rule> rules, Object extract) {
public boolean isValidForOS() {
public boolean isValidForOS(Platform platform) {
if (rules == null) {
// No rules allow everything.
return true;
@@ -76,7 +83,7 @@ public record MinecraftVersionMeta(
boolean valid = false;
for (Rule rule : this.rules) {
if (rule.appliesToOS()) {
if (rule.appliesToOS(platform)) {
valid = rule.isAllowed();
}
}
@@ -88,25 +95,38 @@ public record MinecraftVersionMeta(
return this.natives != null;
}
public boolean hasNativesForOS() {
public boolean hasNativesForOS(Platform platform) {
if (!hasNatives()) {
return false;
}
if (classifierForOS() == null) {
if (classifierForOS(platform) == null) {
return false;
}
return isValidForOS();
return isValidForOS(platform);
}
public Download classifierForOS() {
String classifier = natives.get(OperatingSystem.CURRENT_OS);
@Nullable
public Download classifierForOS(Platform platform) {
String classifier = natives.get(OS_NAMES.get(platform.getOperatingSystem()));
if (Architecture.CURRENT.isArm()) {
classifier += "-arm64";
if (classifier == null) {
return null;
}
if (platform.getArchitecture().isArm() && platform.getArchitecture().is64Bit()) {
// Default to the arm64 natives, if not found fallback.
final Download armNative = downloads().classifier(classifier + "-arm64");
if (armNative != null) {
return armNative;
}
}
// Used in the twitch library in 1.7.10
classifier = classifier.replace("${arch}", platform.getArchitecture().is64Bit() ? "64" : "32");
return downloads().classifier(classifier);
}
@@ -120,14 +140,15 @@ public record MinecraftVersionMeta(
}
public record Downloads(Download artifact, Map<String, Download> classifiers) {
@Nullable
public Download classifier(String os) {
return classifiers.get(os);
}
}
public record Rule(String action, OS os) {
public boolean appliesToOS() {
return os() == null || os().isValidForOS();
public boolean appliesToOS(Platform platform) {
return os() == null || os().isValidForOS(platform);
}
public boolean isAllowed() {
@@ -136,8 +157,8 @@ public record MinecraftVersionMeta(
}
public record OS(String name) {
public boolean isValidForOS() {
return name() == null || name().equalsIgnoreCase(OperatingSystem.CURRENT_OS);
public boolean isValidForOS(Platform platform) {
return name() == null || name().equalsIgnoreCase(OS_NAMES.get(platform.getOperatingSystem()));
}
}

View File

@@ -0,0 +1,91 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library;
import org.jetbrains.annotations.Nullable;
public record Library(String group, String name, String version, @Nullable String classifier, Target target) {
public enum Target {
/**
* A runtime only library.
*/
RUNTIME,
/**
* A runtime and compile library.
*/
COMPILE,
/**
* Natives.
*/
NATIVES,
/**
* A mod library that needs remapping.
*/
LOCAL_MOD
}
public static Library fromMaven(String name, Target target) {
String[] split = name.split(":");
assert split.length == 3 || split.length == 4;
return new Library(split[0], split[1], split[2], split.length == 4 ? split[3] : null, target);
}
/**
* Returns true when the group or the group and name match.
*
* @param str Takes a string containing the maven group, or a group and name split by :
* @return true when the group or the group and name match.
*/
public boolean is(String str) {
if (str.contains(":")) {
final String[] split = str.split(":");
assert split.length == 2;
return this.group.equals(split[0]) && this.name.equals(split[1]);
}
return this.group.equals(str);
}
public String mavenNotation() {
if (classifier != null) {
return "%s:%s:%s:%s".formatted(group, name, version, classifier);
}
return "%s:%s:%s".formatted(group, name, version);
}
public Library withVersion(String version) {
return new Library(this.group, this.name, version, this.classifier, this.target);
}
public Library withClassifier(@Nullable String classifier) {
return new Library(this.group, this.name, this.version, classifier, this.target);
}
public Library withTarget(Target target) {
return new Library(this.group, this.name, this.version, this.classifier, target);
}
}

View File

@@ -0,0 +1,115 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library;
import java.util.Arrays;
import org.gradle.api.JavaVersion;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
public final class LibraryContext {
private final MinecraftVersionMeta versionMeta;
private final JavaVersion javaVersion;
public LibraryContext(MinecraftVersionMeta versionMeta, JavaVersion javaVersion) {
this.versionMeta = versionMeta;
this.javaVersion = javaVersion;
}
/**
* @return True when the Minecraft libraries support ARM64 MacOS
*/
public boolean supportsArm64MacOS() {
return versionMeta.libraries().stream()
.anyMatch(library -> library.name().startsWith("org.lwjgl:lwjgl:3") && library.name().endsWith(":natives-macos-arm64"));
}
/**
* @return True when the Minecraft libraries support Java 19 or later
*/
public boolean supportsJava19OrLater() {
return versionMeta.libraries().stream().filter(library -> library.name().startsWith("org.lwjgl:lwjgl:")).anyMatch(library -> {
final String[] split = library.name().split(":");
if (split.length != 3) {
return false;
}
final String version = split[2];
final int[] versionSplit = Arrays.stream(version.split("\\."))
.mapToInt(Integer::parseInt)
.toArray();
// LWJGL 4 or newer
if (versionSplit[0] > 3) {
return true;
}
// LWJGL 3.4 or newer
if (versionSplit[0] == 3 && versionSplit[1] > 3) {
return true;
}
// LWJGL 3.3.2 or newer
if (versionSplit[0] == 3 && versionSplit[1] == 3 && versionSplit[2] >= 2) {
return true;
}
return false;
});
}
/**
* @return True when using LWJGL 3
*/
public boolean usesLWJGL3() {
return versionMeta.libraries().stream()
.anyMatch(library -> library.name().startsWith("org.lwjgl:lwjgl:3"));
}
/**
* @return True when the Minecraft natives are on the classpath, as opposed to being extracted
*/
public boolean hasClasspathNatives() {
return !versionMeta.hasNativesToExtract();
}
/**
* @return True when there is an exact match for this library
*/
public boolean hasLibrary(String name) {
return versionMeta.libraries().stream()
.anyMatch(library -> library.name().equals(name));
}
/**
* @return True when the current Java version is 19 or later
*/
public boolean isJava19OrLater() {
return javaVersion.isCompatibleWith(JavaVersion.VERSION_19);
}
}

View File

@@ -0,0 +1,69 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import net.fabricmc.loom.util.Platform;
public abstract class LibraryProcessor {
protected static final Predicate<Library> ALLOW_ALL = library -> true;
protected final Platform platform;
protected final LibraryContext context;
public LibraryProcessor(Platform platform, LibraryContext context) {
this.platform = Objects.requireNonNull(platform);
this.context = Objects.requireNonNull(context);
}
public abstract ApplicationResult getApplicationResult();
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
return ALLOW_ALL;
}
public void applyRepositories(RepositoryHandler repositories) {
}
public enum ApplicationResult {
/**
* This processor should be applied automatically to enable Minecraft to run on the current platform.
*/
MUST_APPLY,
/**
* This processor can optionally be applied on the current platform.
*/
CAN_APPLY,
/**
* This processor is incompatible with the current platform and should not be applied on the current platform.
*/
DONT_APPLY
}
}

View File

@@ -0,0 +1,127 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.jetbrains.annotations.VisibleForTesting;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.ArmNativesLibraryProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.LWJGL2MavenLibraryProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.LWJGL3UpgradeLibraryProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.LegacyASMLibraryProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.LoomNativeSupportLibraryProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.ObjcBridgeUpgradeLibraryProcessor;
import net.fabricmc.loom.configuration.providers.minecraft.library.processors.RuntimeLog4jLibraryProcessor;
import net.fabricmc.loom.util.Platform;
public class LibraryProcessorManager {
private static final List<LibraryProcessorFactory<?>> LIBRARY_PROCESSORS = List.of(
ArmNativesLibraryProcessor::new,
LegacyASMLibraryProcessor::new,
LoomNativeSupportLibraryProcessor::new,
LWJGL2MavenLibraryProcessor::new,
LWJGL3UpgradeLibraryProcessor::new,
ObjcBridgeUpgradeLibraryProcessor::new,
RuntimeLog4jLibraryProcessor::new
);
private final Platform platform;
private final RepositoryHandler repositories;
private final List<String> enabledProcessors;
public LibraryProcessorManager(Platform platform, RepositoryHandler repositories, List<String> enabledProcessors) {
this.platform = platform;
this.repositories = repositories;
this.enabledProcessors = enabledProcessors;
}
public LibraryProcessorManager(Platform platform, RepositoryHandler repositories) {
this(platform, repositories, Collections.emptyList());
}
private List<LibraryProcessor> getProcessors(LibraryContext context) {
var processors = new ArrayList<LibraryProcessor>();
for (LibraryProcessorFactory<?> factory : LIBRARY_PROCESSORS) {
final LibraryProcessor processor = factory.apply(platform, context);
final LibraryProcessor.ApplicationResult applicationResult = processor.getApplicationResult();
switch (applicationResult) {
case MUST_APPLY -> {
processors.add(processor);
}
case CAN_APPLY -> {
if (enabledProcessors.contains(processor.getClass().getSimpleName())) {
processors.add(processor);
}
}
case DONT_APPLY -> { }
}
}
return Collections.unmodifiableList(processors);
}
public List<Library> processLibraries(List<Library> librariesIn, LibraryContext libraryContext) {
final List<LibraryProcessor> processors = getProcessors(libraryContext);
if (processors.isEmpty()) {
return librariesIn;
}
return processLibraries(processors, librariesIn);
}
@VisibleForTesting
public List<Library> processLibraries(List<LibraryProcessor> processors, List<Library> librariesIn) {
var libraries = new ArrayList<>(librariesIn);
for (LibraryProcessor processor : processors) {
var processedLibraries = new ArrayList<Library>();
final Predicate<Library> predicate = processor.apply(processedLibraries::add);
for (Library library : libraries) {
if (predicate.test(library)) {
processedLibraries.add(library);
}
}
processor.applyRepositories(repositories);
libraries = processedLibraries;
}
return Collections.unmodifiableList(libraries);
}
public interface LibraryProcessorFactory<T extends LibraryProcessor> extends BiFunction<Platform, LibraryContext, T> {
}
}

View File

@@ -0,0 +1,103 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.fabricmc.loom.configuration.providers.BundleMetadata;
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
import net.fabricmc.loom.util.Platform;
/**
* Utils to get the Minecraft libraries for a given platform, no processing is applied.
*/
public class MinecraftLibraryHelper {
private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-(\\k<version>)-)(?<classifier>.*).jar$");
public static List<Library> getLibrariesForPlatform(MinecraftVersionMeta versionMeta, Platform platform) {
var libraries = new ArrayList<Library>();
for (MinecraftVersionMeta.Library library : versionMeta.libraries()) {
if (!library.isValidForOS(platform)) {
continue;
}
if (library.artifact() != null) {
Library mavenLib = Library.fromMaven(library.name(), Library.Target.COMPILE);
// Versions that have the natives on the classpath, attempt to target them as natives.
if (mavenLib.classifier() != null && mavenLib.classifier().startsWith("natives-")) {
mavenLib = mavenLib.withTarget(Library.Target.NATIVES);
}
libraries.add(mavenLib);
}
if (library.hasNativesForOS(platform)) {
final MinecraftVersionMeta.Download download = library.classifierForOS(platform);
if (download != null) {
libraries.add(downloadToLibrary(download));
}
}
}
return Collections.unmodifiableList(libraries);
}
private static Library downloadToLibrary(MinecraftVersionMeta.Download download) {
final String path = download.path();
final Matcher matcher = NATIVES_PATTERN.matcher(path);
if (!matcher.find()) {
throw new IllegalStateException("Failed to match regex for natives path : " + path);
}
final String group = matcher.group("group").replace("/", ".");
final String name = matcher.group("name");
final String version = matcher.group("version");
final String classifier = matcher.group("classifier");
final String dependencyNotation = "%s:%s:%s:%s".formatted(group, name, version, classifier);
return Library.fromMaven(dependencyNotation, Library.Target.NATIVES);
}
public static List<Library> getServerLibraries(BundleMetadata bundleMetadata) {
Objects.requireNonNull(bundleMetadata);
var libraries = new ArrayList<Library>();
for (BundleMetadata.Entry library : bundleMetadata.libraries()) {
libraries.add(Library.fromMaven(library.name(), Library.Target.COMPILE));
}
return libraries;
}
}

View File

@@ -0,0 +1,100 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import net.fabricmc.loom.LoomRepositoryPlugin;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Platform;
/**
* A processor to add support for ARM64.
*/
public class ArmNativesLibraryProcessor extends LibraryProcessor {
private static final String LWJGL_GROUP = "org.lwjgl";
public ArmNativesLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
if (!context.usesLWJGL3()) {
// Only supports LWJGL 3
return ApplicationResult.DONT_APPLY;
}
if (!platform.getArchitecture().isArm() || !platform.getArchitecture().is64Bit()) {
// Not an arm64 platform, can never apply this.
return ApplicationResult.DONT_APPLY;
}
if (platform.getOperatingSystem().isMacOS()) {
if (context.supportsArm64MacOS()) {
// This version already supports arm64 macOS, nothing to do.
return ApplicationResult.DONT_APPLY;
}
// Must upgrade natives to support macos ARM
return ApplicationResult.MUST_APPLY;
}
if (!context.hasClasspathNatives()) {
// Only support updating linux and windows versions that have the natives on the classpath.
return ApplicationResult.DONT_APPLY;
}
// Must add arm 64 to Windows and Linux for versions that use classpath natives.
return ApplicationResult.MUST_APPLY;
}
@Override
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
return library -> {
if (library.is(LWJGL_GROUP) && library.target() == Library.Target.NATIVES && (library.classifier() != null && library.classifier().startsWith("natives-"))) {
// Add the arm64 natives.
dependencyConsumer.accept(library.withClassifier(library.classifier() + "-arm64"));
if (!context.hasClasspathNatives()) {
// Remove the none arm64 natives when extracting.
return false;
}
}
return true;
};
}
@Override
public void applyRepositories(RepositoryHandler repositories) {
LoomRepositoryPlugin.forceLWJGLFromMavenCentral(repositories);
}
}

View File

@@ -0,0 +1,63 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.List;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import net.fabricmc.loom.LoomRepositoryPlugin;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Platform;
/**
* 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version.
*/
public class LWJGL2MavenLibraryProcessor extends LibraryProcessor {
private static final List<String> LWJGL_LIST = List.of(
"org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3",
"org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20131017"
);
public LWJGL2MavenLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
if (context.usesLWJGL3()) {
// Does not support LWJGL 3
return ApplicationResult.DONT_APPLY;
}
return LWJGL_LIST.stream().anyMatch(context::hasLibrary) ? ApplicationResult.MUST_APPLY : ApplicationResult.DONT_APPLY;
}
@Override
public void applyRepositories(RepositoryHandler repositories) {
LoomRepositoryPlugin.setupForLegacyVersions(repositories);
}
}

View File

@@ -0,0 +1,90 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import net.fabricmc.loom.LoomRepositoryPlugin;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Platform;
public class LWJGL3UpgradeLibraryProcessor extends LibraryProcessor {
private static final String LWJGL_GROUP = "org.lwjgl";
private static final String LWJGL_VERSION = "3.3.2";
public LWJGL3UpgradeLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
if (!context.usesLWJGL3()) {
// Only supports LWJGL 3
return ApplicationResult.DONT_APPLY;
}
if (context.isJava19OrLater() && !context.supportsJava19OrLater()) {
// Update LWJGL when Java 19 is not supported
return ApplicationResult.MUST_APPLY;
}
if (upgradeMacOSArm()) {
// Update LWJGL when ARM64 macOS is not supported
return ApplicationResult.MUST_APPLY;
}
// If the developer requests we can still upgrade LWJGL on this platform
return ApplicationResult.CAN_APPLY;
}
@Override
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
return library -> {
if (library.is(LWJGL_GROUP) && library.name().startsWith("lwjgl")) {
// Replace the natives with the new version, none natives become runtime only
final Library.Target target = library.target() == Library.Target.NATIVES ? Library.Target.NATIVES : Library.Target.RUNTIME;
final Library upgradedLibrary = library.withVersion(LWJGL_VERSION).withTarget(target);
dependencyConsumer.accept(upgradedLibrary);
}
return true;
};
}
@Override
public void applyRepositories(RepositoryHandler repositories) {
LoomRepositoryPlugin.forceLWJGLFromMavenCentral(repositories);
}
// Add support for macOS
private boolean upgradeMacOSArm() {
return platform.getOperatingSystem().isMacOS() && platform.getArchitecture().isArm() && !context.supportsArm64MacOS() && !context.hasClasspathNatives();
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.function.Consumer;
import java.util.function.Predicate;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Platform;
/**
* Never depend on the legacy "asm-all".
*/
public class LegacyASMLibraryProcessor extends LibraryProcessor {
private static final String LEGACY_ASM = "org.ow2.asm:asm-all";
public LegacyASMLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
// Always attempt to remove
return ApplicationResult.MUST_APPLY;
}
@Override
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
return library -> !library.is(LEGACY_ASM);
}
}

View File

@@ -0,0 +1,62 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.function.Consumer;
import java.util.function.Predicate;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.Platform;
public class LoomNativeSupportLibraryProcessor extends LibraryProcessor {
public LoomNativeSupportLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
if (!context.usesLWJGL3()) {
// Only supports LWJGL 3
return ApplicationResult.DONT_APPLY;
}
if (platform.getOperatingSystem().isMacOS() && platform.getArchitecture().isArm() && !context.supportsArm64MacOS()) {
// Add the loom native support mod when adding ARM64 macOS support
return ApplicationResult.MUST_APPLY;
}
// A developer can opt into this
return ApplicationResult.CAN_APPLY;
}
@Override
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
dependencyConsumer.accept(Library.fromMaven(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION, Library.Target.LOCAL_MOD));
return ALLOW_ALL;
}
}

View File

@@ -0,0 +1,74 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.function.Consumer;
import java.util.function.Predicate;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Platform;
public class ObjcBridgeUpgradeLibraryProcessor extends LibraryProcessor {
private static final String OBJC_BRIDGE_PREFIX = "ca.weblite:java-objc-bridge";
private static final String OBJC_BRIDGE_VERSION = "1.1";
private static final String OBJC_BRIDGE_NAME = "%s:%s".formatted(OBJC_BRIDGE_PREFIX, OBJC_BRIDGE_VERSION);
public ObjcBridgeUpgradeLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
if (!context.usesLWJGL3()) {
// Only supports LWJGL 3
return ApplicationResult.DONT_APPLY;
}
if (!(platform.getOperatingSystem().isMacOS() && platform.getArchitecture().isArm())) {
// Only supported on arm64 macOS
return ApplicationResult.DONT_APPLY;
}
// Apply when Arm64 macOS is unsupported by Minecraft
return context.supportsArm64MacOS() ? ApplicationResult.DONT_APPLY : ApplicationResult.MUST_APPLY;
}
@Override
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
// Add the updated library on the runtime classpath.
dependencyConsumer.accept(Library.fromMaven(OBJC_BRIDGE_NAME, Library.Target.RUNTIME));
return library -> {
if (library.is(OBJC_BRIDGE_PREFIX)) {
// Remove the natives, as they are included in the dep library we added to the runtime classpath above.
return library.target() != Library.Target.NATIVES;
}
return true;
};
}
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.library.processors;
import java.util.function.Consumer;
import java.util.function.Predicate;
import net.fabricmc.loom.configuration.providers.minecraft.library.Library;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryContext;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessor;
import net.fabricmc.loom.util.Platform;
public class RuntimeLog4jLibraryProcessor extends LibraryProcessor {
private static final String LOG4J_GROUP = "org.apache.logging.log4j";
public RuntimeLog4jLibraryProcessor(Platform platform, LibraryContext context) {
super(platform, context);
}
@Override
public ApplicationResult getApplicationResult() {
return ApplicationResult.CAN_APPLY;
}
@Override
public Predicate<Library> apply(Consumer<Library> dependencyConsumer) {
return library -> {
if (library.is(LOG4J_GROUP)) {
dependencyConsumer.accept(library.withTarget(Library.Target.RUNTIME));
return false;
}
return true;
};
}
}

View File

@@ -176,7 +176,7 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(remappedJars.outputJarPath()).build()) {
outputConsumer.addNonClassFiles(remappedJars.inputJar());
remapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(getProject()));
remapper.readClassPath(TinyRemapperHelper.getMinecraftCompileLibraries(getProject()));
for (Path path : remappedJars.remapClasspath()) {
remapper.readClassPath(path);

View File

@@ -71,7 +71,7 @@ import net.fabricmc.loom.decompilers.LineNumberRemapper;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.FileSystemUtil;
import net.fabricmc.loom.util.IOStringConsumer;
import net.fabricmc.loom.util.OperatingSystem;
import net.fabricmc.loom.util.Platform;
import net.fabricmc.loom.util.gradle.ThreadedProgressLoggerConsumer;
import net.fabricmc.loom.util.gradle.ThreadedSimpleProgressLogger;
import net.fabricmc.loom.util.gradle.WorkerDaemonClientsManagerHelper;
@@ -124,11 +124,13 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
@TaskAction
public void run() throws IOException {
if (!OperatingSystem.is64Bit()) {
final Platform platform = Platform.CURRENT;
if (!platform.getArchitecture().is64Bit()) {
throw new UnsupportedOperationException("GenSources task requires a 64bit JVM to run due to the memory requirements.");
}
if (!OperatingSystem.isUnixDomainSocketsSupported()) {
if (!platform.supportsUnixDomainSockets()) {
getProject().getLogger().warn("Decompile worker logging disabled as Unix Domain Sockets is not supported on your operating system.");
doWork(null);
@@ -167,7 +169,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
params.getIPCPath().set(ipcServer.getPath().toFile());
}
params.getClassPath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES));
params.getClassPath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
});
try {
@@ -223,7 +225,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
public abstract static class DecompileAction implements WorkAction<DecompileParams> {
@Override
public void execute() {
if (!getParameters().getIPCPath().isPresent() || !OperatingSystem.isUnixDomainSocketsSupported()) {
if (!getParameters().getIPCPath().isPresent() || !Platform.CURRENT.supportsUnixDomainSockets()) {
// Does not support unix domain sockets, print to sout.
doDecompile(System.out::println);
return;

View File

@@ -68,7 +68,7 @@ public abstract class UnpickJarTask extends JavaExec {
getMainClass().set("daomephsta.unpick.cli.Main");
getConstantJar().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MAPPING_CONSTANTS));
getUnpickClasspath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES));
getUnpickClasspath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
getUnpickClasspath().from(getProject().getConfigurations().getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED));
}

View File

@@ -54,7 +54,7 @@ public abstract class GenerateRemapClasspathTask extends AbstractLoomTask {
public GenerateRemapClasspathTask() {
final ConfigurationContainer configurations = getProject().getConfigurations();
getRemapClasspath().from(configurations.named(Constants.Configurations.LOADER_DEPENDENCIES));
getRemapClasspath().from(configurations.named(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES));
getExtension().getRuntimeRemapConfigurations().stream()
.map(RemapConfigurationSettings::getName)
.map(configurations::named)

View File

@@ -46,15 +46,24 @@ public class Constants {
public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped";
public static final String INCLUDE = "include";
public static final String MINECRAFT = "minecraft";
public static final String MINECRAFT_COMPILE_LIBRARIES = "minecraftLibraries";
public static final String MINECRAFT_RUNTIME_LIBRARIES = "minecraftRuntimeLibraries";
/**
* The server specific configuration will be empty when using a legacy (pre 21w38a server jar)
* These configurations contain the minecraft client libraries.
*/
public static final String MINECRAFT_CLIENT_COMPILE_LIBRARIES = "minecraftClientLibraries";
public static final String MINECRAFT_CLIENT_RUNTIME_LIBRARIES = "minecraftClientRuntimeLibraries";
/**
* The server specific configurations will be empty when using a legacy (pre 21w38a server jar)
* find the client only dependencies on the "minecraftLibraries" config.
*/
public static final String MINECRAFT_SERVER_DEPENDENCIES = "minecraftServerLibraries";
public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries";
public static final String MINECRAFT_RUNTIME_DEPENDENCIES = "minecraftRuntimeOnlyLibraries";
public static final String MINECRAFT_SERVER_COMPILE_LIBRARIES = "minecraftServerLibraries";
public static final String MINECRAFT_SERVER_RUNTIME_LIBRARIES = "minecraftServerRuntimeLibraries";
/**
* Not used on Minecraft 1.19-pre1 or later. Natives are all loaded from the classpath.
* Before Minecraft 1.19-pre1 this contains libraries that need to be extracted otherwise this goes on the runtime classpath.
*/
public static final String MINECRAFT_NATIVES = "minecraftNatives";
public static final String MAPPINGS = "mappings";
@@ -141,5 +150,6 @@ public class Constants {
public static final String DONT_REMAP = "fabric.loom.dontRemap";
public static final String DISABLE_REMAPPED_VARIANTS = "fabric.loom.disableRemappedVariants";
public static final String DISABLE_PROJECT_DEPENDENT_MODS = "fabric.loom.disableProjectDependentMods";
public static final String LIBRARY_PROCESSORS = "fabric.loom.libraryProcessors";
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2016-2021 FabricMC
* Copyright (c) 2023 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
@@ -29,42 +29,52 @@ import java.io.UncheckedIOException;
import java.net.StandardProtocolFamily;
import java.nio.channels.ServerSocketChannel;
public class OperatingSystem {
public static final String WINDOWS = "windows";
public static final String MAC_OS = "osx";
public static final String LINUX = "linux";
final class CurrentPlatform implements Platform {
static final Platform INSTANCE = new CurrentPlatform();
public static final String CURRENT_OS = getOS();
private final OperatingSystem operatingSystem;
private final Architecture architecture;
private final boolean supportsUnixDomainSockets;
private static String getOS() {
String osName = System.getProperty("os.name").toLowerCase();
private CurrentPlatform() {
this.operatingSystem = getCurrentOperatingSystem();
this.architecture = getCurrentArchitecture();
this.supportsUnixDomainSockets = isUnixDomainSocketsSupported();
}
private static OperatingSystem getCurrentOperatingSystem() {
final String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) {
return WINDOWS;
return OperatingSystem.WINDOWS;
} else if (osName.contains("mac")) {
return MAC_OS;
return OperatingSystem.MAC_OS;
} else {
return LINUX;
// Or unknown
return OperatingSystem.LINUX;
}
}
public static boolean is64Bit() {
return System.getProperty("sun.arch.data.model").contains("64");
}
private static Architecture getCurrentArchitecture() {
final String arch = System.getProperty("os.arch");
final boolean is64Bit = arch.contains("64") || arch.startsWith("armv8");
final boolean isArm = arch.startsWith("arm") || arch.startsWith("aarch64");
public static boolean isCIBuild() {
String loomProperty = System.getProperty("fabric.loom.ci");
return new Architecture() {
@Override
public boolean is64Bit() {
return is64Bit;
}
if (loomProperty != null) {
return loomProperty.equalsIgnoreCase("true");
}
// CI seems to be set by most popular CI services
return System.getenv("CI") != null;
@Override
public boolean isArm() {
return isArm;
}
};
}
// Requires Unix, or Windows 10 17063 or later. See: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
public static boolean isUnixDomainSocketsSupported() {
private static boolean isUnixDomainSocketsSupported() {
try (ServerSocketChannel serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) {
return true;
} catch (UnsupportedOperationException e) {
@@ -73,4 +83,19 @@ public class OperatingSystem {
throw new UncheckedIOException(e);
}
}
@Override
public OperatingSystem getOperatingSystem() {
return operatingSystem;
}
@Override
public Architecture getArchitecture() {
return architecture;
}
@Override
public boolean supportsUnixDomainSockets() {
return supportsUnixDomainSockets;
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2021 FabricMC
* Copyright (c) 2023 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,14 +24,36 @@
package net.fabricmc.loom.util;
public record Architecture(String name) {
public static final Architecture CURRENT = new Architecture(System.getProperty("os.arch"));
public interface Platform {
Platform CURRENT = CurrentPlatform.INSTANCE;
public boolean is64Bit() {
return name.contains("64") || name.startsWith("armv8");
enum OperatingSystem {
WINDOWS,
MAC_OS,
LINUX; // Or Unknown
public boolean isWindows() {
return this == WINDOWS;
}
public boolean isMacOS() {
return this == MAC_OS;
}
public boolean isLinux() {
return this == LINUX;
}
}
public boolean isArm() {
return name.startsWith("arm") || name.startsWith("aarch64");
OperatingSystem getOperatingSystem();
interface Architecture {
boolean is64Bit();
boolean isArm();
}
Architecture getArchitecture();
boolean supportsUnixDomainSockets();
}

View File

@@ -249,7 +249,7 @@ public class SourceRemapper {
final List<Path> classPath = new ArrayList<>();
for (File file : project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()) {
for (File file : project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES).getFiles()) {
classPath.add(file.toPath());
}

View File

@@ -94,8 +94,8 @@ public final class TinyRemapperHelper {
return builder.build();
}
public static Path[] getMinecraftDependencies(Project project) {
return project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles()
public static Path[] getMinecraftCompileLibraries(Project project) {
return project.getConfigurations().getByName(Constants.Configurations.MINECRAFT_COMPILE_LIBRARIES).getFiles()
.stream().map(File::toPath).toArray(Path[]::new);
}