From 0d76d81dabf8aee729e2fda46e6aa8b4b26f9273 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Wed, 28 Oct 2026 21:55:09 -0400 Subject: [PATCH 1/2] Downloaded LWJGL libraries - LWJGL is no longer shaded into the Bukkit jar - plugin.yml lists the LWJGL jars and Linux natives as Spigot libraries - The Paper loader resolves the same plugin.yml list through the Maven Central mirror - The packed payload no longer reserves the LWJGL natives prefix - Tests cover reading the library list from the plugin jar --- adapters/bukkit/plugin/build.gradle | 11 ++++++ .../art/arcane/iris/IrisPluginLoader.java | 35 +++++++++++++++++++ .../plugin/src/main/resources/plugin.yml | 1 + .../art/arcane/iris/IrisPluginLoaderTest.java | 19 ++++++++++ build.gradle | 9 +---- 5 files changed, 67 insertions(+), 8 deletions(-) diff --git a/adapters/bukkit/plugin/build.gradle b/adapters/bukkit/plugin/build.gradle index d711f56e4..95f7d079f 100644 --- a/adapters/bukkit/plugin/build.gradle +++ b/adapters/bukkit/plugin/build.gradle @@ -28,6 +28,16 @@ dependencies { } } +String lwjglVersion = libs.versions.lwjgl.get() +List mavenLibraries = [ + "org.lwjgl:lwjgl:${lwjglVersion}", + "org.lwjgl:lwjgl:jar:natives-linux:${lwjglVersion}", + "org.lwjgl:lwjgl-opengl:${lwjglVersion}", + "org.lwjgl:lwjgl-opengl:jar:natives-linux:${lwjglVersion}", + "org.lwjgl:lwjgl-egl:${lwjglVersion}", + "org.lwjgl:lwjgl-jawt:${lwjglVersion}", +].collect { GString coordinate -> coordinate.toString() } + tasks.named('processResources').configure { def pluginProperties = [ name : rootProject.name, @@ -35,6 +45,7 @@ tasks.named('processResources').configure { apiVersion: apiVersion, main : mainClass, bootstrapper: bootstrapperClass, + libraries : mavenLibraries.collect { String coordinate -> "'${coordinate}'" }.join(', '), ] inputs.properties(pluginProperties) filesMatching(['**/paper-plugin.yml', '**/plugin.yml']) { diff --git a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/IrisPluginLoader.java b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/IrisPluginLoader.java index 5f3b93e39..6e0c04585 100644 --- a/adapters/bukkit/plugin/src/main/java/art/arcane/iris/IrisPluginLoader.java +++ b/adapters/bukkit/plugin/src/main/java/art/arcane/iris/IrisPluginLoader.java @@ -6,12 +6,22 @@ import io.papermc.paper.plugin.bootstrap.PluginProviderContext; import io.papermc.paper.plugin.loader.PluginClasspathBuilder; import io.papermc.paper.plugin.loader.PluginLoader; import io.papermc.paper.plugin.loader.library.impl.JarLibrary; +import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver; +import org.bukkit.configuration.file.YamlConfiguration; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.RemoteRepository; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; @SuppressWarnings("UnstableApiUsage") public final class IrisPluginLoader implements PluginLoader { @@ -40,6 +50,21 @@ public final class IrisPluginLoader implements PluginLoader { classpathBuilder.addLibrary(new JarLibrary(library)); } } + classpathBuilder.addLibrary(mavenResolver(mavenLibraries(context.getPluginSource()))); + } + + static List mavenLibraries(Path pluginJar) { + try (ZipFile jar = new ZipFile(pluginJar.toFile())) { + ZipEntry descriptor = jar.getEntry("plugin.yml"); + if (descriptor == null) { + throw new IllegalStateException("The Iris jar " + pluginJar + " has no plugin.yml library list."); + } + try (Reader reader = new InputStreamReader(jar.getInputStream(descriptor), StandardCharsets.UTF_8)) { + return YamlConfiguration.loadConfiguration(reader).getStringList("libraries"); + } + } catch (IOException failure) { + throw new IllegalStateException("Unable to read the Iris library list from " + pluginJar + ".", failure); + } } static List relocatedLibraries(Path libraryRoot) { @@ -59,6 +84,16 @@ public final class IrisPluginLoader implements PluginLoader { } } + private static MavenLibraryResolver mavenResolver(List coordinates) { + MavenLibraryResolver resolver = new MavenLibraryResolver(); + resolver.addRepository(new RemoteRepository.Builder("central", "default", + MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build()); + for (String coordinate : coordinates) { + resolver.addDependency(new Dependency(new DefaultArtifact(coordinate), null)); + } + return resolver; + } + private static boolean isRelocatedLibrary(Path path) { int count = path.getNameCount(); for (int i = 0; i < count - 2; i++) { diff --git a/adapters/bukkit/plugin/src/main/resources/plugin.yml b/adapters/bukkit/plugin/src/main/resources/plugin.yml index d92da834f..585ecde53 100644 --- a/adapters/bukkit/plugin/src/main/resources/plugin.yml +++ b/adapters/bukkit/plugin/src/main/resources/plugin.yml @@ -27,3 +27,4 @@ permissions: description: Allows survival players to fell Iris-managed trees with an axe. default: op api-version: '${apiVersion}' +libraries: [ ${libraries} ] diff --git a/adapters/bukkit/plugin/src/test/java/art/arcane/iris/IrisPluginLoaderTest.java b/adapters/bukkit/plugin/src/test/java/art/arcane/iris/IrisPluginLoaderTest.java index ddfa94791..513a94a00 100644 --- a/adapters/bukkit/plugin/src/test/java/art/arcane/iris/IrisPluginLoaderTest.java +++ b/adapters/bukkit/plugin/src/test/java/art/arcane/iris/IrisPluginLoaderTest.java @@ -4,9 +4,13 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import static org.junit.Assert.assertEquals; @@ -31,4 +35,19 @@ public class IrisPluginLoaderTest { assertEquals(List.of(relocatedCaffeine, relocatedGson), libraries); } + + @Test + public void readsMavenLibrariesFromTheSpigotDescriptorInThePluginJar() throws Exception { + Path jar = temporaryFolder.getRoot().toPath().resolve("Iris.jar"); + try (OutputStream file = Files.newOutputStream(jar); ZipOutputStream zip = new ZipOutputStream(file)) { + zip.putNextEntry(new ZipEntry("plugin.yml")); + zip.write("name: Iris\nlibraries: [ 'org.lwjgl:lwjgl:3.4.3', 'org.lwjgl:lwjgl:jar:natives-linux:3.4.3' ]\n" + .getBytes(StandardCharsets.UTF_8)); + zip.closeEntry(); + } + + List libraries = IrisPluginLoader.mavenLibraries(jar); + + assertEquals(List.of("org.lwjgl:lwjgl:3.4.3", "org.lwjgl:lwjgl:jar:natives-linux:3.4.3"), libraries); + } } diff --git a/build.gradle b/build.gradle index 6de2fb813..d522eb3b9 100644 --- a/build.gradle +++ b/build.gradle @@ -179,13 +179,6 @@ def jarJar = configurations.create('jarJar') dependencies { add('included', project(path: ':core', configuration: 'shadow')) add('included', project(path: ':adapters:bukkit:plugin', configuration: 'runtimeElements')) - // Shaded: the runtime downloader can neither fetch the natives classifiers nor relocate lwjgl's own jar. - add('included', libs.lwjgl) - add('included', libs.lwjgl.opengl) - add('included', libs.lwjgl.egl) - add('included', libs.lwjgl.jawt) - add('included', variantOf(libs.lwjgl) { classifier('natives-linux') }) - add('included', variantOf(libs.lwjgl.opengl) { classifier('natives-linux') }) add('jarJar', project(':core:agent')) } @@ -742,7 +735,7 @@ pluginPackaging { policyName = 'Iris Bukkit' packed = true packedJarAccessors = ['art/arcane/iris/platform/bukkit/plugin/VolmitPlugin#getJarFile'] - packedPayloadOnlyPrefixes = ['linux/x64/org/lwjgl/', 'iris-language-guides/'] + packedPayloadOnlyPrefixes = ['iris-language-guides/'] stripDirectories = true stripLocalVariables = true releaseCompression = providers.gradleProperty('compactRelease') From b6e9f8a14d49d138e16a19ecb397e516e4b87ec0 Mon Sep 17 00:00:00 2001 From: Brian Neumann-Fopiano Date: Wed, 28 Oct 2026 22:58:20 -0400 Subject: [PATCH 2/2] Fixed VolmLib commit stamp - The VolmLib stamp records a commit only when the checkout is its own Git repository - A VolmLib copy inside another repository stamps an unknown commit --- gradle/volmlib-resolution.settings.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gradle/volmlib-resolution.settings.gradle b/gradle/volmlib-resolution.settings.gradle index ca1f9e821..e47636609 100644 --- a/gradle/volmlib-resolution.settings.gradle +++ b/gradle/volmlib-resolution.settings.gradle @@ -120,7 +120,9 @@ if (irisLocalVolmLibDirectory == null) { } } } else { - String commit = irisGit(irisLocalVolmLibDirectory, 'rev-parse', 'HEAD') + String root = irisGit(irisLocalVolmLibDirectory, 'rev-parse', '--show-toplevel') + boolean ownRepository = root != null && new File(root).canonicalPath == irisLocalVolmLibDirectory.canonicalPath + String commit = ownRepository ? irisGit(irisLocalVolmLibDirectory, 'rev-parse', 'HEAD') : null String status = commit == null ? null : irisGit(irisLocalVolmLibDirectory, '--no-optional-locks', 'status', '--porcelain') String dirty = status == null ? 'unknown' : String.valueOf(!status.isEmpty()) irisVolmLibStamp = [source: 'local', commit: commit ?: 'unknown', dirty: dirty]