Created
May 3, 2025 00:16
-
-
Save HSGamer/82b4e72b8eaf9cac41289cba51116497 to your computer and use it in GitHub Desktop.
Load and remap libraries at runtime with libby and PaperMC's PluginRemapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import net.byteflux.libby.BukkitLibraryManager; | |
| import net.byteflux.libby.Library; | |
| import org.bukkit.plugin.Plugin; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.io.UncheckedIOException; | |
| import java.lang.reflect.Field; | |
| import java.nio.file.Files; | |
| import java.nio.file.Path; | |
| import java.nio.file.StandardCopyOption; | |
| import java.util.Collections; | |
| import java.util.Enumeration; | |
| import java.util.List; | |
| import java.util.function.Function; | |
| import java.util.jar.JarEntry; | |
| import java.util.jar.JarFile; | |
| import java.util.jar.JarOutputStream; | |
| import java.util.jar.Manifest; | |
| public class RemappedBukkitLibraryManager extends BukkitLibraryManager { | |
| private final Function<List<Path>, List<Path>> REMAPPER; | |
| { | |
| Function<List<Path>, List<Path>> remapper; | |
| try { | |
| Class<?> clazz = Class.forName("org.bukkit.plugin.java.LibraryLoader"); | |
| Field remapperField = clazz.getDeclaredField("REMAPPER"); | |
| //noinspection unchecked | |
| remapper = (Function<List<Path>, List<Path>>) remapperField.get(null); | |
| } catch (Exception e) { | |
| remapper = null; | |
| } | |
| REMAPPER = remapper; | |
| } | |
| public RemappedBukkitLibraryManager(Plugin plugin) { | |
| super(plugin); | |
| } | |
| public RemappedBukkitLibraryManager(Plugin plugin, String directoryName) { | |
| super(plugin, directoryName); | |
| } | |
| private Path remap(Path file) { | |
| return REMAPPER != null ? REMAPPER.apply(Collections.singletonList(file)).get(0) : file; | |
| } | |
| // This method's only purpose is to add the "paperweight-mappings-namespace" attribute to the MANIFEST.MF file of the library | |
| // So that it can be remapped by Paper's PluginRemapper | |
| // Thanks Copilot for this monstrosity of a method that solves the problem | |
| private void modifyManifest(Path file, Path modifiedFile) { | |
| try { | |
| Path tempJarPath = Files.createTempFile("temp-", ".jar"); | |
| try (JarFile jarFile = new JarFile(file.toFile()); | |
| JarOutputStream tempJarOutputStream = new JarOutputStream(Files.newOutputStream(tempJarPath))) { | |
| // Copy existing entries | |
| Enumeration<JarEntry> entries = jarFile.entries(); | |
| while (entries.hasMoreElements()) { | |
| JarEntry entry = entries.nextElement(); | |
| if (JarFile.MANIFEST_NAME.equals(entry.getName())) { | |
| continue; // Skip the existing MANIFEST.MF | |
| } | |
| try (InputStream entryInputStream = jarFile.getInputStream(entry)) { | |
| tempJarOutputStream.putNextEntry(new JarEntry(entry.getName())); | |
| byte[] buffer = new byte[1024]; | |
| int bytesRead; | |
| while ((bytesRead = entryInputStream.read(buffer)) != -1) { | |
| tempJarOutputStream.write(buffer, 0, bytesRead); | |
| } | |
| tempJarOutputStream.closeEntry(); | |
| } | |
| } | |
| // Modify the MANIFEST.MF | |
| Manifest manifest = jarFile.getManifest(); | |
| if (manifest == null) { | |
| manifest = new Manifest(); | |
| } | |
| manifest.getMainAttributes().putValue("paperweight-mappings-namespace", "spigot"); | |
| // Write the modified MANIFEST.MF | |
| tempJarOutputStream.putNextEntry(new JarEntry(JarFile.MANIFEST_NAME)); | |
| manifest.write(tempJarOutputStream); | |
| tempJarOutputStream.closeEntry(); | |
| } | |
| Files.move(tempJarPath, modifiedFile, StandardCopyOption.REPLACE_EXISTING); | |
| } catch (IOException e) { | |
| throw new UncheckedIOException(e); | |
| } | |
| } | |
| public void remapAndLoadLibrary(Library library) { | |
| Path path = saveDirectory.resolve(library.getPath()); | |
| Path parent = path.getParent(); | |
| String name = path.getFileName().toString(); | |
| name = name.substring(0, name.lastIndexOf('.')); | |
| boolean downloaded = false; | |
| if (!Files.exists(path)) { | |
| downloadLibrary(library); | |
| downloaded = true; | |
| } | |
| Path modifiedPath = parent.resolve(name + "-modified.jar"); | |
| if (downloaded || !Files.exists(modifiedPath)) { | |
| modifyManifest(path, modifiedPath); | |
| } | |
| Path remappedPath = remap(modifiedPath); | |
| if (library.isIsolatedLoad()) { | |
| addToIsolatedClasspath(library, remappedPath); | |
| } else { | |
| addToClasspath(remappedPath); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import net.byteflux.libby.Library; | |
| import org.bukkit.plugin.java.JavaPlugin; | |
| public final class TestPlugin extends JavaPlugin { | |
| @Override | |
| public void onEnable() { | |
| RemappedBukkitLibraryManager libraryManager = new RemappedBukkitLibraryManager(this); | |
| Library lib = Library.builder() | |
| .groupId("net{}wesjd") | |
| .artifactId("anvilgui") | |
| .version("1.10.5-SNAPSHOT") | |
| .repository("https://repo.codemc.io/repository/maven-public/") | |
| .build(); | |
| libraryManager.remapAndLoadLibrary(lib); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment