From c0d76d77f5e47dc7a8a2cb92395d49a0acbe8e15 Mon Sep 17 00:00:00 2001 From: Frank van der Heijden Date: Sun, 7 Jun 2020 12:40:14 +0200 Subject: [PATCH] Cleanup recipes for plugins in MC >= 1.12 --- .../serverutils/managers/PluginManager.java | 1 + .../reflection/RCraftingManager.java | 54 ++++++++++++++++++ .../serverutils/reflection/RMinecraftKey.java | 57 +++++++++++++++++++ .../reflection/RMinecraftServer.java | 29 ++++++++++ .../reflection/RRegistryMaterials.java | 40 +++++++++++++ .../reflection/RRegistrySimple.java | 38 +++++++++++++ .../serverutils/utils/MapUtils.java | 29 ++++++++++ 7 files changed, 248 insertions(+) create mode 100644 src/main/java/net/frankheijden/serverutils/reflection/RCraftingManager.java create mode 100644 src/main/java/net/frankheijden/serverutils/reflection/RMinecraftKey.java create mode 100644 src/main/java/net/frankheijden/serverutils/reflection/RMinecraftServer.java create mode 100644 src/main/java/net/frankheijden/serverutils/reflection/RRegistryMaterials.java create mode 100644 src/main/java/net/frankheijden/serverutils/reflection/RRegistrySimple.java create mode 100644 src/main/java/net/frankheijden/serverutils/utils/MapUtils.java diff --git a/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java b/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java index 53044b0..2c7fbd1 100644 --- a/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java +++ b/src/main/java/net/frankheijden/serverutils/managers/PluginManager.java @@ -47,6 +47,7 @@ public class PluginManager { Bukkit.getPluginManager().disablePlugin(plugin); RSimplePluginManager.getPlugins(Bukkit.getPluginManager()).remove(plugin); RSimplePluginManager.removeLookupName(Bukkit.getPluginManager(), plugin.getName()); + RCraftingManager.removeRecipesFor(plugin); } catch (Exception ex) { ex.printStackTrace(); return Result.ERROR; diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RCraftingManager.java b/src/main/java/net/frankheijden/serverutils/reflection/RCraftingManager.java new file mode 100644 index 0000000..5ba2bf4 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RCraftingManager.java @@ -0,0 +1,54 @@ +package net.frankheijden.serverutils.reflection; + +import net.frankheijden.serverutils.utils.MapUtils; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.*; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.*; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.min; + +public class RCraftingManager { + + private static Class craftingManagerClass; + private static Map fields; + + static { + try { + craftingManagerClass = Class.forName(String.format("net.minecraft.server.%s.CraftingManager", ReflectionUtils.NMS)); + fields = getAllFields(craftingManagerClass, + fieldOf("recipes", min(12))); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static void removeRecipesFor(Plugin plugin) throws IllegalAccessException, InvocationTargetException { + // Cleaning up recipes before MC 1.12 is not possible, + // as recipes are not associated to plugins. + if (MINOR < 12) return; + + Field recipesField = fields.get("recipes"); + + if (MINOR == 12) { + Object recipes = get(fields, null, "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); + + if (MINOR == 13) { + MapUtils.removeKeys(recipes, RMinecraftKey.matchingPluginPredicate(new AtomicBoolean(false), plugin)); + } else { + Collection list = (Collection) recipes.values(); + list.forEach(map -> MapUtils.removeKeys(map, RMinecraftKey.matchingPluginPredicate(new AtomicBoolean(false), plugin))); + } + } + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RMinecraftKey.java b/src/main/java/net/frankheijden/serverutils/reflection/RMinecraftKey.java new file mode 100644 index 0000000..4bd90fa --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RMinecraftKey.java @@ -0,0 +1,57 @@ +package net.frankheijden.serverutils.reflection; + +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Field; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.*; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.get; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllFields; + +public class RMinecraftKey { + + private static Class minecraftKeyClass; + private static Map fields; + + static { + try { + minecraftKeyClass = Class.forName(String.format("net.minecraft.server.%s.MinecraftKey", ReflectionUtils.NMS)); + fields = getAllFields(minecraftKeyClass, + fieldOf("a", max(13)), + fieldOf("namespace", min(14))); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static String getNameSpace(Object instance) throws IllegalAccessException { + if (ReflectionUtils.MINOR <= 13) { + return (String) get(fields, instance, "a"); + } + return (String) get(fields, instance, "namespace"); + } + + public static boolean isFrom(Object instance, Plugin plugin) throws IllegalAccessException { + String namespace = plugin.getName().toLowerCase(Locale.ROOT); + return namespace.equalsIgnoreCase(getNameSpace(instance)); + } + + public static Predicate matchingPluginPredicate(AtomicBoolean errorThrown, Plugin plugin) { + return o -> { + try { + return RMinecraftKey.isFrom(o, plugin); + } catch (IllegalAccessException ex) { + if (!errorThrown.get()) { + ex.printStackTrace(); + errorThrown.set(true); + } + } + return false; + }; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RMinecraftServer.java b/src/main/java/net/frankheijden/serverutils/reflection/RMinecraftServer.java new file mode 100644 index 0000000..4d1e214 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RMinecraftServer.java @@ -0,0 +1,29 @@ +package net.frankheijden.serverutils.reflection; + +import java.lang.reflect.Method; +import java.util.Map; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.MethodParam.methodOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllMethods; + +public class RMinecraftServer { + + private static Class minecraftServerClass; + private static Map methods; + + static { + try { + minecraftServerClass = Class.forName(String.format("net.minecraft.server.%s.MinecraftServer", ReflectionUtils.NMS)); + methods = getAllMethods(minecraftServerClass, + methodOf("getServer", ALL_VERSIONS), + methodOf("getCraftingManager", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static Map getMethods() { + return methods; + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RRegistryMaterials.java b/src/main/java/net/frankheijden/serverutils/reflection/RRegistryMaterials.java new file mode 100644 index 0000000..928c81a --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RRegistryMaterials.java @@ -0,0 +1,40 @@ +package net.frankheijden.serverutils.reflection; + +import net.frankheijden.serverutils.utils.MapUtils; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.get; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllFields; + +public class RRegistryMaterials { + + private static Class registryMaterialsClass; + + private static Map fields; + + static { + try { + registryMaterialsClass = Class.forName(String.format("net.minecraft.server.%s.RegistryMaterials", ReflectionUtils.NMS)); + fields = getAllFields(registryMaterialsClass, + fieldOf("b", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @SuppressWarnings("rawtypes") + public static void removeKeysFor(Object instance, Plugin plugin) throws IllegalAccessException { + Map map = (Map) get(fields, instance, "b"); + if (map == null) throw new RuntimeException("Map object was null!"); + + AtomicBoolean errorThrown = new AtomicBoolean(false); + MapUtils.removeValues(map, RMinecraftKey.matchingPluginPredicate(errorThrown, plugin)); + RRegistrySimple.removeKeyFor(instance, plugin); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/reflection/RRegistrySimple.java b/src/main/java/net/frankheijden/serverutils/reflection/RRegistrySimple.java new file mode 100644 index 0000000..4cb12a0 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/reflection/RRegistrySimple.java @@ -0,0 +1,38 @@ +package net.frankheijden.serverutils.reflection; + +import net.frankheijden.serverutils.utils.MapUtils; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Field; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static net.frankheijden.serverutils.reflection.ReflectionUtils.FieldParam.fieldOf; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.VersionParam.ALL_VERSIONS; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.get; +import static net.frankheijden.serverutils.reflection.ReflectionUtils.getAllFields; + +public class RRegistrySimple { + + private static Class registrySimpleClass; + private static Map fields; + + static { + try { + registrySimpleClass = Class.forName(String.format("net.minecraft.server.%s.RegistrySimple", ReflectionUtils.NMS)); + fields = getAllFields(registrySimpleClass, + fieldOf("c", ALL_VERSIONS)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + @SuppressWarnings("rawtypes") + public static void removeKeyFor(Object instance, Plugin plugin) throws IllegalAccessException { + Map map = (Map) get(fields, instance, "c"); + if (map == null) throw new RuntimeException("Map object was null!"); + + AtomicBoolean errorThrown = new AtomicBoolean(false); + MapUtils.removeKeys(map, RMinecraftKey.matchingPluginPredicate(errorThrown, plugin)); + } +} diff --git a/src/main/java/net/frankheijden/serverutils/utils/MapUtils.java b/src/main/java/net/frankheijden/serverutils/utils/MapUtils.java new file mode 100644 index 0000000..f7f04d2 --- /dev/null +++ b/src/main/java/net/frankheijden/serverutils/utils/MapUtils.java @@ -0,0 +1,29 @@ +package net.frankheijden.serverutils.utils; + +import java.util.*; +import java.util.function.Predicate; + +public class MapUtils { + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static void removeKeys(Map map, Predicate predicate) { + Set keysToRemove = new HashSet<>(); + map.forEach((k, v) -> { + if (predicate.test(k)) { + keysToRemove.add(k); + } + }); + keysToRemove.forEach(map::remove); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static void removeValues(Map map, Predicate predicate) { + Set keysToRemove = new HashSet<>(); + map.forEach((k, v) -> { + if (predicate.test(v)) { + keysToRemove.add(k); + } + }); + keysToRemove.forEach(map::remove); + } +}