From 640b255e1d793fc7c90d5670cc79a140d52d76e0 Mon Sep 17 00:00:00 2001 From: Marc Baloup Date: Wed, 26 Jun 2024 23:10:13 +0200 Subject: [PATCH] Bypass PaperReflectionHolder that try to understand our Mojang mapped reflection call as Spigot mapped --- .../paper/reflect/PandalibPaperReflect.java | 4 ++ .../fr/pandacube/lib/reflect/Reflect.java | 2 +- .../lib/reflect/ReflectionWrapperBypass.java | 54 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/ReflectionWrapperBypass.java diff --git a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java index 3a7f9ec..daa873f 100644 --- a/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java +++ b/pandalib-paper/src/main/java/fr/pandacube/lib/paper/reflect/PandalibPaperReflect.java @@ -75,6 +75,7 @@ import fr.pandacube.lib.paper.reflect.wrapper.paper.PaperAdventure; import fr.pandacube.lib.paper.reflect.wrapper.paper.QueuedChangesMapLong2Object; import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.FallbackValue_Int; import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.WorldConfiguration; +import fr.pandacube.lib.reflect.ReflectionWrapperBypass; import fr.pandacube.lib.util.ThrowableAccumulator; import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper; @@ -96,6 +97,9 @@ public class PandalibPaperReflect { return; isInit = true; } + + ReflectionWrapperBypass.enable(); + initWrapperClasses(); } diff --git a/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/Reflect.java b/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/Reflect.java index 432917c..1ac62f2 100644 --- a/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/Reflect.java +++ b/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/Reflect.java @@ -32,7 +32,7 @@ public class Reflect { * @throws ClassNotFoundException if the provided class was not found. */ public static ReflectClass ofClass(String className) throws ClassNotFoundException { - return ofClass(Class.forName(className)); + return ofClass(ReflectionWrapperBypass.getClass(className)); } /** diff --git a/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/ReflectionWrapperBypass.java b/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/ReflectionWrapperBypass.java new file mode 100644 index 0000000..78fdf8b --- /dev/null +++ b/pandalib-reflect/src/main/java/fr/pandacube/lib/reflect/ReflectionWrapperBypass.java @@ -0,0 +1,54 @@ +package fr.pandacube.lib.reflect; + +import fr.pandacube.lib.util.ThrowableUtil; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Utility class to provide bypass functionality when the runtime environment modify our reflection code to inject a + * wrapper that translate class and method names. + *

+ * It is the case on 1.20.6+ Paper server: Paper runtime uses Mojang mapping but their reflection wrapper assumes the plugin + * uses Spigot mapping, so tries to translate to Mojang names, but we already use the Mojang name. + */ +public class ReflectionWrapperBypass { + + private static final AtomicBoolean enabled = new AtomicBoolean(false); + + public static void enable() { + enabled.set(true); + } + + public static void disable() { + enabled.set(false); + } + + + public static Class getClass(String className) throws ClassNotFoundException { + if (!enabled.get()) { + return Class.forName(className); + } + + try { + Class c = Class.forName(className); + if (c.getName().equals(className)) // there were no translation here + return c; + } catch (ClassNotFoundException ignored) { } + + try { + return (Class) Class.class.getDeclaredMethod("forName", String.class) + .invoke(null, className); + } catch (IllegalAccessException e) { + throw new IllegalAccessError("java.lang.Class.forName(String)"); // wut? + } catch (NoSuchMethodException e) { + throw new NoSuchMethodError("java.lang.Class.forName(String)"); // wut? + } catch (InvocationTargetException e) { + if (e.getCause() instanceof ClassNotFoundException cnfe) + throw cnfe; + throw ThrowableUtil.uncheck(e.getCause(), false); + } + } + + +}