Refactor reflections and use MinecraftReflection

This commit is contained in:
Frank van der Heijden 2020-12-21 00:11:31 +01:00
parent 295eb77452
commit 8a855d6935
No known key found for this signature in database
GPG key ID: 26DA56488D314D11
34 changed files with 305 additions and 1148 deletions

View file

@ -9,7 +9,6 @@ import java.util.Map;
import net.frankheijden.serverutils.bukkit.commands.CommandPlugins; import net.frankheijden.serverutils.bukkit.commands.CommandPlugins;
import net.frankheijden.serverutils.bukkit.commands.CommandServerUtils; import net.frankheijden.serverutils.bukkit.commands.CommandServerUtils;
import net.frankheijden.serverutils.bukkit.entities.BukkitPlugin; import net.frankheijden.serverutils.bukkit.entities.BukkitPlugin;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import net.frankheijden.serverutils.bukkit.listeners.BukkitListener; import net.frankheijden.serverutils.bukkit.listeners.BukkitListener;
import net.frankheijden.serverutils.bukkit.managers.BukkitPluginManager; import net.frankheijden.serverutils.bukkit.managers.BukkitPluginManager;
import net.frankheijden.serverutils.bukkit.reflection.RCommandMap; import net.frankheijden.serverutils.bukkit.reflection.RCommandMap;
@ -46,7 +45,6 @@ public class ServerUtils extends JavaPlugin implements CommandExecutor {
ServerUtilsApp.init(this, plugin); ServerUtilsApp.init(this, plugin);
new Metrics(this, ServerUtilsApp.BSTATS_METRICS_ID); new Metrics(this, ServerUtilsApp.BSTATS_METRICS_ID);
new BukkitReflection();
this.commandManager = new PaperCommandManager(this); this.commandManager = new PaperCommandManager(this);
commandManager.registerCommand(new CommandServerUtils(), true); commandManager.registerCommand(new CommandServerUtils(), true);

View file

@ -1,6 +1,5 @@
package net.frankheijden.serverutils.bukkit.commands; package net.frankheijden.serverutils.bukkit.commands;
import static net.frankheijden.serverutils.bukkit.entities.BukkitReflection.MINOR;
import static net.frankheijden.serverutils.common.config.Messenger.sendMessage; import static net.frankheijden.serverutils.common.config.Messenger.sendMessage;
import co.aikar.commands.BaseCommand; import co.aikar.commands.BaseCommand;
@ -13,6 +12,7 @@ import co.aikar.commands.annotation.Default;
import co.aikar.commands.annotation.Dependency; import co.aikar.commands.annotation.Dependency;
import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Description;
import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Subcommand;
import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -303,7 +303,7 @@ public class CommandServerUtils extends BaseCommand {
.add("Name", plugin.getName()) .add("Name", plugin.getName())
.add("Full Name", description.getFullName()) .add("Full Name", description.getFullName())
.add("Version", description.getVersion()); .add("Version", description.getVersion());
if (MINOR >= 13) builder.add("API Version", description.getAPIVersion()); if (MinecraftReflectionVersion.MINOR >= 13) builder.add("API Version", description.getAPIVersion());
builder.add("Website", description.getWebsite()) builder.add("Website", description.getWebsite())
.add("Authors", ListBuilder.create(description.getAuthors()) .add("Authors", ListBuilder.create(description.getAuthors())
.format(listFormat) .format(listFormat)
@ -329,11 +329,13 @@ public class CommandServerUtils extends BaseCommand {
.seperator(seperator) .seperator(seperator)
.lastSeperator(lastSeperator) .lastSeperator(lastSeperator)
.toString()); .toString());
if (MINOR >= 15) builder.add("Provides", ListBuilder.create(description.getProvides()) if (MinecraftReflectionVersion.MINOR >= 15) {
builder.add("Provides", ListBuilder.create(description.getProvides())
.format(listFormat) .format(listFormat)
.seperator(seperator) .seperator(seperator)
.lastSeperator(lastSeperator) .lastSeperator(lastSeperator)
.toString()); .toString());
}
builder.sendTo(sender); builder.sendTo(sender);
Messenger.sendMessage(sender, "serverutils.plugininfo.footer"); Messenger.sendMessage(sender, "serverutils.plugininfo.footer");

View file

@ -1,29 +0,0 @@
package net.frankheijden.serverutils.bukkit.entities;
import net.frankheijden.serverutils.common.reflection.ReflectionUtils;
import net.frankheijden.serverutils.common.reflection.VersionParam;
import org.bukkit.Bukkit;
public class BukkitReflection extends ReflectionUtils {
public static String NMS;
public static int MAJOR;
public static int MINOR;
public static int PATCH;
static {
String bukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
NMS = bukkitPackage.substring(bukkitPackage.lastIndexOf('.') + 1);
String[] split = NMS.split("_");
MAJOR = Integer.parseInt(split[0].substring(1));
MINOR = Integer.parseInt(split[1]);
PATCH = Integer.parseInt(split[2].substring(1, 2));
}
@Override
public boolean isCompatible(VersionParam versionParam) {
return versionParam.min.minor <= MINOR && versionParam.min.patch <= PATCH
&& MINOR <= versionParam.max.minor && PATCH <= versionParam.max.patch;
}
}

View file

@ -2,7 +2,6 @@ package net.frankheijden.serverutils.bukkit.managers;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -150,12 +149,8 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin> {
ClassLoader loader = RJavaPlugin.getClassLoader(plugin); ClassLoader loader = RJavaPlugin.getClassLoader(plugin);
RPluginClassLoader.clearClassLoader(loader); RPluginClassLoader.clearClassLoader(loader);
addIfInstance(closeables, (Closeable) () -> { addIfInstance(closeables, (Closeable) () -> {
try {
Map<String, Class<?>> classes = RPluginClassLoader.getClasses(loader); Map<String, Class<?>> classes = RPluginClassLoader.getClasses(loader);
RJavaPluginLoader.removeClasses(getPluginLoader(getPluginFile(plugin)), classes.keySet()); RJavaPluginLoader.removeClasses(getPluginLoader(getPluginFile(plugin)), classes.keySet());
} catch (IllegalAccessException ex) {
throw new IOException(ex);
}
}); });
addIfInstance(closeables, loader); addIfInstance(closeables, loader);
addIfInstance(closeables, RJavaPlugin.clearJavaPlugin(plugin)); addIfInstance(closeables, RJavaPlugin.clearJavaPlugin(plugin));
@ -192,11 +187,7 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin> {
if (Bukkit.getPluginManager().isPluginEnabled(plugin.getName())) return Result.ALREADY_ENABLED; if (Bukkit.getPluginManager().isPluginEnabled(plugin.getName())) return Result.ALREADY_ENABLED;
Bukkit.getPluginManager().enablePlugin(plugin); Bukkit.getPluginManager().enablePlugin(plugin);
try {
RCraftServer.syncCommands(); RCraftServer.syncCommands();
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
return Bukkit.getPluginManager().isPluginEnabled(plugin.getName()) ? Result.SUCCESS : Result.ERROR; return Bukkit.getPluginManager().isPluginEnabled(plugin.getName()) ? Result.SUCCESS : Result.ERROR;
} }
@ -270,11 +261,7 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin> {
return false; return false;
}); });
try {
RCraftServer.syncCommands(); RCraftServer.syncCommands();
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
} }
/** /**
@ -372,11 +359,7 @@ public class BukkitPluginManager extends AbstractPluginManager<Plugin> {
@Override @Override
public File getPluginFile(Plugin plugin) { public File getPluginFile(Plugin plugin) {
try {
return RJavaPlugin.getFile(plugin); return RJavaPlugin.getFile(plugin);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Error retrieving current plugin file", ex);
}
} }
/** /**

View file

@ -1,34 +1,25 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getDeclaredField; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import dev.frankheijden.minecraftreflection.exceptions.MinecraftReflectionException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.SimpleCommandMap; import org.bukkit.command.SimpleCommandMap;
public class RCommandMap { public class RCommandMap {
private static Field knownCommands = null; private static final MinecraftReflection reflection = MinecraftReflection
private static Method getKnownCommands = null; .of(SimpleCommandMap.class);
static { /**
* Gets the known commands from the given command map.
* TODO: figure out which version causes method change.
*/
public static Map<String, Command> getKnownCommands(SimpleCommandMap map) {
try { try {
try { return reflection.get(map, "knownCommands");
knownCommands = getDeclaredField(SimpleCommandMap.class, "knownCommands"); } catch (MinecraftReflectionException ignored) {
} catch (NoSuchFieldException ignored) { return reflection.invoke(map, "getKnownCommands");
getKnownCommands = SimpleCommandMap.class.getDeclaredMethod("getKnownCommands");
}
} catch (Exception ex) {
ex.printStackTrace();
} }
} }
@SuppressWarnings("unchecked")
public static Map<String, Command> getKnownCommands(SimpleCommandMap map)
throws IllegalAccessException, InvocationTargetException {
return (Map<String, Command>) (knownCommands == null ? getKnownCommands.invoke(map) : knownCommands.get(map));
}
} }

View file

@ -1,24 +1,9 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf; import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getDeclaredField;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getDeclaredMethod;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.invoke;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.set;
import static net.frankheijden.serverutils.common.reflection.VersionParam.exact;
import static net.frankheijden.serverutils.common.reflection.VersionParam.max;
import static net.frankheijden.serverutils.common.reflection.VersionParam.min;
import java.io.File; import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Warning; import org.bukkit.Warning;
import org.bukkit.command.Command; import org.bukkit.command.Command;
@ -27,159 +12,117 @@ import org.bukkit.configuration.file.YamlConfiguration;
public class RCraftServer { public class RCraftServer {
private static Class<?> craftServerClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Object craftServer; .of("org.bukkit.craftbukkit.%s.CraftServer");
private static File configFile;
private static File commandsConfigFile;
private static SimpleCommandMap commandMap;
private static Map<String, Field> fields; public static MinecraftReflection getReflection() {
private static Map<String, Method> methods; return reflection;
static {
try {
craftServerClass = Class.forName(String.format("org.bukkit.craftbukkit.%s.CraftServer",
BukkitReflection.NMS));
craftServer = craftServerClass.cast(Bukkit.getServer());
commandsConfigFile = (File) getDeclaredMethod(craftServerClass,
"getCommandsConfigFile").invoke(craftServer);
configFile = (File) getDeclaredMethod(craftServerClass, "getConfigFile").invoke(craftServer);
commandMap = (SimpleCommandMap) getDeclaredField(craftServerClass, "commandMap").get(Bukkit.getServer());
fields = getAllFields(craftServerClass,
fieldOf("configuration"),
fieldOf("console"),
fieldOf("commandsConfiguration"),
fieldOf("overrideAllCommandBlockCommands"),
fieldOf("unrestrictedAdvancements", exact(12)),
fieldOf("ignoreVanillaPermissions", min(13)),
fieldOf("monsterSpawn"),
fieldOf("animalSpawn"),
fieldOf("waterAnimalSpawn"),
fieldOf("ambientSpawn"),
fieldOf("warningState"),
fieldOf("minimumAPI", min(14)),
fieldOf("printSaveWarning"),
fieldOf("chunkGCPeriod", max(12)),
fieldOf("chunkGCLoadThresh", max(12)),
fieldOf("playerList"));
methods = getAllMethods(craftServerClass,
methodOf("loadIcon"),
methodOf("syncCommands", min(13)),
methodOf("getHandle"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Object getCraftServer() {
return craftServer;
} }
public static File getConfigFile() { public static File getConfigFile() {
return configFile; return reflection.invoke(Bukkit.getServer(), "getConfigFile");
} }
/** /**
* Retrieves the options file from a key. * Retrieves the options file from a key.
* @param option The option key. * @param option The option key.
* @return The associated file. * @return The associated file.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/ */
public static File getOptionsFile(String option) throws IllegalAccessException, InvocationTargetException { public static File getOptionsFile(String option) {
Object console = getConsole(); Object options = reflection.get(getConsole(), "options");
Object options = get(RDedicatedServer.getFields(), console, "options"); return reflection.invoke(options, "valueOf", option);
return (File) invoke(ROptionSet.getMethods(), options, "valueOf", option);
} }
public static File getCommandsConfigFile() { public static File getCommandsConfigFile() {
return commandsConfigFile; return reflection.invoke(Bukkit.getServer(), "getCommandsConfigFile");
} }
public static SimpleCommandMap getCommandMap() { public static SimpleCommandMap getCommandMap() {
return commandMap; return reflection.get(Bukkit.getServer(), "commandMap");
} }
public static void syncCommands() throws InvocationTargetException, IllegalAccessException { public static void syncCommands() {
invoke(methods, craftServer, "syncCommands"); if (MinecraftReflectionVersion.MINOR >= 13) reflection.invoke(Bukkit.getServer(), "syncCommands");
} }
public static Object getConsole() throws IllegalAccessException { public static Object getConsole() {
return get(fields, craftServer, "console"); return reflection.get(Bukkit.getServer(), "console");
} }
/** /**
* Reloads the bukkit configuration. * Reloads the bukkit configuration.
* @throws ReflectiveOperationException Iff exception thrown regarding reflection.
*/ */
public static void reloadBukkitConfiguration() throws ReflectiveOperationException { public static void reloadBukkitConfiguration() {
YamlConfiguration bukkit = YamlConfiguration.loadConfiguration(getConfigFile()); YamlConfiguration bukkit = YamlConfiguration.loadConfiguration(getConfigFile());
set(fields, craftServer, "configuration", bukkit); reflection.set(Bukkit.getServer(), "configuration", bukkit);
Object console = getConsole(); RDedicatedServer.reload(getConsole());
RDedicatedServer.reload(console);
set(fields, craftServer, "monsterSpawn", bukkit.getInt("spawn-limits.monsters")); reflection.set(Bukkit.getServer(), "monsterSpawn", bukkit.getInt("spawn-limits.monsters"));
set(fields, craftServer, "animalSpawn", bukkit.getInt("spawn-limits.animals")); reflection.set(Bukkit.getServer(), "animalSpawn", bukkit.getInt("spawn-limits.animals"));
set(fields, craftServer, "waterAnimalSpawn", bukkit.getInt("spawn-limits.water-animals")); reflection.set(Bukkit.getServer(), "waterAnimalSpawn", bukkit.getInt("spawn-limits.water-animals"));
set(fields, craftServer, "ambientSpawn", bukkit.getInt("spawn-limits.ambient")); reflection.set(Bukkit.getServer(), "ambientSpawn", bukkit.getInt("spawn-limits.ambient"));
set(fields, craftServer, "warningState", reflection.set(Bukkit.getServer(), "warningState",
Warning.WarningState.value(bukkit.getString("settings.deprecated-verbose"))); Warning.WarningState.value(bukkit.getString("settings.deprecated-verbose")));
set(fields, craftServer, "minimumAPI", bukkit.getString("settings.minimum-api")); if (MinecraftReflectionVersion.isMin(14))
set(fields, craftServer, "printSaveWarning", false); reflection.set(Bukkit.getServer(), "minimumAPI", bukkit.getString("settings.minimum-api"));
reflection.set(Bukkit.getServer(), "printSaveWarning", false);
set(RDedicatedServer.getFields(), console, "autosavePeriod", bukkit.getInt("ticks-per.autosave")); reflection.set(Bukkit.getServer(), "monsterSpawn", bukkit.getInt("spawn-limits.monsters"));
reflection.set(Bukkit.getServer(), "monsterSpawn", bukkit.getInt("spawn-limits.monsters"));
set(fields, craftServer, "chunkGCPeriod", bukkit.getInt("chunk-gc.period-in-ticks")); reflection.set(Bukkit.getServer(), "monsterSpawn", bukkit.getInt("spawn-limits.monsters"));
set(fields, craftServer, "chunkGCLoadThresh", bukkit.getInt("chunk-gc.load-threshold")); if (MinecraftReflectionVersion.isMax(12)) {
reflection.set(Bukkit.getServer(), "chunkGCPeriod", bukkit.getInt("chunk-gc.period-in-ticks"));
reflection.set(Bukkit.getServer(), "chunkGCLoadThresh", bukkit.getInt("chunk-gc.load-threshold"));
} }
public static void loadIcon() throws InvocationTargetException, IllegalAccessException { RDedicatedServer.getReflection().set(getConsole(), "autosavePeriod", bukkit.getInt("ticks-per.autosave"));
invoke(methods, craftServer, "loadIcon"); }
public static void loadIcon() {
reflection.invoke(Bukkit.getServer(), "loadIcon");
} }
/** /**
* Reloads the commands.yml file. * Reloads the commands.yml file.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/ */
public static void reloadCommandsConfiguration() throws IllegalAccessException, InvocationTargetException { public static void reloadCommandsConfiguration() {
SimpleCommandMap commandMap = getCommandMap();
Map<String, Command> map = RCommandMap.getKnownCommands(commandMap); Map<String, Command> map = RCommandMap.getKnownCommands(commandMap);
Bukkit.getCommandAliases().keySet().forEach(map::remove); Bukkit.getCommandAliases().keySet().forEach(map::remove);
YamlConfiguration commands = YamlConfiguration.loadConfiguration(getCommandsConfigFile()); YamlConfiguration commands = YamlConfiguration.loadConfiguration(getCommandsConfigFile());
set(fields, craftServer, "commandsConfiguration", commands); reflection.set(Bukkit.getServer(), "commandsConfiguration", commands);
set(fields, craftServer, "overrideAllCommandBlockCommands", reflection.set(Bukkit.getServer(), "overrideAllCommandBlockCommands",
commands.getStringList("command-block-overrides").contains("*")); commands.getStringList("command-block-overrides").contains("*"));
set(fields, craftServer, "ignoreVanillaPermissions", if (MinecraftReflectionVersion.isMin(13)) reflection.set(
commands.getBoolean("ignore-vanilla-permissions")); Bukkit.getServer(),
set(fields, craftServer, "unrestrictedAdvancements", "ignoreVanillaPermissions",
commands.getBoolean("unrestricted-advancements")); commands.getBoolean("ignore-vanilla-permissions")
);
if (MinecraftReflectionVersion.is(12)) reflection.set(
Bukkit.getServer(),
"unrestrictedAdvancements",
commands.getBoolean("unrestricted-advancements")
);
commandMap.registerServerAliases(); commandMap.registerServerAliases();
} }
/** /**
* Reloads the ip-bans file. * Reloads the ip-bans file.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/ */
public static void reloadIpBans() throws IllegalAccessException, InvocationTargetException { public static void reloadIpBans() {
Object playerList = get(fields, craftServer, "playerList"); Object playerList = reflection.get(Bukkit.getServer(), "playerList");
Object jsonList = invoke(RPlayerList.getMethods(), playerList, "getIPBans"); Object jsonList = RPlayerList.getReflection().invoke(playerList, "getIPBans");
RJsonList.load(jsonList); RJsonList.load(jsonList);
} }
/** /**
* Reloads the profile bans file. * Reloads the profile bans file.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/ */
public static void reloadProfileBans() throws IllegalAccessException, InvocationTargetException { public static void reloadProfileBans() {
Object playerList = get(fields, craftServer, "playerList"); Object playerList = reflection.get(Bukkit.getServer(), "playerList");
Object jsonList = invoke(RPlayerList.getMethods(), playerList, "getProfileBans"); Object jsonList = RPlayerList.getReflection().invoke(playerList, "getProfileBans");
RJsonList.load(jsonList); RJsonList.load(jsonList);
} }
} }

View file

@ -1,62 +1,36 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.bukkit.entities.BukkitReflection.MINOR; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.invoke;
import static net.frankheijden.serverutils.common.reflection.VersionParam.min;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate; import java.util.function.Predicate;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import net.frankheijden.serverutils.common.utils.MapUtils; import net.frankheijden.serverutils.common.utils.MapUtils;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
public class RCraftingManager { public class RCraftingManager {
private static Class<?> craftingManagerClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.minecraft.server.%s.CraftingManager");
static {
try {
craftingManagerClass = Class.forName(String.format("net.minecraft.server.%s.CraftingManager",
BukkitReflection.NMS));
fields = getAllFields(craftingManagerClass,
fieldOf("recipes", min(12)));
} catch (Exception ex) {
ex.printStackTrace();
}
}
/** /**
* Removes all associated recipes of a plugin. * Removes all associated recipes of a plugin.
* @param plugin The plugin to remove recipes for. * @param plugin The plugin to remove recipes for.
* @throws IllegalAccessException When prohibited access to the method.
* @throws InvocationTargetException If the method call produced an exception.
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public static void removeRecipesFor(Plugin plugin) throws IllegalAccessException, InvocationTargetException { public static void removeRecipesFor(Plugin plugin) {
// Cleaning up recipes before MC 1.12 is not possible, // Cleaning up recipes before MC 1.12 is not possible,
// as recipes are not associated to plugins. // as recipes are not associated to plugins.
if (MINOR < 12) return; if (MinecraftReflectionVersion.MINOR == 12) {
RRegistryMaterials.removeKeysFor(reflection.get(null, "recipes"), plugin);
Field recipesField = fields.get("recipes"); } else if (MinecraftReflectionVersion.MINOR > 12) {
Object server = RMinecraftServer.getReflection().invoke(null, "getServer");
if (MINOR == 12) { Object craftingManager = RMinecraftServer.getReflection().invoke(server, "getCraftingManager");
Object recipes = get(fields, null, "recipes"); Map recipes = reflection.get(craftingManager, "recipes");
RRegistryMaterials.removeKeysFor(recipes, plugin);
} else {
Object server = invoke(RMinecraftServer.getMethods(), null, "getServer");
Object craftingManager = invoke(RMinecraftServer.getMethods(), server, "getCraftingManager");
Map recipes = (Map) recipesField.get(craftingManager);
Predicate<Object> predicate = RMinecraftKey.matchingPluginPredicate(new AtomicBoolean(false), plugin); Predicate<Object> predicate = RMinecraftKey.matchingPluginPredicate(new AtomicBoolean(false), plugin);
if (MINOR == 13) { if (MinecraftReflectionVersion.MINOR == 13) {
MapUtils.removeKeys(recipes, predicate); MapUtils.removeKeys(recipes, predicate);
} else { } else {
Collection<Map> list = (Collection<Map>) recipes.values(); Collection<Map> list = (Collection<Map>) recipes.values();

View file

@ -1,122 +1,73 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.bukkit.entities.BukkitReflection.MINOR; import dev.frankheijden.minecraftreflection.ClassObject;
import static net.frankheijden.serverutils.bukkit.entities.BukkitReflection.PATCH; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.invoke;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.set;
import static net.frankheijden.serverutils.common.reflection.VersionParam.between;
import static net.frankheijden.serverutils.common.reflection.VersionParam.exact;
import static net.frankheijden.serverutils.common.reflection.VersionParam.max;
import static net.frankheijden.serverutils.common.reflection.VersionParam.min;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import net.frankheijden.serverutils.common.reflection.VersionParam;
public class RDedicatedServer { public class RDedicatedServer {
private static Class<?> dedicatedServerClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.minecraft.server.%s.DedicatedServer");
private static Map<String, Method> methods;
static { public static MinecraftReflection getReflection() {
try { return reflection;
dedicatedServerClass = Class.forName(String.format("net.minecraft.server.%s.DedicatedServer",
BukkitReflection.NMS));
fields = getAllFields(dedicatedServerClass,
fieldOf("propertyManager"),
fieldOf("options"),
fieldOf("autosavePeriod"),
fieldOf("o", between(13, 15)));
methods = getAllMethods(dedicatedServerClass,
methodOf("setSpawnAnimals", max(15), boolean.class),
methodOf("getSpawnAnimals"),
methodOf("setPVP", boolean.class),
methodOf("getPVP"),
methodOf("setAllowFlight", boolean.class),
methodOf("getAllowFlight"),
methodOf("setMotd", String.class),
methodOf("getMotd"),
methodOf("setSpawnNPCs", max(15), boolean.class),
methodOf("setAllowFlight", boolean.class),
methodOf("setResourcePack", String.class, String.class),
methodOf("setForceGamemode", boolean.class),
methodOf("n", between(13, 15), boolean.class),
methodOf("aZ", max(15)),
methodOf("aZ", min(new VersionParam.Version(16, 2))),
methodOf("i", min(16), boolean.class),
methodOf("aY", exact(new VersionParam.Version(16, 1))),
methodOf("getCustomRegistry", min(new VersionParam.Version(16, 2))));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
public static Class<?> getClazz() { public static Object getCustomRegistry(Object dedicatedServer) {
return dedicatedServerClass; return reflection.invoke(dedicatedServer, "getCustomRegistry");
}
public static Object getCustomRegistry(Object dedicatedServer) throws ReflectiveOperationException {
return invoke(methods, dedicatedServer, "getCustomRegistry");
}
public static Map<String, Field> getFields() {
return fields;
} }
/** /**
* Reloads the specified console (= DedicatedServer) instance's bukkit config. * Reloads the specified console (= DedicatedServer) instance's bukkit config.
* @param console The console to reload. * @param console The console to reload.
* @throws ReflectiveOperationException Iff exception thrown regarding reflection.
*/ */
public static void reload(Object console) throws ReflectiveOperationException { public static void reload(Object console) {
Object options = get(fields, console, "options"); Object options = reflection.get(console, "options");
if (MINOR >= 13) { if (MinecraftReflectionVersion.MINOR >= 13) {
Object propertyManager; Object propertyManager;
if (MINOR >= 16 && PATCH >= 2) { if (MinecraftReflectionVersion.MINOR >= 16 && MinecraftReflectionVersion.PATCH >= 2) {
propertyManager = RDedicatedServerSettings.newInstance(invoke(methods, console, "getCustomRegistry"), propertyManager = RDedicatedServerSettings.newInstance(reflection.invoke(console, "getCustomRegistry"),
options); options);
} else { } else {
propertyManager = RDedicatedServerSettings.newInstance(options); propertyManager = RDedicatedServerSettings.newInstance(options);
} }
set(fields, console, "propertyManager", propertyManager); reflection.set(console, "propertyManager", propertyManager);
Object config = invoke(RDedicatedServerSettings.getMethods(), propertyManager, "getProperties"); Object config = RDedicatedServerSettings.getReflection().invoke(propertyManager, "getProperties");
invoke(methods, console, "setPVP", getConfigValue(config, "pvp")); reflection.invoke(console, "setPVP", ClassObject.of(boolean.class, getConfigValue(config, "pvp")));
invoke(methods, console, "setAllowFlight", getConfigValue(config, "allowFlight")); reflection.invoke(console, "setAllowFlight",
invoke(methods, console, "setMotd", getConfigValue(config, "motd")); ClassObject.of(boolean.class, getConfigValue(config, "allowFlight")));
invoke(methods, console, "setForceGamemode", getConfigValue(config, "forceGamemode")); reflection.invoke(console, "setMotd", getConfigValue(config, "motd"));
reflection.invoke(console, "setForceGamemode",
ClassObject.of(boolean.class, getConfigValue(config, "forceGamemode")));
Object resourcePackHash; Object resourcePackHash;
if (MINOR <= 15 || (MINOR == 16 && PATCH == 1)) { if (MinecraftReflectionVersion.MINOR <= 15 || MinecraftReflectionVersion.is(16, 1)) {
resourcePackHash = invoke(methods, console, "aZ"); resourcePackHash = reflection.invoke(console, "aZ");
} else if (MinecraftReflectionVersion.is(16, 3)) {
resourcePackHash = reflection.invoke(console, "ba");
} else { } else {
resourcePackHash = invoke(methods, console, "aY"); resourcePackHash = reflection.invoke(console, "aY");
} }
invoke(methods, console, "setResourcePack", getConfigValue(config, "resourcePack"), resourcePackHash); reflection.invoke(console, "setResourcePack", getConfigValue(config, "resourcePack"), resourcePackHash);
if (MINOR <= 15) { if (MinecraftReflectionVersion.MINOR <= 15) {
invoke(methods, console, "setSpawnAnimals", getConfigValue(config, "spawnAnimals")); reflection.invoke(console, "setSpawnAnimals",
invoke(methods, console, "setSpawnNPCs", getConfigValue(config, "spawnNpcs")); ClassObject.of(boolean.class, getConfigValue(config, "spawnAnimals")));
invoke(methods, console, "n", getConfigValue(config, "enforceWhitelist")); reflection.invoke(console, "setSpawnNPCs",
set(fields, console, "o", getConfigValue(config, "gamemode")); ClassObject.of(boolean.class, getConfigValue(config, "spawnNpcs")));
reflection.invoke(console, "n",
ClassObject.of(boolean.class, getConfigValue(config, "enforceWhitelist")));
reflection.set(console, "o", getConfigValue(config, "gamemode"));
} else { } else {
invoke(methods, console, "i", getConfigValue(config, "enforceWhitelist")); reflection.invoke(console, "i",
ClassObject.of(boolean.class, getConfigValue(config, "enforceWhitelist")));
} }
} else { } else {
Object config = RPropertyManager.newInstance(options); Object config = RPropertyManager.newInstance(options);
@ -131,28 +82,28 @@ public class RDedicatedServer {
* Reloads server.properties. * Reloads server.properties.
* @throws ReflectiveOperationException Iff exception thrown regarding reflection. * @throws ReflectiveOperationException Iff exception thrown regarding reflection.
*/ */
public static void reloadServerProperties() throws ReflectiveOperationException { public static void reloadServerProperties() {
Object console = RCraftServer.getConsole(); Object console = RCraftServer.getConsole();
Object playerList = get(RMinecraftServer.getFields(), console, "playerList"); Object playerList = RMinecraftServer.getReflection().get(console, "playerList");
Object propertyManager = get(fields, console, "propertyManager"); Object propertyManager = reflection.get(console, "propertyManager");
Path path = RDedicatedServerSettings.getServerPropertiesPath(propertyManager); Path path = RDedicatedServerSettings.getServerPropertiesPath(propertyManager);
Properties properties = new Properties(); Properties properties = new Properties();
try (InputStream in = new FileInputStream(path.toFile())) { try (InputStream in = new FileInputStream(path.toFile())) {
properties.load(in); properties.load(in);
} catch (IOException ex) { } catch (IOException ex) {
throw new ReflectiveOperationException("Unable to load server.properties", ex); throw new RuntimeException("Unable to load server.properties", ex);
} }
int maxPlayers = Integer.parseInt(properties.getProperty("max-players")); int maxPlayers = Integer.parseInt(properties.getProperty("max-players"));
set(RPlayerList.getFields(), playerList, "maxPlayers", maxPlayers); RPlayerList.getReflection().set(playerList, "maxPlayers", maxPlayers);
int viewDistance = Integer.parseInt(properties.getProperty("view-distance")); int viewDistance = Integer.parseInt(properties.getProperty("view-distance"));
RPlayerList.setViewDistance(playerList, viewDistance); RPlayerList.setViewDistance(playerList, viewDistance);
} }
public static Object getConfigValue(Object config, String key) throws IllegalAccessException { public static Object getConfigValue(Object config, String key) {
return get(RDedicatedServerProperties.getFields(), config, key); return RDedicatedServerProperties.getReflection().get(config, key);
} }
/** /**
@ -163,14 +114,11 @@ public class RDedicatedServer {
* @param setMethod The setter method for the config value. * @param setMethod The setter method for the config value.
* @param configMethod The method which we call the config value upon. * @param configMethod The method which we call the config value upon.
* @param key The config key. * @param key The config key.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/ */
public static void setConfigValue(Object config, Object console, String getMethod, String setMethod, public static void setConfigValue(Object config, Object console, String getMethod, String setMethod,
String configMethod, String key) String configMethod, String key) {
throws InvocationTargetException, IllegalAccessException { Object defaultValue = reflection.invoke(console, getMethod);
Object defaultValue = invoke(methods, console, getMethod); Object configValue = RPropertyManager.getReflection().invoke(config, configMethod, key, defaultValue);
Object configValue = invoke(RPropertyManager.getMethods(), config, configMethod, key, defaultValue); reflection.invoke(console, setMethod, configValue);
invoke(methods, console, setMethod, configValue);
} }
} }

View file

@ -1,37 +1,13 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import java.lang.reflect.Field;
import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
public class RDedicatedServerProperties { public class RDedicatedServerProperties {
private static Class<?> serverPropertiesClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.minecraft.server.%s.DedicatedServerProperties");
static { public static MinecraftReflection getReflection() {
try { return reflection;
serverPropertiesClass = Class.forName(String.format("net.minecraft.server.%s.DedicatedServerProperties",
BukkitReflection.NMS));
fields = getAllFields(serverPropertiesClass,
fieldOf("spawnAnimals"),
fieldOf("spawnNpcs"),
fieldOf("pvp"),
fieldOf("allowFlight"),
fieldOf("resourcePack"),
fieldOf("motd"),
fieldOf("forceGamemode"),
fieldOf("enforceWhitelist"),
fieldOf("gamemode"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Map<String, Field> getFields() {
return fields;
} }
} }

View file

@ -1,69 +1,33 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.ConstructorParam.constructorOf; import dev.frankheijden.minecraftreflection.ClassObject;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllConstructors;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
public class RDedicatedServerSettings { public class RDedicatedServerSettings {
private static Class<?> serverSettingsClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Method> methods; .of("net.minecraft.server.%s.DedicatedServerSettings");
private static Map<String, Field> fields;
private static List<Constructor<?>> constructors;
static { public static MinecraftReflection getReflection() {
try { return reflection;
serverSettingsClass = Class.forName(String.format("net.minecraft.server.%s.DedicatedServerSettings",
BukkitReflection.NMS));
methods = getAllMethods(serverSettingsClass,
methodOf("getProperties"));
fields = getAllFields(serverSettingsClass,
fieldOf("path"));
constructors = getAllConstructors(serverSettingsClass,
constructorOf(Class.forName("joptsimple.OptionSet")),
constructorOf(Class.forName(String.format("net.minecraft.server.%s.IRegistryCustom",
BukkitReflection.NMS)), Class.forName("joptsimple.OptionSet")));
} catch (Exception ex) {
ex.printStackTrace();
} }
public static Object newInstance(Object options) {
return reflection.newInstance(options);
} }
/** /**
* Retrieves the default constructor. * Initiates a new instance of DedicatedServerSettings.
* @return The default constructor of DedicatedServerSettings.
* @throws NoSuchMethodException If no constructor was found.
*/ */
public static Constructor<?> getConstructor() throws NoSuchMethodException { public static Object newInstance(Object registry, Object options) {
if (constructors.size() == 0) throw new NoSuchMethodException("No constructor found for " return reflection.newInstance(
+ serverSettingsClass.getName()); ClassObject.of(RIRegistryCustom.getReflection().getClazz(), registry),
return constructors.get(0); ClassObject.of(options)
);
} }
public static Object newInstance(Object options) throws ReflectiveOperationException { public static Path getServerPropertiesPath(Object instance) {
return getConstructor().newInstance(options); return reflection.get(instance, "path");
}
public static Object newInstance(Object registry, Object options) throws ReflectiveOperationException {
return getConstructor().newInstance(registry, options);
}
public static Path getServerPropertiesPath(Object instance) throws ReflectiveOperationException {
return (Path) get(fields, instance, "path");
}
public static Map<String, Method> getMethods() {
return methods;
} }
} }

View file

@ -0,0 +1,13 @@
package net.frankheijden.serverutils.bukkit.reflection;
import dev.frankheijden.minecraftreflection.MinecraftReflection;
public class RIRegistryCustom {
private static final MinecraftReflection reflection = MinecraftReflection
.of("net.minecraft.server.%s.IRegistryCustom");
public static MinecraftReflection getReflection() {
return reflection;
}
}

View file

@ -1,59 +1,35 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.invoke;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.set;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class RJavaPlugin { public class RJavaPlugin {
private static Class<?> javaPluginClass; private static final MinecraftReflection reflection = MinecraftReflection.of(JavaPlugin.class);
private static Map<String, Field> fields;
private static Map<String, Method> methods;
static { public static MinecraftReflection getReflection() {
try { return reflection;
javaPluginClass = JavaPlugin.class;
fields = getAllFields(javaPluginClass,
fieldOf("loader"),
fieldOf("classLoader"));
methods = getAllMethods(javaPluginClass,
methodOf("getClassLoader"),
methodOf("getClass"),
methodOf("getFile"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
public static ClassLoader getClassLoader(Object instance) throws InvocationTargetException, IllegalAccessException { public static ClassLoader getClassLoader(Object instance) {
return (ClassLoader) invoke(methods, instance, "getClassLoader"); return reflection.invoke(instance, "getClassLoader");
} }
public static File getFile(Object instance) throws ReflectiveOperationException { public static File getFile(Object instance) {
return (File) invoke(methods, instance, "getFile"); return reflection.invoke(instance, "getFile");
} }
/** /**
* Clears the JavaPlugin from instances and returns the classloader associated with it. * Clears the JavaPlugin from instances and returns the classloader associated with it.
* @param instance The instance of the JavaPlugin. * @param instance The instance of the JavaPlugin.
* @return The classloader associated with it. * @return The classloader associated with it.
* @throws ReflectiveOperationException When a reflection error occurred.
*/ */
public static Closeable clearJavaPlugin(Object instance) throws ReflectiveOperationException { public static Closeable clearJavaPlugin(Object instance) {
set(fields, instance, "loader", null); reflection.set(instance, "loader", null);
set(fields, instance, "classLoader", null); reflection.set(instance, "classLoader", null);
Class<?> clazz = (Class<?>) invoke(methods, instance, "getClass"); Class<?> clazz = reflection.invoke(instance, "getClass");
if (clazz != null && clazz.getClassLoader() instanceof Closeable) { if (clazz != null && clazz.getClassLoader() instanceof Closeable) {
return (Closeable) clazz.getClassLoader(); return (Closeable) clazz.getClassLoader();
} }

View file

@ -1,38 +1,25 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import java.lang.reflect.Field;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.plugin.java.JavaPluginLoader;
public class RJavaPluginLoader { public class RJavaPluginLoader {
private static Class<?> javaPluginLoaderClass; private static final MinecraftReflection reflection = MinecraftReflection.of(JavaPluginLoader.class);
private static Map<String, Field> fields;
static { public static MinecraftReflection getReflection() {
try { return reflection;
javaPluginLoaderClass = JavaPluginLoader.class;
fields = getAllFields(javaPluginLoaderClass,
fieldOf("classes"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
/** /**
* Removes the given classes from the JavaPluginLoader instance. * Removes the given classes from the JavaPluginLoader instance.
* @param instance The instance. * @param instance The instance.
* @param list The list of classpaths. * @param list The list of classpaths.
* @throws IllegalAccessException When prohibited access to the method.
*/ */
@SuppressWarnings("unchecked") public static void removeClasses(Object instance, Collection<? extends String> list) {
public static void removeClasses(Object instance, Collection<? extends String> list) throws IllegalAccessException { Map<String, Class<?>> classes = reflection.get(instance, "classes");
Map<String, Class<?>> classes = (Map<String, Class<?>>) get(fields, instance, "classes");
if (classes == null) return; if (classes == null) return;
for (String key : list) { for (String key : list) {

View file

@ -1,30 +1,16 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.invoke;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
public class RJsonList { public class RJsonList {
private static Class<?> jsonListClass; private static final MinecraftReflection reflection = MinecraftReflection.of("net.minecraft.server.%s.JsonList");
private static Map<String, Method> methods;
static { public static MinecraftReflection getReflection() {
try { return reflection;
jsonListClass = Class.forName(String.format("net.minecraft.server.%s.JsonList", BukkitReflection.NMS));
methods = getAllMethods(jsonListClass,
methodOf("load"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
public static void load(Object jsonList) throws InvocationTargetException, IllegalAccessException { public static void load(Object jsonList) {
invoke(methods, jsonList, "load"); reflection.invoke(jsonList, "load");
} }
} }

View file

@ -1,48 +1,31 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.bukkit.entities.BukkitReflection.MINOR; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflectionVersion;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.VersionParam.max;
import static net.frankheijden.serverutils.common.reflection.VersionParam.min;
import java.lang.reflect.Field;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate; import java.util.function.Predicate;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
public class RMinecraftKey { public class RMinecraftKey {
private static Class<?> minecraftKeyClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.minecraft.server.%s.MinecraftKey");
static { public static MinecraftReflection getReflection() {
try { return reflection;
minecraftKeyClass = Class.forName(String.format("net.minecraft.server.%s.MinecraftKey",
BukkitReflection.NMS));
fields = getAllFields(minecraftKeyClass,
fieldOf("a", max(13)),
fieldOf("namespace", min(14)));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
/** /**
* Retrieves the namespace of the specified MinecraftKey instance. * Retrieves the namespace of the specified MinecraftKey instance.
* @param instance The MinecraftKey instance. * @param instance The MinecraftKey instance.
* @return The namespace. * @return The namespace.
* @throws IllegalAccessException When prohibited access to the field.
*/ */
public static String getNameSpace(Object instance) throws IllegalAccessException { public static String getNameSpace(Object instance) {
if (MINOR <= 13) { if (MinecraftReflectionVersion.MINOR <= 13) {
return (String) get(fields, instance, "a"); return reflection.get(instance, "a");
} }
return (String) get(fields, instance, "namespace"); return reflection.get(instance, "namespace");
} }
public static boolean isFrom(Object instance, Plugin plugin) throws IllegalAccessException { public static boolean isFrom(Object instance, Plugin plugin) throws IllegalAccessException {

View file

@ -1,40 +1,13 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
public class RMinecraftServer { public class RMinecraftServer {
private static Class<?> minecraftServerClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Method> methods; .of("net.minecraft.server.%s.MinecraftServer");
private static Map<String, Field> fields;
static { public static MinecraftReflection getReflection() {
try { return reflection;
minecraftServerClass = Class.forName(String.format("net.minecraft.server.%s.MinecraftServer",
BukkitReflection.NMS));
methods = getAllMethods(minecraftServerClass,
methodOf("getServer"),
methodOf("getCraftingManager"));
fields = getAllFields(minecraftServerClass,
fieldOf("playerList"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Map<String, Method> getMethods() {
return methods;
}
public static Map<String, Field> getFields() {
return fields;
} }
} }

View file

@ -1,27 +1,12 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import java.lang.reflect.Method;
import java.util.Map;
public class ROptionSet { public class ROptionSet {
private static Class<?> optionSetClass; private static final MinecraftReflection reflection = MinecraftReflection.of("joptsimple.OptionSet");
private static Map<String, Method> methods;
static { public static MinecraftReflection getReflection() {
try { return reflection;
optionSetClass = Class.forName("joptsimple.OptionSet");
methods = getAllMethods(optionSetClass,
methodOf("valueOf", String.class));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Map<String, Method> getMethods() {
return methods;
} }
} }

View file

@ -1,48 +1,19 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.ClassObject;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.invoke;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.set;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
public class RPlayerList { public class RPlayerList {
private static Class<?> playerListClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Method> methods; .of("net.minecraft.server.%s.PlayerList");
private static Map<String, Field> fields;
static { public static MinecraftReflection getReflection() {
try { return reflection;
playerListClass = Class.forName(String.format("net.minecraft.server.%s.PlayerList", BukkitReflection.NMS));
methods = getAllMethods(playerListClass,
methodOf("getIPBans"),
methodOf("getProfileBans"),
methodOf("a", int.class));
fields = getAllFields(playerListClass,
fieldOf("maxPlayers"),
fieldOf("viewDistance"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
public static Map<String, Method> getMethods() { public static void setViewDistance(Object instance, int viewDistance) {
return methods; reflection.set(instance, "viewDistance", viewDistance);
} reflection.invoke(instance, "a", ClassObject.of(int.class, viewDistance));
public static Map<String, Field> getFields() {
return fields;
}
public static void setViewDistance(Object instance, int viewDistance) throws ReflectiveOperationException {
set(fields, instance, "viewDistance", viewDistance);
invoke(methods, instance, "a", viewDistance);
} }
} }

View file

@ -1,42 +1,24 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.set;
import java.lang.reflect.Field;
import java.util.Map; import java.util.Map;
public class RPluginClassLoader { public class RPluginClassLoader {
private static Class<?> pluginClassLoaderClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("org.bukkit.plugin.java.PluginClassLoader");
static { public static MinecraftReflection getReflection() {
try { return reflection;
pluginClassLoaderClass = Class.forName("org.bukkit.plugin.java.PluginClassLoader");
fields = getAllFields(pluginClassLoaderClass,
fieldOf("plugin"),
fieldOf("pluginInit"),
fieldOf("classes"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static boolean isInstance(Object obj) {
return pluginClassLoaderClass.isInstance(obj);
} }
/** /**
* Clears and closes the provided classloader. * Clears and closes the provided classloader.
* @param loader The classloader instance. * @param loader The classloader instance.
* @throws IllegalAccessException When prohibited access to the field.
*/ */
public static void clearClassLoader(ClassLoader loader) throws IllegalAccessException { public static void clearClassLoader(ClassLoader loader) {
if (loader == null) return; if (loader == null) return;
if (isInstance(loader)) { if (reflection.getClazz().isInstance(loader)) {
clearPluginClassLoader(loader); clearPluginClassLoader(loader);
} }
} }
@ -44,16 +26,14 @@ public class RPluginClassLoader {
/** /**
* Clears the plugin fields from the specified PluginClassLoader. * Clears the plugin fields from the specified PluginClassLoader.
* @param pluginLoader The plugin loader instance. * @param pluginLoader The plugin loader instance.
* @throws IllegalAccessException When prohibited access to the field.
*/ */
public static void clearPluginClassLoader(Object pluginLoader) throws IllegalAccessException { public static void clearPluginClassLoader(Object pluginLoader) {
if (pluginLoader == null) return; if (pluginLoader == null) return;
set(fields, pluginLoader, "plugin", null); reflection.set(pluginLoader, "plugin", null);
set(fields, pluginLoader, "pluginInit", null); reflection.set(pluginLoader, "pluginInit", null);
} }
@SuppressWarnings("unchecked") public static Map<String, Class<?>> getClasses(Object pluginLoader) {
public static Map<String, Class<?>> getClasses(Object pluginLoader) throws IllegalAccessException { return reflection.get(pluginLoader, "classes");
return (Map<String, Class<?>>) get(fields, pluginLoader, "classes");
} }
} }

View file

@ -1,34 +1,17 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.MethodParam.methodOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllMethods;
import java.lang.reflect.Method;
import java.util.Map;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
public class RPropertyManager { public class RPropertyManager {
private static Class<?> propertyManagerClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Method> methods; .of("net.minecraft.server.%s.PropertyManager");
static { public static MinecraftReflection getReflection() {
try { return reflection;
propertyManagerClass = Class.forName(String.format("net.minecraft.server.%s.PropertyManager",
BukkitReflection.NMS));
methods = getAllMethods(propertyManagerClass,
methodOf("getBoolean", String.class, boolean.class),
methodOf("getString", String.class, String.class));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
public static Object newInstance(Object options) throws ReflectiveOperationException { public static Object newInstance(Object options) {
return propertyManagerClass.getDeclaredConstructor(Class.forName("joptsimple.OptionSet")).newInstance(options); return ROptionSet.getReflection().newInstance(options);
}
public static Map<String, Method> getMethods() {
return methods;
} }
} }

View file

@ -1,42 +1,28 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import java.lang.reflect.Field;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import net.frankheijden.serverutils.common.utils.MapUtils; import net.frankheijden.serverutils.common.utils.MapUtils;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
public class RRegistryMaterials { public class RRegistryMaterials {
private static Class<?> registryMaterialsClass; private static final MinecraftReflection reflection = MinecraftReflection
.of("net.minecraft.server.%s.RegistryMaterials");
private static Map<String, Field> fields; public static MinecraftReflection getReflection() {
return reflection;
static {
try {
registryMaterialsClass = Class.forName(String.format("net.minecraft.server.%s.RegistryMaterials",
BukkitReflection.NMS));
fields = getAllFields(registryMaterialsClass,
fieldOf("b"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
/** /**
* Removes all registered keys from an instance associated to the specified plugin. * Removes all registered keys from an instance associated to the specified plugin.
* @param instance The RegistryMaterials instance. * @param instance The RegistryMaterials instance.
* @param plugin The plugin to remove keys for. * @param plugin The plugin to remove keys for.
* @throws IllegalAccessException When prohibited access to the field.
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static void removeKeysFor(Object instance, Plugin plugin) throws IllegalAccessException { public static void removeKeysFor(Object instance, Plugin plugin) {
Map map = (Map) get(fields, instance, "b"); Map map = reflection.get(instance, "b");
if (map == null) throw new RuntimeException("Map object was null!"); if (map == null) throw new RuntimeException("Map object was null!");
AtomicBoolean errorThrown = new AtomicBoolean(false); AtomicBoolean errorThrown = new AtomicBoolean(false);

View file

@ -1,41 +1,28 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import java.lang.reflect.Field;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import net.frankheijden.serverutils.bukkit.entities.BukkitReflection;
import net.frankheijden.serverutils.common.utils.MapUtils; import net.frankheijden.serverutils.common.utils.MapUtils;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
public class RRegistrySimple { public class RRegistrySimple {
private static Class<?> registrySimpleClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.minecraft.server.%s.RegistrySimple");
static { public static MinecraftReflection getReflection() {
try { return reflection;
registrySimpleClass = Class.forName(String.format("net.minecraft.server.%s.RegistrySimple",
BukkitReflection.NMS));
fields = getAllFields(registrySimpleClass,
fieldOf("c"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
/** /**
* Removes all registered MinecraftKey's from an instance associated to the specified plugin. * Removes all registered MinecraftKey's from an instance associated to the specified plugin.
* @param instance The RegistrySimple instance. * @param instance The RegistrySimple instance.
* @param plugin The plugin to remove keys for. * @param plugin The plugin to remove keys for.
* @throws IllegalAccessException When prohibited access to the field.
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static void removeKeyFor(Object instance, Plugin plugin) throws IllegalAccessException { public static void removeKeyFor(Object instance, Plugin plugin) {
Map map = (Map) get(fields, instance, "c"); Map map = reflection.get(instance, "c");
if (map == null) throw new RuntimeException("Map object was null!"); if (map == null) throw new RuntimeException("Map object was null!");
AtomicBoolean errorThrown = new AtomicBoolean(false); AtomicBoolean errorThrown = new AtomicBoolean(false);

View file

@ -1,10 +1,6 @@
package net.frankheijden.serverutils.bukkit.reflection; package net.frankheijden.serverutils.bukkit.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf; import dev.frankheijden.minecraftreflection.MinecraftReflection;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -15,29 +11,18 @@ import org.bukkit.plugin.SimplePluginManager;
public class RSimplePluginManager { public class RSimplePluginManager {
private static Class<?> simplePluginManagerClass; private static final MinecraftReflection reflection = MinecraftReflection.of(SimplePluginManager.class);
private static Map<String, Field> fields;
static { public static MinecraftReflection getReflection() {
try { return reflection;
simplePluginManagerClass = SimplePluginManager.class;
fields = getAllFields(simplePluginManagerClass,
fieldOf("plugins"),
fieldOf("lookupNames"),
fieldOf("fileAssociations"));
} catch (Exception ex) {
ex.printStackTrace();
}
} }
@SuppressWarnings("unchecked")
public static Map<Pattern, PluginLoader> getFileAssociations(Object manager) throws IllegalAccessException { public static Map<Pattern, PluginLoader> getFileAssociations(Object manager) throws IllegalAccessException {
return (Map<Pattern, PluginLoader>) get(fields, manager, "fileAssociations"); return reflection.get(manager, "fileAssociations");
} }
@SuppressWarnings("unchecked") public static List<Plugin> getPlugins(Object manager) {
public static List<Plugin> getPlugins(Object manager) throws IllegalAccessException { return reflection.get(manager, "plugins");
return (List<Plugin>) get(fields, manager, "plugins");
} }
/** /**
@ -45,11 +30,9 @@ public class RSimplePluginManager {
* This ensures the plugin cannot be found anymore in Bukkit#getPlugin(String name). * This ensures the plugin cannot be found anymore in Bukkit#getPlugin(String name).
* @param manager The SimplePluginManager instance to remove the lookup name from. * @param manager The SimplePluginManager instance to remove the lookup name from.
* @param name The name of the plugin to remove. * @param name The name of the plugin to remove.
* @throws IllegalAccessException When prohibited access to the field.
*/ */
@SuppressWarnings("unchecked") public static void removeLookupName(Object manager, String name) {
public static void removeLookupName(Object manager, String name) throws IllegalAccessException { Map<String, Plugin> lookupNames = reflection.get(manager, "lookupNames");
Map<String, Plugin> lookupNames = (Map<String, Plugin>) get(fields, manager, "lookupNames");
if (lookupNames == null) return; if (lookupNames == null) return;
lookupNames.remove(name.replace(' ', '_')); lookupNames.remove(name.replace(' ', '_'));
lookupNames.remove(name.replace(' ', '_').toLowerCase(Locale.ENGLISH)); // Paper lookupNames.remove(name.replace(' ', '_').toLowerCase(Locale.ENGLISH)); // Paper

View file

@ -6,7 +6,6 @@ import co.aikar.commands.CommandCompletions;
import net.frankheijden.serverutils.bungee.commands.CommandPlugins; import net.frankheijden.serverutils.bungee.commands.CommandPlugins;
import net.frankheijden.serverutils.bungee.commands.CommandServerUtils; import net.frankheijden.serverutils.bungee.commands.CommandServerUtils;
import net.frankheijden.serverutils.bungee.entities.BungeePlugin; import net.frankheijden.serverutils.bungee.entities.BungeePlugin;
import net.frankheijden.serverutils.bungee.entities.BungeeReflection;
import net.frankheijden.serverutils.bungee.listeners.BungeeListener; import net.frankheijden.serverutils.bungee.listeners.BungeeListener;
import net.frankheijden.serverutils.bungee.managers.BungeePluginManager; import net.frankheijden.serverutils.bungee.managers.BungeePluginManager;
import net.frankheijden.serverutils.bungee.reflection.RPluginClassLoader; import net.frankheijden.serverutils.bungee.reflection.RPluginClassLoader;
@ -38,7 +37,6 @@ public class ServerUtils extends Plugin {
ServerUtilsApp.init(this, plugin); ServerUtilsApp.init(this, plugin);
new Metrics(this, ServerUtilsApp.BSTATS_METRICS_ID); new Metrics(this, ServerUtilsApp.BSTATS_METRICS_ID);
new BungeeReflection();
this.commandManager = new BungeeCommandManager(this); this.commandManager = new BungeeCommandManager(this);
commandManager.registerCommand(new CommandPlugins()); commandManager.registerCommand(new CommandPlugins());

View file

@ -255,13 +255,7 @@ public class CommandServerUtils extends BaseCommand {
return; return;
} }
Plugin plugin; Plugin plugin = RPluginManager.getPlugin(proxy.getPluginManager(), cmd);
try {
plugin = RPluginManager.getPlugin(proxy.getPluginManager(), cmd);
} catch (IllegalAccessException ex) {
ex.printStackTrace();
return;
}
if (plugin == null) { if (plugin == null) {
return; return;
} }

View file

@ -1,12 +0,0 @@
package net.frankheijden.serverutils.bungee.entities;
import net.frankheijden.serverutils.common.reflection.ReflectionUtils;
import net.frankheijden.serverutils.common.reflection.VersionParam;
public class BungeeReflection extends ReflectionUtils {
@Override
public boolean isCompatible(VersionParam param) {
return true;
}
}

View file

@ -1,55 +1,33 @@
package net.frankheijden.serverutils.bungee.reflection; package net.frankheijden.serverutils.bungee.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL; import java.net.URL;
import java.util.Map;
import java.util.Set; import java.util.Set;
import dev.frankheijden.minecraftreflection.MinecraftReflection;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginDescription; import net.md_5.bungee.api.plugin.PluginDescription;
public class RPluginClassLoader { public class RPluginClassLoader {
private static Class<?> loaderClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.md_5.bungee.api.plugin.PluginClassloader");
private static Constructor<?> constructor;
static { public static Object newInstance(ProxyServer proxy, PluginDescription desc, URL... urls) {
try { return reflection.newInstance(proxy, desc, urls);
loaderClass = Class.forName("net.md_5.bungee.api.plugin.PluginClassloader");
constructor = loaderClass.getDeclaredConstructor(ProxyServer.class, PluginDescription.class, URL[].class);
constructor.setAccessible(true);
fields = getAllFields(loaderClass,
fieldOf("allLoaders"),
fieldOf("plugin"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Object newInstance(ProxyServer proxy, PluginDescription desc, URL... urls) throws Exception {
return constructor.newInstance(proxy, desc, urls);
} }
/** /**
* Retrieves the PluginClassLoader of a specific plugin. * Retrieves the PluginClassLoader of a specific plugin.
* @param plugin The plugin to lookup the PluginClassLoader for. * @param plugin The plugin to lookup the PluginClassLoader for.
* @return The PluginClassLoader. * @return The PluginClassLoader.
* @throws ReflectiveOperationException Iff a reflection error occurred.
*/ */
@SuppressWarnings("unchecked") public static Object getPluginClassLoader(Plugin plugin) {
public static Object getPluginClassLoader(Plugin plugin) throws ReflectiveOperationException { Set<Object> allLoaders = reflection.get(null, "allLoaders");
Set<Object> allLoaders = (Set<Object>) get(fields, null, "allLoaders");
if (allLoaders == null) return null; if (allLoaders == null) return null;
Object matchingLoader = null; Object matchingLoader = null;
for (Object loader : allLoaders) { for (Object loader : allLoaders) {
if (plugin.equals(get(fields, loader, "plugin"))) { if (plugin.equals(reflection.get(loader, "plugin"))) {
matchingLoader = loader; matchingLoader = loader;
break; break;
} }

View file

@ -1,12 +1,8 @@
package net.frankheijden.serverutils.bungee.reflection; package net.frankheijden.serverutils.bungee.reflection;
import static net.frankheijden.serverutils.common.reflection.FieldParam.fieldOf;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.get;
import static net.frankheijden.serverutils.common.reflection.ReflectionUtils.getAllFields;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import java.lang.reflect.Field;
import java.util.Map; import java.util.Map;
import dev.frankheijden.minecraftreflection.MinecraftReflection;
import net.frankheijden.serverutils.common.utils.MapUtils; import net.frankheijden.serverutils.common.utils.MapUtils;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
@ -14,61 +10,40 @@ import org.yaml.snakeyaml.Yaml;
public class RPluginManager { public class RPluginManager {
private static Class<?> pluginManagerClass; private static final MinecraftReflection reflection = MinecraftReflection
private static Map<String, Field> fields; .of("net.md_5.bungee.api.plugin.PluginManager");
static {
try {
pluginManagerClass = Class.forName("net.md_5.bungee.api.plugin.PluginManager");
fields = getAllFields(pluginManagerClass,
fieldOf("yaml"),
fieldOf("plugins"),
fieldOf("commandMap"),
fieldOf("toLoad"),
fieldOf("commandsByPlugin"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
/** /**
* Clears the plugin from the PluginManager. * Clears the plugin from the PluginManager.
* @param instance The instance of the PluginManager. * @param instance The instance of the PluginManager.
* @param plugin The plugin to clear. * @param plugin The plugin to clear.
* @throws ReflectiveOperationException Iff a reflection error happened.
*/ */
@SuppressWarnings("rawtypes") public static void clearPlugin(Object instance, Plugin plugin) {
public static void clearPlugin(Object instance, Plugin plugin) throws ReflectiveOperationException {
String pluginName = plugin.getDescription().getName(); String pluginName = plugin.getDescription().getName();
MapUtils.remove((Map) get(fields, instance, "plugins"), pluginName); MapUtils.remove(reflection.get(instance, "plugins"), pluginName);
MapUtils.remove((Map) get(fields, instance, "toLoad"), pluginName); MapUtils.remove(reflection.get(instance, "toLoad"), pluginName);
} }
@SuppressWarnings("unchecked") public static Map<String, Plugin> getPlugins(Object instance) {
public static Map<String, Plugin> getPlugins(Object instance) throws ReflectiveOperationException { return reflection.get(instance, "plugins");
return (Map<String, Plugin>) get(fields, instance, "plugins");
} }
public static Yaml getYaml(Object instance) throws IllegalAccessException { public static Yaml getYaml(Object instance) {
return (Yaml) get(fields, instance, "yaml"); return reflection.get(instance, "yaml");
} }
@SuppressWarnings("unchecked")
public static Map<String, Command> getCommands(Object instance) throws IllegalAccessException { public static Map<String, Command> getCommands(Object instance) throws IllegalAccessException {
return (Map<String, Command>) get(fields, instance, "commandMap"); return reflection.get(instance, "commandMap");
} }
/** /**
* Retrieves the registered plugin of the command. * Retrieves the registered plugin of the command.
* @param instance The PluginManager instance. * @param instance The PluginManager instance.
* @param cmd The command to check the plugin of. * @param cmd The command to check the plugin of.
* @return The plugin of the command * @return The plugin of the command.
* @throws IllegalAccessException Iff some reflection error occurred.
*/ */
@SuppressWarnings("unchecked") public static Plugin getPlugin(Object instance, Command cmd) {
public static Plugin getPlugin(Object instance, Command cmd) throws IllegalAccessException { Multimap<Plugin, Command> plugins = reflection.get(instance, "commandsByPlugin");
Object obj = get(fields, instance, "commandsByPlugin");
Multimap<Plugin, Command> plugins = (Multimap<Plugin, Command>) obj;
if (plugins == null) return null; if (plugins == null) return null;
for (Map.Entry<Plugin, Command> entry : plugins.entries()) { for (Map.Entry<Plugin, Command> entry : plugins.entries()) {

View file

@ -1,14 +0,0 @@
package net.frankheijden.serverutils.common.reflection;
public class ConstructorParam {
public final Class<?>[] params;
private ConstructorParam(Class<?>[] params) {
this.params = params;
}
public static ConstructorParam constructorOf(Class<?>... params) {
return new ConstructorParam(params);
}
}

View file

@ -1,22 +0,0 @@
package net.frankheijden.serverutils.common.reflection;
import static net.frankheijden.serverutils.common.reflection.VersionParam.ALL_VERSIONS;
public class FieldParam {
public final String field;
public final VersionParam versionParam;
private FieldParam(String field, VersionParam versionParam) {
this.field = field;
this.versionParam = versionParam;
}
public static FieldParam fieldOf(String field, VersionParam versionParam) {
return new FieldParam(field, versionParam);
}
public static FieldParam fieldOf(String field) {
return fieldOf(field, ALL_VERSIONS);
}
}

View file

@ -1,24 +0,0 @@
package net.frankheijden.serverutils.common.reflection;
import static net.frankheijden.serverutils.common.reflection.VersionParam.ALL_VERSIONS;
public class MethodParam {
public final String method;
public final VersionParam versionParam;
public final Class<?>[] params;
private MethodParam(String method, VersionParam versionParam, Class<?>... params) {
this.method = method;
this.versionParam = versionParam;
this.params = params;
}
public static MethodParam methodOf(String method, VersionParam versionParam, Class<?>... params) {
return new MethodParam(method, versionParam, params);
}
public static MethodParam methodOf(String method, Class<?>... params) {
return methodOf(method, ALL_VERSIONS, params);
}
}

View file

@ -1,193 +0,0 @@
package net.frankheijden.serverutils.common.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class ReflectionUtils {
private static ReflectionUtils instance;
public ReflectionUtils() {
instance = this;
}
public static ReflectionUtils getInstance() {
return instance;
}
public abstract boolean isCompatible(VersionParam param);
/**
* Retrieves a declared field from a class and makes it accessible.
* @param clazz The class of the method.
* @param field The field name.
* @return The specified field.
* @throws NoSuchFieldException iff field doesn't exist.
*/
public static Field getDeclaredField(Class<?> clazz, String field) throws NoSuchFieldException {
Field f = clazz.getDeclaredField(field);
f.setAccessible(true);
return f;
}
/**
* Retrieves a field from a class and makes it accessible.
* @param clazz The class of the method.
* @param field The field name.
* @return The specified field.
* @throws NoSuchFieldException iff field doesn't exist.
*/
public static Field getField(Class<?> clazz, String field) throws NoSuchFieldException {
Field f = clazz.getField(field);
f.setAccessible(true);
return f;
}
/**
* Retrieves a declared method from a class and makes it accessible.
* @param clazz The class of the method.
* @param method The method name.
* @param params The parameters of the method.
* @return The specified method.
* @throws NoSuchMethodException iff method doesn't exist.
*/
public static Method getDeclaredMethod(Class<?> clazz, String method, Class<?>... params)
throws NoSuchMethodException {
Method m = clazz.getDeclaredMethod(method, params);
m.setAccessible(true);
return m;
}
/**
* Retrieves a method from a class and makes it accessible.
* @param clazz The class of the method.
* @param method The method name.
* @param params The parameters of the method.
* @return The specified method.
* @throws NoSuchMethodException iff method doesn't exist.
*/
public static Method getMethod(Class<?> clazz, String method, Class<?>... params)
throws NoSuchMethodException {
Method m = clazz.getMethod(method, params);
m.setAccessible(true);
return m;
}
/**
* Retrieves fields from a class based on the specified FieldParams.
* @param clazz The class of the fields.
* @param fieldParams The fields which will be collected.
* @return A map with key the field name and value the actual field.
*/
public static Map<String, Field> getAllFields(Class<?> clazz, FieldParam... fieldParams) {
Map<String, Field> map = new HashMap<>();
for (FieldParam fieldParam : fieldParams) {
if (!getInstance().isCompatible(fieldParam.versionParam)) continue;
try {
map.put(fieldParam.field, getDeclaredField(clazz, fieldParam.field));
} catch (NoSuchFieldException ignored) {
try {
map.put(fieldParam.field, getField(clazz, fieldParam.field));
} catch (NoSuchFieldException ex) {
ex.printStackTrace();
}
}
}
return map;
}
/**
* Retrieves methods from a class based on the specified MethodParams.
* @param clazz The class of the methods.
* @param methodParams The methods which will be collected.
* @return A map with key the method name and value the actual method.
*/
public static Map<String, Method> getAllMethods(Class<?> clazz, MethodParam... methodParams) {
Map<String, Method> map = new HashMap<>();
for (MethodParam methodParam : methodParams) {
if (!getInstance().isCompatible(methodParam.versionParam)) continue;
try {
map.put(methodParam.method, getDeclaredMethod(clazz, methodParam.method, methodParam.params));
} catch (NoSuchMethodException ignored) {
try {
map.put(methodParam.method, getMethod(clazz, methodParam.method, methodParam.params));
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
}
}
return map;
}
/**
* Fetches all constructors by their parameter input.
* @param clazz The class to find constructors on.
* @param constructorParams The constructor parameters.
* @return The list of constructors.
*/
public static List<Constructor<?>> getAllConstructors(Class<?> clazz, ConstructorParam... constructorParams) {
List<Constructor<?>> constructors = new ArrayList<>();
for (ConstructorParam constructorParam : constructorParams) {
try {
constructors.add(clazz.getDeclaredConstructor(constructorParam.params));
} catch (NoSuchMethodException ignored) {
//
}
}
return constructors;
}
/**
* Invokes a method on an instance.
* Will return null if method not present in map.
* @param map The map with methods.
* @param instance The instance of the class.
* @param methodName The name of the method.
* @param params The parameters of the method.
* @return The object returned by the method, or null if not present in map.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/
public static Object invoke(Map<String, Method> map, Object instance, String methodName, Object... params)
throws InvocationTargetException, IllegalAccessException {
Method method = map.get(methodName);
if (method == null) return null;
return method.invoke(instance, params);
}
/**
* Retrieves the specified field from an object instance.
* Returns null if the field is not in the map.
* @param map The map with fields.
* @param instance The instance of the class.
* @param fieldName The field name.
* @throws IllegalAccessException When prohibited access to the field.
*/
public static Object get(Map<String, Field> map, Object instance, String fieldName) throws IllegalAccessException {
Field field = map.get(fieldName);
if (field == null) return null;
return field.get(instance);
}
/**
* Sets the specified field to the specified value.
* Will silently fail if the field is not in the map.
* @param map The map with fields.
* @param instance The instance of the class.
* @param fieldName The field name.
* @param value The value to set the field to.
* @throws IllegalAccessException When prohibited access to the field.
*/
public static void set(Map<String, Field> map, Object instance, String fieldName, Object value)
throws IllegalAccessException {
Field field = map.get(fieldName);
if (field == null) return;
field.set(instance, value);
}
}

View file

@ -1,74 +0,0 @@
package net.frankheijden.serverutils.common.reflection;
public class VersionParam {
public static final Version MIN_VERSION = new Version(Integer.MIN_VALUE, Integer.MIN_VALUE);
public static final Version MAX_VERSION = new Version(Integer.MAX_VALUE, Integer.MAX_VALUE);
public static final VersionParam ALL_VERSIONS = new VersionParam(MIN_VERSION, MAX_VERSION);
public final Version min;
public final Version max;
private VersionParam(int min, int max) {
this(min, Integer.MIN_VALUE, max, Integer.MAX_VALUE);
}
private VersionParam(int min, int minPatch, int max, int maxPatch) {
this(new Version(min, minPatch), new Version(max, maxPatch));
}
private VersionParam(Version min, Version max) {
this.min = min;
this.max = max;
}
public static VersionParam exact(int minor) {
return new VersionParam(minor, minor);
}
public static VersionParam exact(Version ver) {
return new VersionParam(ver, ver);
}
public static VersionParam between(int minMinor, int maxMinor) {
return new VersionParam(minMinor, maxMinor);
}
public static VersionParam between(Version min, Version max) {
return new VersionParam(min, max);
}
public static VersionParam min(int minMinor) {
return between(minMinor, Integer.MAX_VALUE);
}
public static VersionParam min(Version min) {
return between(min, MAX_VERSION);
}
public static VersionParam max(int maxMinor) {
return between(Integer.MIN_VALUE, maxMinor);
}
public static VersionParam max(Version max) {
return between(MIN_VERSION, max);
}
public static class Version {
public final int minor;
public final int patch;
public Version(int minor, int patch) {
this.minor = minor;
this.patch = patch;
}
public int getMinor() {
return minor;
}
public int getPatch() {
return patch;
}
}
}

View file

@ -4,6 +4,7 @@ plugins {
} }
group = 'net.frankheijden.serverutils' group = 'net.frankheijden.serverutils'
String dependencyDir = group + '.dependencies'
version = '2.2.4-DEV' version = '2.2.4-DEV'
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
@ -17,11 +18,14 @@ subprojects {
repositories { repositories {
mavenCentral() mavenCentral()
maven { url 'https://jitpack.io' }
maven { url 'https://repo.aikar.co/content/groups/aikar/' } maven { url 'https://repo.aikar.co/content/groups/aikar/' }
maven { url 'https://papermc.io/repo/repository/maven-public/' } maven { url 'https://papermc.io/repo/repository/maven-public/' }
} }
dependencies { dependencies {
implementation 'com.github.FrankHeijden:MinecraftReflection:1.0.0'
testCompile 'org.assertj:assertj-core:3.18.1' testCompile 'org.assertj:assertj-core:3.18.1'
testCompile 'org.junit.jupiter:junit-jupiter-api:5.7.0' testCompile 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0' testCompile 'org.junit.jupiter:junit-jupiter-params:5.7.0'
@ -60,4 +64,8 @@ dependencies {
implementation project(path: ':Bungee', configuration: 'shadow') implementation project(path: ':Bungee', configuration: 'shadow')
} }
shadowJar {
relocate 'dev.frankheijden.minecraftreflection', dependencyDir + '.minecraftreflection'
}
build.dependsOn shadowJar build.dependsOn shadowJar