From 5e7b65a9a9c0c9f51679933447bfad543fc1e11d Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 23 May 2024 13:13:02 -0700 Subject: [PATCH] Allow using PluginLoader classpath API from Bukkit plugins (#10758) Allows using the PluginLoader API without any of the other changes imposed by switching to a paper-plugin.yml. Used by setting paper-plugin-loader in plugin.yml to the class name of your PluginLoader. Also allows skipping the libraries field by setting paper-skip-libraries to true (by default both libraries and jars provided by the PluginLoader are added to the classpath). --- ...plugin-to-use-Paper-PluginLoader-API.patch | 91 ++++++++++++ patches/server/0019-Paper-Plugins.patch | 20 +-- ...plugin-to-use-Paper-PluginLoader-API.patch | 130 ++++++++++++++++++ 3 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 patches/api/0479-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch create mode 100644 patches/server/1047-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch diff --git a/patches/api/0479-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch b/patches/api/0479-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch new file mode 100644 index 0000000000..786865aa5f --- /dev/null +++ b/patches/api/0479-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch @@ -0,0 +1,91 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 21 May 2024 13:18:00 -0700 +Subject: [PATCH] Allow Bukkit plugin to use Paper PluginLoader API + + +diff --git a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java +index c0691a849831f99268fdcb7b0f471f80a1a2a70e..8f45caade7357bc55c6a90cfe0c3a2feb2d877ff 100644 +--- a/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java ++++ b/src/main/java/org/bukkit/plugin/PluginDescriptionFile.java +@@ -259,6 +259,13 @@ public final class PluginDescriptionFile implements io.papermc.paper.plugin.conf + private Set awareness = ImmutableSet.of(); + private String apiVersion = null; + private List libraries = ImmutableList.of(); ++ // Paper start - plugin loader api ++ private String paperPluginLoader; ++ @org.jetbrains.annotations.ApiStatus.Internal @org.jetbrains.annotations.Nullable ++ public String getPaperPluginLoader() { ++ return this.paperPluginLoader; ++ } ++ // Paper end - plugin loader api + // Paper start - oh my goddddd + /** + * Don't use this. +@@ -1232,6 +1239,23 @@ public final class PluginDescriptionFile implements io.papermc.paper.plugin.conf + } else { + libraries = ImmutableList.of(); + } ++ // Paper start - plugin loader api ++ if (map.containsKey("paper-plugin-loader")) { ++ this.paperPluginLoader = map.get("paper-plugin-loader").toString(); ++ } ++ ++ /* ++ Allow skipping the Bukkit/Spigot 'libraries' list. By default, both the 'libraries' ++ list and the 'paper-plugin-loader' will contribute libraries. It may be desired to only ++ use one or the other. (i.e. 'libraries' on Spigot and 'paper-plugin-loader' on Paper) ++ */ ++ if (map.containsKey("paper-skip-libraries")) { ++ String skip = map.get("paper-skip-libraries").toString(); ++ if (skip.equalsIgnoreCase("true")) { ++ this.libraries = ImmutableList.of(); ++ } ++ } ++ // Paper end - plugin loader api + + try { + lazyPermissions = (Map) map.get("permissions"); +diff --git a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +index 8e1b6be2462aaa692efa1f72986921a6dc357196..c66252802c51174bc26f266cb5cdecdd856ff220 100644 +--- a/src/main/java/org/bukkit/plugin/java/LibraryLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/LibraryLoader.java +@@ -84,7 +84,13 @@ public class LibraryLoader + @Nullable + public ClassLoader createLoader(@NotNull PluginDescriptionFile desc) + { +- if ( desc.getLibraries().isEmpty() ) ++ // Paper start - plugin loader api ++ return this.createLoader(desc, null); ++ } ++ @Nullable ++ public ClassLoader createLoader(@NotNull PluginDescriptionFile desc, java.util.@Nullable List paperLibraryPaths) { ++ if ( desc.getLibraries().isEmpty() && paperLibraryPaths == null ) ++ // Paper end - plugin loader api + { + return null; + } +@@ -103,17 +109,20 @@ public class LibraryLoader + } + + DependencyResult result; +- try ++ if (!dependencies.isEmpty()) try // Paper - plugin loader api + { + result = repository.resolveDependencies( session, new DependencyRequest( new CollectRequest( (Dependency) null, dependencies, repositories ), null ) ); + } catch ( DependencyResolutionException ex ) + { + throw new RuntimeException( "Error resolving libraries", ex ); +- } ++ } else result = null; // Paper - plugin loader api + + List jarFiles = new ArrayList<>(); + List jarPaths = new ArrayList<>(); // Paper - remap libraries +- for ( ArtifactResult artifact : result.getArtifactResults() ) ++ // Paper start - plugin loader api ++ if (paperLibraryPaths != null) jarPaths.addAll(paperLibraryPaths); ++ if (result != null) for ( ArtifactResult artifact : result.getArtifactResults() ) ++ // Paper end - plugin loader api + { + // Paper start - remap libraries + jarPaths.add(artifact.getArtifact().getFile().toPath()); diff --git a/patches/server/0019-Paper-Plugins.patch b/patches/server/0019-Paper-Plugins.patch index 9b20647620..e5b13df65a 100644 --- a/patches/server/0019-Paper-Plugins.patch +++ b/patches/server/0019-Paper-Plugins.patch @@ -877,10 +877,10 @@ index 0000000000000000000000000000000000000000..f9a2c55a354c877749db3f92956de802 +} diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperPluginClassLoader.java b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperPluginClassLoader.java new file mode 100644 -index 0000000000000000000000000000000000000000..5a00e5c41274ded6b837fb81fa8f54616f2b7bc8 +index 0000000000000000000000000000000000000000..18401ede9cd1fc7094c6b74859929938e01795ca --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperPluginClassLoader.java -@@ -0,0 +1,205 @@ +@@ -0,0 +1,209 @@ +package io.papermc.paper.plugin.entrypoint.classloader; + +import io.papermc.paper.plugin.configuration.PluginMeta; @@ -936,13 +936,17 @@ index 0000000000000000000000000000000000000000..5a00e5c41274ded6b837fb81fa8f5461 + this.libraryLoader = libraryLoader; + + this.logger = logger; -+ if (this.configuration.hasOpenClassloader()) { ++ if (this.configuration().hasOpenClassloader()) { + this.group = PaperClassLoaderStorage.instance().registerOpenGroup(this); + } + } + ++ private PaperPluginMeta configuration() { ++ return (PaperPluginMeta) this.configuration; ++ } ++ + public void refreshClassloaderDependencyTree(DependencyContext dependencyContext) { -+ if (this.configuration.hasOpenClassloader()) { ++ if (this.configuration().hasOpenClassloader()) { + return; + } + if (this.group != null) { @@ -1088,13 +1092,13 @@ index 0000000000000000000000000000000000000000..5a00e5c41274ded6b837fb81fa8f5461 +} diff --git a/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java new file mode 100644 -index 0000000000000000000000000000000000000000..a4c18063854e050bd0c54d488ceeda43c768b6df +index 0000000000000000000000000000000000000000..967465e542483e93a736129b5f5c6622cefd33fa --- /dev/null +++ b/src/main/java/io/papermc/paper/plugin/entrypoint/classloader/PaperSimplePluginClassLoader.java @@ -0,0 +1,116 @@ +package io.papermc.paper.plugin.entrypoint.classloader; + -+import io.papermc.paper.plugin.provider.configuration.PaperPluginMeta; ++import io.papermc.paper.plugin.configuration.PluginMeta; +import io.papermc.paper.plugin.util.NamespaceChecker; +import org.jetbrains.annotations.ApiStatus; + @@ -1120,13 +1124,13 @@ index 0000000000000000000000000000000000000000..a4c18063854e050bd0c54d488ceeda43 + ClassLoader.registerAsParallelCapable(); + } + -+ protected final PaperPluginMeta configuration; ++ protected final PluginMeta configuration; + protected final Path source; + protected final Manifest jarManifest; + protected final URL jarUrl; + protected final JarFile jar; + -+ public PaperSimplePluginClassLoader(Path source, JarFile file, PaperPluginMeta configuration, ClassLoader parentLoader) throws IOException { ++ public PaperSimplePluginClassLoader(Path source, JarFile file, PluginMeta configuration, ClassLoader parentLoader) throws IOException { + super(source.getFileName().toString(), new URL[]{source.toUri().toURL()}, parentLoader); + + this.source = source; diff --git a/patches/server/1047-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch b/patches/server/1047-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch new file mode 100644 index 0000000000..980c3dc8a0 --- /dev/null +++ b/patches/server/1047-Allow-Bukkit-plugin-to-use-Paper-PluginLoader-API.patch @@ -0,0 +1,130 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> +Date: Tue, 21 May 2024 13:18:15 -0700 +Subject: [PATCH] Allow Bukkit plugin to use Paper PluginLoader API + + +diff --git a/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java +index f9d4b33050a6fe8c2dabe8e5eec075d95dc513e0..dc106685ecb483c33c06e4f83eda27be58251aad 100644 +--- a/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java ++++ b/src/main/java/io/papermc/paper/plugin/loader/PaperClasspathBuilder.java +@@ -41,15 +41,7 @@ public class PaperClasspathBuilder implements PluginClasspathBuilder { + } + + public PaperPluginClassLoader buildClassLoader(Logger logger, Path source, JarFile jarFile, PaperPluginMeta configuration) { +- PaperLibraryStore paperLibraryStore = new PaperLibraryStore(); +- for (ClassPathLibrary library : this.libraries) { +- library.register(paperLibraryStore); +- } +- +- List paths = paperLibraryStore.getPaths(); +- if (PluginInitializerManager.instance().pluginRemapper != null) { +- paths = PluginInitializerManager.instance().pluginRemapper.remapLibraries(paths); +- } ++ List paths = this.buildLibraryPaths(true); + URL[] urls = new URL[paths.size()]; + for (int i = 0; i < paths.size(); i++) { + Path path = paths.get(i); +@@ -69,4 +61,17 @@ public class PaperClasspathBuilder implements PluginClasspathBuilder { + throw new RuntimeException(exception); + } + } ++ ++ public List buildLibraryPaths(final boolean remap) { ++ PaperLibraryStore paperLibraryStore = new PaperLibraryStore(); ++ for (ClassPathLibrary library : this.libraries) { ++ library.register(paperLibraryStore); ++ } ++ ++ List paths = paperLibraryStore.getPaths(); ++ if (remap && PluginInitializerManager.instance().pluginRemapper != null) { ++ paths = PluginInitializerManager.instance().pluginRemapper.remapLibraries(paths); ++ } ++ return paths; ++ } + } +diff --git a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProvider.java b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProvider.java +index 75a2b687d58d76b94f8bec111df8613f120ff74b..0fd1040ed376f19c6d5326767baaf3048ce1bfb4 100644 +--- a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProvider.java ++++ b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProvider.java +@@ -40,15 +40,17 @@ public class SpigotPluginProvider implements PluginProvider, Provide + private final PluginDescriptionFile description; + private final JarFile jarFile; + private final Logger logger; ++ private final List paperLibraryPaths; + private final ComponentLogger componentLogger; + private ProviderStatus status; + private DependencyContext dependencyContext; + +- SpigotPluginProvider(Path path, JarFile file, PluginDescriptionFile description) { ++ SpigotPluginProvider(Path path, JarFile file, PluginDescriptionFile description, List paperLibraryPaths) { + this.path = path; + this.jarFile = file; + this.description = description; + this.logger = PaperPluginLogger.getLogger(description); ++ this.paperLibraryPaths = paperLibraryPaths; + this.componentLogger = ComponentLogger.logger(this.logger.getName()); + } + +@@ -120,7 +122,7 @@ public class SpigotPluginProvider implements PluginProvider, Provide + + final PluginClassLoader loader; + try { +- loader = new PluginClassLoader(this.getClass().getClassLoader(), this.description, dataFolder, this.path.toFile(), LIBRARY_LOADER.createLoader(this.description), this.jarFile, this.dependencyContext); // Paper ++ loader = new PluginClassLoader(this.getClass().getClassLoader(), this.description, dataFolder, this.path.toFile(), LIBRARY_LOADER.createLoader(this.description, this.paperLibraryPaths), this.jarFile, this.dependencyContext); // Paper + } catch (InvalidPluginException ex) { + throw ex; + } catch (Throwable ex) { +diff --git a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java +index fdb52ad85cfaa1d53aadcad72cec3d3c8c12c058..38075b7348ad7ca3cfece2bfae63e0cce827c694 100644 +--- a/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java ++++ b/src/main/java/io/papermc/paper/plugin/provider/type/spigot/SpigotPluginProviderFactory.java +@@ -1,9 +1,18 @@ + package io.papermc.paper.plugin.provider.type.spigot; + ++import com.destroystokyo.paper.utils.PaperPluginLogger; ++import io.papermc.paper.plugin.bootstrap.PluginProviderContextImpl; + import io.papermc.paper.plugin.entrypoint.classloader.BytecodeModifyingURLClassLoader; ++import io.papermc.paper.plugin.entrypoint.classloader.PaperSimplePluginClassLoader; ++import io.papermc.paper.plugin.loader.PaperClasspathBuilder; ++import io.papermc.paper.plugin.loader.PluginLoader; + import io.papermc.paper.plugin.provider.configuration.serializer.constraints.PluginConfigConstraints; + import io.papermc.paper.plugin.provider.type.PluginTypeFactory; ++import io.papermc.paper.plugin.provider.util.ProviderUtil; + import io.papermc.paper.util.MappingEnvironment; ++import java.util.List; ++import java.util.logging.Logger; ++import net.kyori.adventure.text.logger.slf4j.ComponentLogger; + import org.bukkit.plugin.InvalidDescriptionException; + import org.bukkit.plugin.PluginDescriptionFile; + import org.bukkit.plugin.java.LibraryLoader; +@@ -36,7 +45,28 @@ class SpigotPluginProviderFactory implements PluginTypeFactory paperLibraryPaths; ++ if (configuration.getPaperPluginLoader() != null) { ++ final Logger logger = PaperPluginLogger.getLogger(configuration); ++ PaperClasspathBuilder builder = new PaperClasspathBuilder(PluginProviderContextImpl.create( ++ configuration, ComponentLogger.logger(logger.getName()), source ++ )); ++ ++ try ( ++ PaperSimplePluginClassLoader simplePluginClassLoader = new PaperSimplePluginClassLoader(source, file, configuration, this.getClass().getClassLoader()) ++ ) { ++ PluginLoader loader = ProviderUtil.loadClass(configuration.getPaperPluginLoader(), PluginLoader.class, simplePluginClassLoader); ++ loader.classloader(builder); ++ } catch (IOException e) { ++ throw new RuntimeException(e); ++ } ++ ++ paperLibraryPaths = builder.buildLibraryPaths(false); ++ } else { ++ paperLibraryPaths = null; ++ } ++ ++ return new SpigotPluginProvider(source, file, configuration, paperLibraryPaths); + } + + @Override