From 3700fad9ca0efcc71a2ec8639e912214ed6df2c4 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Sun, 26 Jun 2022 00:02:46 +0100 Subject: [PATCH] ARM64 Windows & Linux support for MC versions that have classpath natives. Closes #675 --- .../fabricmc/loom/LoomRepositoryPlugin.java | 20 ++- .../minecraft/LWJGLVersionOverride.java | 19 +- .../minecraft/MinecraftLibraryProvider.java | 167 +++++++++++------- .../minecraft/MinecraftProvider.java | 4 +- .../net/fabricmc/loom/util/Architecture.java | 12 +- 5 files changed, 145 insertions(+), 77 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/LoomRepositoryPlugin.java b/src/main/java/net/fabricmc/loom/LoomRepositoryPlugin.java index 2301f575..c0da3e8d 100644 --- a/src/main/java/net/fabricmc/loom/LoomRepositoryPlugin.java +++ b/src/main/java/net/fabricmc/loom/LoomRepositoryPlugin.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-2022 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -117,4 +117,22 @@ public class LoomRepositoryPlugin implements Plugin { }); }); } + + public static void forceLWJGLFromMavenCentral(Project project) { + // Force LWJGL from central, as it contains all the platform natives. + MavenArtifactRepository central = project.getRepositories().maven(repo -> { + repo.setName("MavenCentralLWJGL"); + repo.setUrl(ArtifactRepositoryContainer.MAVEN_CENTRAL_URL); + repo.content(content -> { + content.includeGroup("org.lwjgl"); + }); + }); + + project.getRepositories().exclusiveContent(repository -> { + repository.forRepositories(central); + repository.filter(filter -> { + filter.includeGroup("org.lwjgl"); + }); + }); + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java index 7cdcde94..f06f613d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LWJGLVersionOverride.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-2022 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,9 +31,11 @@ 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 { @@ -81,6 +83,21 @@ public class LWJGLVersionOverride { 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) { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java index 3d155030..f79674da 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java @@ -28,112 +28,155 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.gradle.api.Project; -import org.gradle.api.artifacts.ExternalModuleDependency; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomRepositoryPlugin; import net.fabricmc.loom.configuration.providers.BundleMetadata; +import net.fabricmc.loom.util.Architecture; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.OperatingSystem; public class MinecraftLibraryProvider { private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?.*)/(.*?)/(?.*)/((?.*?)-(\\k)-)(?.*).jar$"); + private static final boolean IS_MACOS = OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS); - public void provide(MinecraftProvider minecraftProvider, Project project) { + private final Project project; + private final MinecraftVersionMeta versionInfo; + private final BundleMetadata serverBundleMetadata; + private final boolean runtimeOnlyLog4j; + private final boolean provideClient; + private final boolean provideServer; + + public MinecraftLibraryProvider(MinecraftProvider minecraftProvider, Project project) { final LoomGradleExtension extension = LoomGradleExtension.get(project); final MinecraftJarConfiguration jarConfiguration = extension.getMinecraftJarConfiguration().get(); - final MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); - final BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata(); - final boolean runtimeOnlyLog4j = extension.getRuntimeOnlyLog4j().get(); - final boolean hasNativesToExtract = versionInfo.hasNativesToExtract(); - final boolean overrideLWJGL = hasNativesToExtract && (LWJGLVersionOverride.overrideByDefault(versionInfo) || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride")); - final boolean isMacOS = OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS); + 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; + } - if (overrideLWJGL) { - project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION); + public void provide() { + 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); + } } - if (hasNativesToExtract) { - project.getConfigurations().register(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false)); + if (provideServer) { + provideServerLibraries(); + } + } + + private void provideClientLibraries(boolean overrideLWJGL, boolean hasNativesToExtract) { + final boolean isArm = Architecture.CURRENT.isArm(); + final boolean classpathArmNatives = !hasNativesToExtract && isArm; + + 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) { - // 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version. - if ("org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3".equals(library.name()) || "org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20131017".equals(library.name())) { + 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); - } else if (library.name().startsWith("org.ow2.asm:asm-all")) { + } + + if (name.startsWith("org.ow2.asm:asm-all")) { // Don't want asm-all, use the modern split version. continue; } - if (runtimeOnlyLog4j && library.name().startsWith("org.apache.logging.log4j")) { + if (runtimeOnlyLog4j && name.startsWith("org.apache.logging.log4j")) { // Make log4j a runtime only dep to force slf4j. - project.getDependencies().add(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, library.name()); - } else if (jarConfiguration.getSupportedEnvironments().contains("client")) { - // Client only library, or legacy version - project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, library.name()); - } else { - project.getLogger().debug("Minecraft library ({}) was not added to any configuration", library.name()); + project.getDependencies().add(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. + project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, name + "-arm64"); + } + + project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, name); } if (library.hasNativesForOS()) { - MinecraftVersionMeta.Download nativeDownload = library.classifierForOS(); - - if (nativeDownload == null) { - continue; - } - - 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); - continue; - } - - 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. - continue; - } - - project.getLogger().debug("Add native dependency '{}'", dependencyNotation); - project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation); + provideNativesForLibrary(library, overrideLWJGL, IS_MACOS); } } + } + 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. + project.getDependencies().add(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, library.name()); + continue; + } + project.getDependencies().add(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, library.name()); } } + } - if (overrideLWJGL) { - LWJGLVersionOverride.DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s)); - LWJGLVersionOverride.NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s)); + private void provideNativesForLibrary(MinecraftVersionMeta.Library library, boolean overrideLWJGL, boolean isMacOS) { + MinecraftVersionMeta.Download nativeDownload = library.classifierForOS(); - if (isMacOS) { - LWJGLVersionOverride.MACOS_DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s)); - LWJGLVersionOverride.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); + if (nativeDownload == null) { + return; } + + 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; + } + + 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; + } + + project.getLogger().debug("Add native dependency '{}'", dependencyNotation); + project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation); } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java index 4c91dec5..77af1a19 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java @@ -120,8 +120,8 @@ public abstract class MinecraftProvider { serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath()); } - libraryProvider = new MinecraftLibraryProvider(); - libraryProvider.provide(this, getProject()); + libraryProvider = new MinecraftLibraryProvider(this, project); + libraryProvider.provide(); } protected void initFiles() { diff --git a/src/main/java/net/fabricmc/loom/util/Architecture.java b/src/main/java/net/fabricmc/loom/util/Architecture.java index 3208a306..afebd26c 100644 --- a/src/main/java/net/fabricmc/loom/util/Architecture.java +++ b/src/main/java/net/fabricmc/loom/util/Architecture.java @@ -24,15 +24,9 @@ package net.fabricmc.loom.util; -public class Architecture { +public record Architecture(String name) { public static final Architecture CURRENT = new Architecture(System.getProperty("os.arch")); - private final String name; - - public Architecture(String name) { - this.name = name; - } - public boolean is64Bit() { return name.contains("64") || name.startsWith("armv8"); } @@ -40,8 +34,4 @@ public class Architecture { public boolean isArm() { return name.startsWith("arm") || name.startsWith("aarch64"); } - - public String getName() { - return name; - } }