Bypass PaperReflectionHolder that try to understand our Mojang mapped reflection call as Spigot mapped

This commit is contained in:
Marc Baloup 2024-06-26 23:10:13 +02:00
parent ed0db5391d
commit 640b255e1d
3 changed files with 59 additions and 1 deletions

View File

@ -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.QueuedChangesMapLong2Object;
import fr.pandacube.lib.paper.reflect.wrapper.paper.configuration.FallbackValue_Int; 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.paper.reflect.wrapper.paper.configuration.WorldConfiguration;
import fr.pandacube.lib.reflect.ReflectionWrapperBypass;
import fr.pandacube.lib.util.ThrowableAccumulator; import fr.pandacube.lib.util.ThrowableAccumulator;
import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper; import static fr.pandacube.lib.reflect.wrapper.WrapperRegistry.initWrapper;
@ -96,6 +97,9 @@ public class PandalibPaperReflect {
return; return;
isInit = true; isInit = true;
} }
ReflectionWrapperBypass.enable();
initWrapperClasses(); initWrapperClasses();
} }

View File

@ -32,7 +32,7 @@ public class Reflect {
* @throws ClassNotFoundException if the provided class was not found. * @throws ClassNotFoundException if the provided class was not found.
*/ */
public static ReflectClass<?> ofClass(String className) throws ClassNotFoundException { public static ReflectClass<?> ofClass(String className) throws ClassNotFoundException {
return ofClass(Class.forName(className)); return ofClass(ReflectionWrapperBypass.getClass(className));
} }
/** /**

View File

@ -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.
* <p>
* 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);
}
}
}