Skip to content

Commit

Permalink
Take relocation of crafbukkit.util.ApiVersion class into account.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Boerman committed Dec 26, 2024
1 parent abbbd50 commit 27c518f
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ object ExamplePlugin
getCommand("home").setExecutor(HomeExecutor)

listConfigs()
checkMaterials()
checkMaterials() // TODO why does this test now fail? Grrr....
//SerializationMethodsTest.test()
//ScalaTypesSerializationTest.test()
}
Expand All @@ -74,6 +74,8 @@ object ExamplePlugin
}

private def checkMaterials(): Unit = {
// TODO fix bytecode transformation to make this test pass.

val console = getServer.getConsoleSender
console.sendMessage(s"${ChatColor.YELLOW}Test that a ScalaPlugin does not find both legacy and modern materials")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package xyz.janboerman.scalaloader.compat;

import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.UnsafeValues;
import org.bukkit.plugin.PluginDescriptionFile;
Expand Down Expand Up @@ -72,32 +73,36 @@ public static Platform detect(Server server) {

public static class CraftBukkitPlatform extends Platform {

private static final Class<?> API_VERSION_CLASS;
static {
Class<?> apiVersionClass;
try {
apiVersionClass = Class.forName("org.bukkit.craftbukkit.util.ApiVersion");
} catch (ClassNotFoundException e) {
apiVersionClass = null;
}
API_VERSION_CLASS = apiVersionClass;
}

private CraftBukkitPlatform() {}

private MethodHandle commodoreConvert = null;
private boolean attempted = false;
private boolean attemptedToFindCommodoreConvert = false;
private Class<?> apiVersionClass;
private boolean attemptedToFindApiVersion = false;

private Class<?> getApiVersionClass() {
if (!attemptedToFindApiVersion) {
attemptedToFindApiVersion = true;
try {
apiVersionClass = Class.forName(getPackageName(Bukkit.getServer().getClass()) + ".util.ApiVersion");
} catch (ClassNotFoundException ignored) {
}
}
return apiVersionClass;
}

// MC 1.20.5+ method signature of Commodore#convert:
public <ScalaPluginClassLoader extends ClassLoader & IScalaPluginClassLoader> byte[] transformNative(Server craftServer, byte[] classBytes, ScalaPluginClassLoader pluginClassLoader) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();

if (commodoreConvert == null) {
attempted = true;
attemptedToFindCommodoreConvert = true;
try {
// public static byte[] convert(byte[] b, final String pluginName, final ApiVersion pluginVersion, final Set<String> activeCompatibilities)
Class<?> commodoreClass = Class.forName(getPackageName(craftServer.getClass()) + ".util.Commodore");
String methodName = "convert";
MethodType methodType = MethodType.methodType(byte[].class,
new Class<?>[] { byte[].class, String.class, API_VERSION_CLASS, Set.class });
new Class<?>[] { byte[].class, String.class, getApiVersionClass(), Set.class });
commodoreConvert = lookup.findStatic(commodoreClass, methodName, methodType);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException ignored) {
//impossible
Expand All @@ -107,7 +112,8 @@ public <ScalaPluginClassLoader extends ClassLoader & IScalaPluginClassLoader> by
if (commodoreConvert != null) {
String pluginName = getPluginName(pluginClassLoader);
try {
MethodHandle getOrCreateVersion = lookup.findStatic(API_VERSION_CLASS, "getOrCreateVersion", MethodType.methodType(API_VERSION_CLASS, String.class));
Class<?> apiVersionClass = getApiVersionClass();
MethodHandle getOrCreateVersion = lookup.findStatic(apiVersionClass, "getOrCreateVersion", MethodType.methodType(apiVersionClass, String.class));
Object apiVersion = getOrCreateVersion.invoke(pluginClassLoader.getApiVersion().getVersionString());

Set activeCompatibilities = Collections.emptySet();
Expand All @@ -125,9 +131,10 @@ public <ScalaPluginClassLoader extends ClassLoader & IScalaPluginClassLoader> by
return classBytes;
}

// MC 1.13-1.20.4 method signature of Commodore#convert:
public byte[] transformNative(Server craftServer, byte[] classBytes, boolean modern) throws Throwable {
if (!attempted) {
attempted = true;
if (!attemptedToFindCommodoreConvert) {
attemptedToFindCommodoreConvert = true;
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
// public static byte[] convert(byte[] b, boolean isModern)
Expand All @@ -150,7 +157,7 @@ public byte[] transformNative(Server craftServer, byte[] classBytes, boolean mod

@Override
public <ScalaPluginClassLoader extends ClassLoader & IScalaPluginClassLoader> byte[] transform(String jarEntryPath, byte[] classBytes, ScalaPluginClassLoader pluginClassLoader) throws Throwable {
if (API_VERSION_CLASS != null) {
if (getApiVersionClass() != null) {
return transformNative(pluginClassLoader.getServer(), classBytes, pluginClassLoader);
} else {
return transformNative(pluginClassLoader.getServer(), classBytes, pluginClassLoader.getApiVersion() != ApiVersion.LEGACY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@
import xyz.janboerman.scalaloader.compat.Migration;
import xyz.janboerman.scalaloader.compat.Platform;
import xyz.janboerman.scalaloader.paper.plugin.ScalaPluginMeta;
import xyz.janboerman.scalaloader.paper.plugin.ScalaPluginClassLoader;
import xyz.janboerman.scalaloader.paper.transform.MainClassBootstrapTransformer;
import xyz.janboerman.scalaloader.paper.transform.MainClassCallerMigrator;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -72,6 +70,8 @@ public Class<?> findClass(final String className) throws ClassNotFoundException
//transform the bytecode
//1. Bukkit's own migrations
try {
// TODO I don't think this will work still for newer versions of CraftBukkit.
// TODO check this, and fix this if it's broken.
byteCode = Platform.CRAFTBUKKIT.transformNative(Bukkit.getServer(), byteCode, modern); //we can assume Platform.CRAFTBUKKIT because we are running on Paper (which is a fork of CraftBukkit).
} catch (Throwable e) {
Bukkit.getLogger().log(Level.SEVERE, "Server could not transform bytecode for class: " + className + ". This is a bug in " + Bukkit.getUnsafe().getClass().getName() + "#processClass", e);
Expand Down

0 comments on commit 27c518f

Please sign in to comment.