Fix plugin loading exception
This commit is contained in:
parent
9f6ea9d3d4
commit
228c508df0
@ -0,0 +1,160 @@
|
||||
package org.patchbukkit.loader;
|
||||
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import io.papermc.paper.plugin.provider.classloader.ConfiguredPluginClassLoader;
|
||||
import io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import org.bukkit.plugin.InvalidDescriptionException;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class PatchBukkitPluginClassLoader
|
||||
extends URLClassLoader
|
||||
implements ConfiguredPluginClassLoader
|
||||
{
|
||||
|
||||
private final PluginDescriptionFile description;
|
||||
private final File dataFolder;
|
||||
private final File file;
|
||||
private JavaPlugin plugin;
|
||||
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public PatchBukkitPluginClassLoader(ClassLoader parent, File file)
|
||||
throws MalformedURLException, InvalidDescriptionException {
|
||||
super(new URL[] { file.toURI().toURL() }, parent);
|
||||
this.file = file;
|
||||
this.description = loadDescription(file);
|
||||
this.dataFolder = new File(file.getParentFile(), description.getName());
|
||||
}
|
||||
|
||||
private static PluginDescriptionFile loadDescription(File file)
|
||||
throws InvalidDescriptionException {
|
||||
try (JarFile jar = new JarFile(file)) {
|
||||
JarEntry entry = jar.getJarEntry("paper-plugin.yml");
|
||||
if (entry == null) {
|
||||
entry = jar.getJarEntry("plugin.yml");
|
||||
}
|
||||
if (entry == null) {
|
||||
throw new InvalidDescriptionException(
|
||||
"Jar does not contain plugin.yml"
|
||||
);
|
||||
}
|
||||
try (InputStream stream = jar.getInputStream(entry)) {
|
||||
return new PluginDescriptionFile(stream);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidDescriptionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Child-first class loading: try to load from plugin JAR before delegating to parent.
|
||||
* This is critical for plugin classes to be loaded by this classloader.
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
synchronized (getClassLoadingLock(name)) {
|
||||
// First, check if already loaded
|
||||
Class<?> c = findLoadedClass(name);
|
||||
|
||||
if (c == null) {
|
||||
// For plugin-specific classes, try to load from JAR first (child-first)
|
||||
// For JDK and server classes, delegate to parent
|
||||
if (
|
||||
!name.startsWith("java.") &&
|
||||
!name.startsWith("jdk.") &&
|
||||
!name.startsWith("sun.") &&
|
||||
!name.startsWith("javax.")
|
||||
) {
|
||||
try {
|
||||
// Try to find in plugin JAR first
|
||||
c = findClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Not in JAR, delegate to parent
|
||||
}
|
||||
}
|
||||
|
||||
// If not found in JAR (or is a system class), delegate to parent
|
||||
if (c == null) {
|
||||
c = getParent().loadClass(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginMeta getConfiguration() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(
|
||||
String name,
|
||||
boolean resolve,
|
||||
boolean checkGlobal,
|
||||
boolean checkLibraries
|
||||
) throws ClassNotFoundException {
|
||||
return loadClass(name, resolve);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
if (!dataFolder.exists()) {
|
||||
dataFolder.mkdirs();
|
||||
}
|
||||
plugin.init(
|
||||
org.bukkit.Bukkit.getServer(),
|
||||
description,
|
||||
dataFolder,
|
||||
file,
|
||||
this,
|
||||
description,
|
||||
com.destroystokyo.paper.utils.PaperPluginLogger.getLogger(
|
||||
description
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JavaPlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PluginClassLoaderGroup getGroup() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public PluginDescriptionFile getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public File getDataFolder() {
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
@ -4,16 +4,32 @@ import io.papermc.paper.plugin.provider.util.ProviderUtil;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class PluginLoader {
|
||||
|
||||
public JavaPlugin createPlugin(String mainClass) {
|
||||
private static final Logger LOGGER = Logger.getLogger("PatchBukkit");
|
||||
|
||||
public static JavaPlugin createPlugin(String jarPath, String mainClass) {
|
||||
try {
|
||||
File jarFile = new File(jarPath);
|
||||
if (!jarFile.exists()) {
|
||||
LOGGER.severe("Plugin file does not exist: " + jarPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
PatchBukkitPluginClassLoader classLoader =
|
||||
new PatchBukkitPluginClassLoader(
|
||||
PluginLoader.class.getClassLoader(),
|
||||
jarFile
|
||||
);
|
||||
|
||||
return ProviderUtil.loadClass(
|
||||
mainClass,
|
||||
JavaPlugin.class,
|
||||
this.getClass().getClassLoader()
|
||||
classLoader
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use j4rs::{ClasspathEntry, InvocationArg, Jvm, JvmBuilder};
|
||||
use j4rs::{InvocationArg, Jvm, JvmBuilder};
|
||||
|
||||
pub fn initialize_jvm(
|
||||
classpath_entries: Vec<ClasspathEntry>,
|
||||
j4rs_folder: &PathBuf,
|
||||
) -> Result<Jvm, String> {
|
||||
pub fn initialize_jvm(j4rs_folder: &PathBuf) -> Result<Jvm, String> {
|
||||
let jvm = JvmBuilder::new()
|
||||
.classpath_entries(classpath_entries)
|
||||
.with_base_path(j4rs_folder)
|
||||
.build()
|
||||
.map_err(|err| format!("JVM failed to init: {:?}", err))?;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use j4rs::ClasspathEntry;
|
||||
use pumpkin::plugin::Context;
|
||||
use pumpkin_api_macros::{plugin_impl, plugin_method};
|
||||
|
||||
@ -60,17 +59,13 @@ async fn on_load_inner(_plugin: &mut MyPlugin, server: Arc<Context>) -> Result<(
|
||||
}
|
||||
}
|
||||
}
|
||||
let classpath_entries = jar_paths
|
||||
.iter()
|
||||
.map(|entry| ClasspathEntry::new(entry))
|
||||
.collect();
|
||||
|
||||
// Manage embedded resources
|
||||
cleanup_stale_files(&dirs.j4rs);
|
||||
sync_embedded_resources(&dirs.j4rs)?;
|
||||
|
||||
// Initialize JVM and PatchBukkit server
|
||||
let jvm = initialize_jvm(classpath_entries, &dirs.j4rs)?;
|
||||
let jvm = initialize_jvm(&dirs.j4rs)?;
|
||||
setup_patchbukkit_server(&jvm)?;
|
||||
|
||||
plugin_manager
|
||||
|
||||
@ -158,7 +158,10 @@ impl PluginManager {
|
||||
let result = jvm.invoke(
|
||||
&loader,
|
||||
"createPlugin",
|
||||
&[InvocationArg::try_from(&plugin.main_class)?],
|
||||
&[
|
||||
InvocationArg::try_from(&plugin.path.to_string_lossy().to_string())?,
|
||||
InvocationArg::try_from(&plugin.main_class)?,
|
||||
],
|
||||
);
|
||||
|
||||
match result {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user