Find plugin instance when loaded through PaperPluginClassLoader

This commit is contained in:
NichtStudioCode 2023-06-12 20:19:21 +02:00
parent 38cc1d57bd
commit 1d276aa356
3 changed files with 65 additions and 42 deletions

@ -17,10 +17,12 @@ public class ReflectionRegistry {
// Classes // Classes
public static final Class<?> PLUGIN_CLASS_LOADER_CLASS = getBukkitClass("plugin.java.PluginClassLoader"); public static final Class<?> PLUGIN_CLASS_LOADER_CLASS = getBukkitClass("plugin.java.PluginClassLoader");
public static final Class<?> PAPER_PLUGIN_CLASS_LOADER_CLASS = getClassOrNull("io.papermc.paper.plugin.entrypoint.classloader.PaperPluginClassLoader");
public static final Class<?> CB_CRAFT_META_SKULL_CLASS = getCBClass("inventory.CraftMetaSkull"); public static final Class<?> CB_CRAFT_META_SKULL_CLASS = getCBClass("inventory.CraftMetaSkull");
public static final Class<?> CB_CRAFT_META_ITEM_CLASS = getCBClass("inventory.CraftMetaItem"); public static final Class<?> CB_CRAFT_META_ITEM_CLASS = getCBClass("inventory.CraftMetaItem");
// Methods // Methods
public static final Method PAPER_PLUGIN_CLASS_LOADER_GET_LOADED_JAVA_PLUGIN_METHOD;
public static final Method CB_CRAFT_META_SKULL_SET_PROFILE_METHOD = getMethod(CB_CRAFT_META_SKULL_CLASS, true, "setProfile", GameProfile.class); public static final Method CB_CRAFT_META_SKULL_SET_PROFILE_METHOD = getMethod(CB_CRAFT_META_SKULL_CLASS, true, "setProfile", GameProfile.class);
// Fields // Fields
@ -28,4 +30,10 @@ public class ReflectionRegistry {
public static final Field CB_CRAFT_META_ITEM_DISPLAY_NAME_FIELD = getField(CB_CRAFT_META_ITEM_CLASS, true, "displayName"); public static final Field CB_CRAFT_META_ITEM_DISPLAY_NAME_FIELD = getField(CB_CRAFT_META_ITEM_CLASS, true, "displayName");
public static final Field CB_CRAFT_META_ITEM_LORE_FIELD = getField(CB_CRAFT_META_ITEM_CLASS, true, "lore"); public static final Field CB_CRAFT_META_ITEM_LORE_FIELD = getField(CB_CRAFT_META_ITEM_CLASS, true, "lore");
static {
Method getPlugin = getMethodOrNull(PAPER_PLUGIN_CLASS_LOADER_CLASS, false, "getLoadedJavaPlugin");
if (getPlugin == null) getPlugin = getMethodOrNull(PAPER_PLUGIN_CLASS_LOADER_CLASS, false, "getPlugin");
PAPER_PLUGIN_CLASS_LOADER_GET_LOADED_JAVA_PLUGIN_METHOD = getPlugin;
}
} }

@ -5,7 +5,6 @@ import xyz.xenondevs.inventoryaccess.version.InventoryAccessRevision;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@SuppressWarnings({"unchecked", "unused"}) @SuppressWarnings({"unchecked", "unused"})
@ -26,11 +25,9 @@ public class ReflectionUtils {
public static <T> Class<T> getImplClass(String path) { public static <T> Class<T> getImplClass(String path) {
try { try {
return (Class<T>) Class.forName("xyz.xenondevs.inventoryaccess." + InventoryAccessRevision.REQUIRED_REVISION.getPackageName() + "." + path); return (Class<T>) Class.forName("xyz.xenondevs.inventoryaccess." + InventoryAccessRevision.REQUIRED_REVISION.getPackageName() + "." + path);
} catch (ClassNotFoundException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
public static <T> Class<T> getBukkitClass(String path) { public static <T> Class<T> getBukkitClass(String path) {
@ -44,11 +41,17 @@ public class ReflectionUtils {
public static <T> Class<T> getClass(String path) { public static <T> Class<T> getClass(String path) {
try { try {
return (Class<T>) Class.forName(path); return (Class<T>) Class.forName(path);
} catch (ClassNotFoundException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
}
}
public static <T> Class<T> getClassOrNull(String path) {
try {
return (Class<T>) Class.forName(path);
} catch (Throwable t) {
return null;
} }
return null;
} }
public static Field getField(Class<?> clazz, boolean declared, String name) { public static Field getField(Class<?> clazz, boolean declared, String name) {
@ -56,11 +59,9 @@ public class ReflectionUtils {
Field field = declared ? clazz.getDeclaredField(name) : clazz.getField(name); Field field = declared ? clazz.getDeclaredField(name) : clazz.getField(name);
if (declared) field.setAccessible(true); if (declared) field.setAccessible(true);
return field; return field;
} catch (NoSuchFieldException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
public static <T> Constructor<T> getConstructor(Class<T> clazz, boolean declared, Class<?>... parameterTypes) { public static <T> Constructor<T> getConstructor(Class<T> clazz, boolean declared, Class<?>... parameterTypes) {
@ -68,31 +69,25 @@ public class ReflectionUtils {
Constructor<T> constructor = declared ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getConstructor(parameterTypes); Constructor<T> constructor = declared ? clazz.getDeclaredConstructor(parameterTypes) : clazz.getConstructor(parameterTypes);
if (declared) constructor.setAccessible(true); if (declared) constructor.setAccessible(true);
return constructor; return constructor;
} catch (NoSuchMethodException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
public static <T> T constructEmpty(Class<?> clazz) { public static <T> T constructEmpty(Class<?> clazz) {
try { try {
return (T) getConstructor(clazz, true).newInstance(); return (T) getConstructor(clazz, true).newInstance();
} catch (ReflectiveOperationException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
public static <T> T construct(Constructor<T> constructor, Object... args) { public static <T> T construct(Constructor<T> constructor, Object... args) {
try { try {
return constructor.newInstance(args); return constructor.newInstance(args);
} catch (ReflectiveOperationException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
public static Method getMethod(Class<?> clazz, boolean declared, String name, Class<?>... parameterTypes) { public static Method getMethod(Class<?> clazz, boolean declared, String name, Class<?>... parameterTypes) {
@ -100,28 +95,34 @@ public class ReflectionUtils {
Method method = declared ? clazz.getDeclaredMethod(name, parameterTypes) : clazz.getMethod(name, parameterTypes); Method method = declared ? clazz.getDeclaredMethod(name, parameterTypes) : clazz.getMethod(name, parameterTypes);
if (declared) method.setAccessible(true); if (declared) method.setAccessible(true);
return method; return method;
} catch (NoSuchMethodException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
}
}
public static Method getMethodOrNull(Class<?> clazz, boolean declared, String name, Class<?>... parameterTypes) {
try {
Method method = declared ? clazz.getDeclaredMethod(name, parameterTypes) : clazz.getMethod(name, parameterTypes);
if (declared) method.setAccessible(true);
return method;
} catch (Throwable t) {
return null;
} }
return null;
} }
public static <T> T invokeMethod(Method method, Object obj, Object... args) { public static <T> T invokeMethod(Method method, Object obj, Object... args) {
try { try {
return (T) method.invoke(obj, args); return (T) method.invoke(obj, args);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
public static void setFieldValue(Field field, Object obj, Object value) { public static void setFieldValue(Field field, Object obj, Object value) {
try { try {
field.set(obj, value); field.set(obj, value);
} catch (IllegalAccessException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
} }
@ -129,11 +130,9 @@ public class ReflectionUtils {
public static <T> T getFieldValue(Field field, Object obj) { public static <T> T getFieldValue(Field field, Object obj) {
try { try {
return (T) field.get(obj); return (T) field.get(obj);
} catch (IllegalAccessException e) { } catch (Throwable t) {
e.printStackTrace(); throw new RuntimeException(t);
} }
return null;
} }
} }

@ -6,12 +6,15 @@ import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.util.ReflectionRegistry;
import xyz.xenondevs.inventoryaccess.util.ReflectionUtils; import xyz.xenondevs.inventoryaccess.util.ReflectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
import static xyz.xenondevs.inventoryaccess.util.ReflectionRegistry.PAPER_PLUGIN_CLASS_LOADER_GET_LOADED_JAVA_PLUGIN_METHOD;
import static xyz.xenondevs.inventoryaccess.util.ReflectionRegistry.PLUGIN_CLASS_LOADER_PLUGIN_FIELD; import static xyz.xenondevs.inventoryaccess.util.ReflectionRegistry.PLUGIN_CLASS_LOADER_PLUGIN_FIELD;
public class InvUI implements Listener { public class InvUI implements Listener {
@ -30,14 +33,27 @@ public class InvUI implements Listener {
public @NotNull Plugin getPlugin() { public @NotNull Plugin getPlugin() {
if (plugin == null) { if (plugin == null) {
// get plugin from class loader if it wasn't set manually plugin = tryFindPlugin();
plugin = ReflectionUtils.getFieldValue(PLUGIN_CLASS_LOADER_PLUGIN_FIELD, getClass().getClassLoader());
Bukkit.getPluginManager().registerEvents(this, plugin); if (plugin == null)
throw new IllegalStateException("Plugin is not set. Set it using InvUI.getInstance().setPlugin(plugin);");
} }
return plugin; return plugin;
} }
private @Nullable Plugin tryFindPlugin() {
ClassLoader loader = getClass().getClassLoader();
if (ReflectionRegistry.PLUGIN_CLASS_LOADER_CLASS.isInstance(loader)) {
return ReflectionUtils.getFieldValue(PLUGIN_CLASS_LOADER_PLUGIN_FIELD, loader);
} else if (ReflectionRegistry.PAPER_PLUGIN_CLASS_LOADER_CLASS.isInstance(loader)) {
return ReflectionUtils.invokeMethod(PAPER_PLUGIN_CLASS_LOADER_GET_LOADED_JAVA_PLUGIN_METHOD, loader);
}
return null;
}
public void setPlugin(@NotNull Plugin plugin) { public void setPlugin(@NotNull Plugin plugin) {
if (this.plugin != null) if (this.plugin != null)
throw new IllegalStateException("Plugin is already set"); throw new IllegalStateException("Plugin is already set");