Initial support update for Bukkit4fabric mod (Fabric)

This commit is contained in:
Irmo van den Berge committed 2020-10-16 22:47:00 +02:00
1 parent fb0c2663f6
commit 23eaed2e49
3 files changed
+177 -9

No files matched your search

@@ -84,6 +84,7 @@ public class CommonBootstrap {
// Always Spigot server
CommonServer server = new SpigotServer();
server.init();
initServerResolvers(server);
server.postInit();
_commonServer = server;
} else {
@@ -93,6 +94,7 @@ public class CommonBootstrap {
servers.add(new MagmaServer());
servers.add(new ArclightServer());
servers.add(new CatServerServer());
servers.add(new Bukkit4FabricServer());
servers.add(new PurpurServer());
servers.add(new SpigotServer());
servers.add(new SportBukkitServer());
@@ -103,6 +105,7 @@ public class CommonBootstrap {
for (CommonServer server : servers) {
try {
if (server.init()) {
initServerResolvers(server);
server.postInit();
_commonServer = server;
break;
@@ -212,12 +215,11 @@ public class CommonBootstrap {
}
/**
* Initializes the type, field and method resolvers for a server, so that such information
* can be obtained at runtime.
* Registers any resolvers used by the current server handler
*
* @param server
*/
private static void initResolvers(CommonServer server) {
private static void initServerResolvers(CommonServer server) {
// Register server to handle field, method and class resolving
if (server instanceof ClassPathResolver) {
Resolver.registerClassResolver((ClassPathResolver) server);
@@ -234,7 +236,15 @@ public class CommonBootstrap {
if (server instanceof CompiledMethodNameResolver) {
Resolver.registerCompiledMethodResolver((CompiledMethodNameResolver) server);
}
}
/**
* Initializes the type, field and method resolvers for a server, so that such information
* can be obtained at runtime.
*
* @param server
*/
private static void initResolvers(CommonServer server) {
// Enum Gamemode not available in package space on <= MC 1.9; we must proxy it
if (Resolver.loadClass("net.minecraft.server.EnumGamemode", false) == null) {
final String eg_path = Resolver.resolveClassPath("net.minecraft.server.EnumGamemode");
@@ -0,0 +1,142 @@
package com.bergerkiller.bukkit.common.server;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import com.bergerkiller.mountiplex.reflection.declarations.Template;
import com.bergerkiller.mountiplex.reflection.resolver.FieldNameResolver;
import com.bergerkiller.mountiplex.reflection.resolver.MethodNameResolver;
/**
* Fabric server support, that uses the Bukkit4Fabric mod for paper/spigot/bukkit support.<br>
* <br>
* https://github.com/BukkitFabric/bukkit4fabric/
*/
public class Bukkit4FabricServer extends SpigotServer implements FieldNameResolver, MethodNameResolver {
private ReflectionRemapperClass reflectionRemapper = null;
@Override
public boolean init() {
if (!super.init()) {
return false;
}
// Check Bukkit4fabric mod exists, we expect this Class to exist
try {
Class.forName("com.javazilla.bukkitfabric.BukkitFabricMod");
} catch (Throwable t) {
return false;
}
// Make sure RemappingUtils exists, this initializes the RemappingUtilsHandle using the above initialized declaration
reflectionRemapper = Template.Class.create(ReflectionRemapperClass.class);
if (!reflectionRemapper.isAvailable()) {
return false;
}
// Force initialization to avoid late catastrophic failing
reflectionRemapper.forceInitialization();
return true;
}
@Override
public String getServerName() {
return "Fabric (Bukkit4fabric)";
}
@Override
public Collection<String> getLoadableWorlds() {
return ForgeSupport.getLoadableWorlds();
}
@Override
public boolean isLoadableWorld(String worldName) {
return ForgeSupport.isLoadableWorld(worldName);
}
@Override
public File getWorldRegionFolder(String worldName) {
return ForgeSupport.getWorldRegionFolder(worldName);
}
@Override
public File getWorldFolder(String worldName) {
return ForgeSupport.getWorldFolder(worldName);
}
@Override
public String resolveClassPath(String path) {
// Replaces path with proper net.minecraft.server.v1_1_1 path
path = super.resolveClassPath(path);
// Ask Magma what the actual class name is on Forge
path = reflectionRemapper.mapClassName(path);
return path;
}
@Override
public boolean canLoadClassPath(String classPath) {
// The .class data at this path contains obfuscated type information
// These obfuscated names are deobufscated at runtime
// This difference causes compiler errors at runtime, so instead of
// loading the .class files, inspect the signatures using reflection.
if (classPath.startsWith("org.bukkit.craftbukkit.")) {
return false;
}
return true;
}
@Override
public String resolveMethodName(Class<?> type, String methodName, Class<?>[] params) {
try {
//TODO: Params???
Method method = reflectionRemapper.getDeclaredMethodByName(type, methodName);
if (method != null) {
return method.getName();
}
} catch (Throwable t) {}
return methodName;
}
@Override
public String resolveFieldName(Class<?> type, String fieldName) {
try {
//TODO: Params???
Field field = reflectionRemapper.getDeclaredFieldByName(type, fieldName);
if (field != null) {
return field.getName();
}
} catch (Throwable t) {}
return fieldName;
}
@Override
public void addVariables(Map<String, String> variables) {
super.addVariables(variables);
variables.put("fabric", "bukkit4fabric");
variables.put("forge_nms_obfuscated", "true");
}
@Template.Optional
@Template.InstanceType("com.javazilla.bukkitfabric.nms.ReflectionRemapper")
public static abstract class ReflectionRemapperClass extends Template.Class<Template.Handle> {
@Template.Generated("public static String mapClassName(String className)")
public abstract String mapClassName(String className);
@Template.Generated("public static java.lang.reflect.Method getDeclaredMethodByName(Class<?> calling, String f)")
public abstract Method getDeclaredMethodByName(Class<?> type, String name);
@Template.Generated("public static java.lang.reflect.Field getDeclaredFieldByName(Class<?> calling, String f)")
public abstract Field getDeclaredFieldByName(Class<?> type, String fieldName);
}
}
@@ -4,8 +4,11 @@ import com.bergerkiller.bukkit.common.Logging;
import com.bergerkiller.bukkit.common.utils.StringUtil;
import com.bergerkiller.mountiplex.reflection.ClassTemplate;
import com.bergerkiller.mountiplex.reflection.resolver.ClassPathResolver;
import com.bergerkiller.mountiplex.reflection.resolver.Resolver;
import com.bergerkiller.mountiplex.reflection.util.asm.ASMUtil;
import com.bergerkiller.mountiplex.reflection.util.asm.MPLType;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
@@ -73,18 +76,18 @@ public class CraftBukkitServer extends CommonServerBase implements ClassPathReso
public void postInit() {
try {
// Find getVersion() method using reflection
Class<?> minecraftServerType = Class.forName(NMS_ROOT_VERSIONED + ".MinecraftServer", false, this.getClass().getClassLoader());
java.lang.reflect.Method getVersionMethod = minecraftServerType.getMethod("getVersion");
Class<?> minecraftServerType = loadClass(NMS_ROOT_VERSIONED + ".MinecraftServer");
java.lang.reflect.Method getVersionMethod = getDeclaredMethod(minecraftServerType, "getVersion");
// This is easy when the server is already initialized
if (Bukkit.getServer() != null) {
// Obtain MinecraftServer instance from server
Class<?> server = Class.forName(CB_ROOT_VERSIONED + ".CraftServer");
Class<?> server = loadClass(CB_ROOT_VERSIONED + ".CraftServer");
// Standard CraftServer::getServer()
Object minecraftServerInstance;
try {
java.lang.reflect.Method getServerMethod = server.getDeclaredMethod("getServer");
java.lang.reflect.Method getServerMethod = getDeclaredMethod(server, "getServer");
minecraftServerInstance = getServerMethod.invoke(Bukkit.getServer());
MC_VERSION = (String) getVersionMethod.invoke(minecraftServerInstance);
return;
@@ -99,10 +102,10 @@ public class CraftBukkitServer extends CommonServerBase implements ClassPathReso
try {
Object gameVersion;
try {
Class<?> minecraftVersionClass = Class.forName(NMS_ROOT_VERSIONED + ".MinecraftVersion");
Class<?> minecraftVersionClass = loadClass(NMS_ROOT_VERSIONED + ".MinecraftVersion");
gameVersion = minecraftVersionClass.getDeclaredMethod("a").invoke(null);
} catch (ClassNotFoundException | NoSuchMethodException ex) {
Class<?> sharedConstantsClass = Class.forName(NMS_ROOT_VERSIONED + ".SharedConstants");
Class<?> sharedConstantsClass = loadClass(NMS_ROOT_VERSIONED + ".SharedConstants");
gameVersion = sharedConstantsClass.getDeclaredMethod("a").invoke(null);
Logging.LOGGER.warning("Failed to find Minecraft Version using MinecraftVersion.class, used SharedConstants instead");
}
@@ -143,6 +146,19 @@ public class CraftBukkitServer extends CommonServerBase implements ClassPathReso
return path;
}
private Method getDeclaredMethod(Class<?> declaringClass, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
methodName = Resolver.resolveMethodName(declaringClass, methodName, parameterTypes);
return MPLType.getDeclaredMethod(declaringClass, methodName, parameterTypes);
}
private Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> type = Resolver.loadClass(name, false);
if (type == null) {
throw new ClassNotFoundException("Failed to load class " + name);
}
return type;
}
@Override
public String getMinecraftVersion() {
return MC_VERSION;