From b87bed54e073897cd18a7e81f06a904922edb3b8 Mon Sep 17 00:00:00 2001 From: Aleksander Jagiello Date: Mon, 30 Aug 2021 22:08:23 +0200 Subject: [PATCH] 1.17.1 support --- .../pl/craftserve/radiation/Radiation.java | 16 ++- .../radiation/RadiationCommandHandler.java | 20 ++-- .../craftserve/radiation/RadiationPlugin.java | 7 +- .../radiation/nms/RadiationNmsBridge.java | 3 + .../radiation/nms/V1_14ToV1_15NmsBridge.java | 6 ++ .../radiation/nms/V1_17_R1NmsBridge.java | 102 ++++++++++++++++++ 6 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 src/main/java/pl/craftserve/radiation/nms/V1_17_R1NmsBridge.java diff --git a/src/main/java/pl/craftserve/radiation/Radiation.java b/src/main/java/pl/craftserve/radiation/Radiation.java index 2047ec8..1ad0a56 100644 --- a/src/main/java/pl/craftserve/radiation/Radiation.java +++ b/src/main/java/pl/craftserve/radiation/Radiation.java @@ -28,6 +28,7 @@ import com.sk89q.worldguard.protection.regions.RegionContainer; import org.bukkit.ChatColor; import org.bukkit.Server; +import org.bukkit.World; import org.bukkit.boss.BossBar; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; @@ -42,6 +43,7 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; +import pl.craftserve.radiation.nms.RadiationNmsBridge; import java.text.MessageFormat; import java.util.ArrayList; @@ -54,7 +56,6 @@ import java.util.Set; import java.util.UUID; import java.util.function.Predicate; -import java.util.logging.Level; import java.util.logging.Logger; public class Radiation implements Listener { @@ -228,11 +229,13 @@ default RegionContainer getRegionContainer() { * Tests if the given flags matches the radiation IDs. */ public static class FlagMatcher implements WorldGuardMatcher { + private final RadiationNmsBridge nmsBridge; private final Flag isRadioactiveFlag; private final Flag radiationTypeFlag; private final Set acceptedRadiationTypes; - public FlagMatcher(Flag isRadioactiveFlag, Flag radiationTypeFlag, Set acceptedRadiationTypes) { + public FlagMatcher(RadiationNmsBridge nmsBridge, Flag isRadioactiveFlag, Flag radiationTypeFlag, Set acceptedRadiationTypes) { + this.nmsBridge = Objects.requireNonNull(nmsBridge, "nmsBridge"); this.isRadioactiveFlag = Objects.requireNonNull(isRadioactiveFlag, "isRadioactiveFlag"); this.radiationTypeFlag = Objects.requireNonNull(radiationTypeFlag, "radiationTypeFlag"); this.acceptedRadiationTypes = Objects.requireNonNull(acceptedRadiationTypes, "acceptedRadiationTypes"); @@ -240,8 +243,13 @@ public FlagMatcher(Flag isRadioactiveFlag, Flag radiationTypeFl @Override public boolean test(Player player, RegionContainer regionContainer) { - Location location = BukkitAdapter.adapt(player.getLocation()); - location = location.setY(Math.max(0, Math.min(255, location.getY()))); + org.bukkit.Location bukkitLocation = player.getLocation(); + World world = player.getWorld(); + int minY = this.nmsBridge.getMinWorldHeight(world); + int maxY = world.getMaxHeight(); + + Location location = BukkitAdapter.adapt(bukkitLocation); + location = location.setY(Math.max(minY, Math.min(maxY, location.getY()))); ApplicableRegionSet regions = regionContainer.createQuery().getApplicableRegions(location); LocalPlayer localPlayer = WorldGuardPlugin.inst().wrapPlayer(player); diff --git a/src/main/java/pl/craftserve/radiation/RadiationCommandHandler.java b/src/main/java/pl/craftserve/radiation/RadiationCommandHandler.java index d9be66f..8c24a4c 100644 --- a/src/main/java/pl/craftserve/radiation/RadiationCommandHandler.java +++ b/src/main/java/pl/craftserve/radiation/RadiationCommandHandler.java @@ -37,6 +37,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import pl.craftserve.radiation.nms.RadiationNmsBridge; import java.util.Collections; import java.util.List; @@ -49,13 +50,15 @@ public class RadiationCommandHandler implements CommandExecutor, TabCompleter { private static final String REGION_ID = "safe_from_radiation"; private static final String GLOBAL_REGION_ID = "__global__"; + private RadiationNmsBridge nmsBridge; private final Flag flag; private final Radiation.WorldGuardMatcher worldGuardMatcher = (player, regionContainer) -> { throw new UnsupportedOperationException(); }; private final LugolsIodinePotion potion; - public RadiationCommandHandler(Flag flag, LugolsIodinePotion potion) { + public RadiationCommandHandler(RadiationNmsBridge nmsBridge, Flag flag, LugolsIodinePotion potion) { + this.nmsBridge = Objects.requireNonNull(nmsBridge, "nmsBridge"); this.flag = Objects.requireNonNull(flag, "flag"); this.potion = potion; } @@ -135,7 +138,8 @@ private boolean define(Player player, RegionContainer container, String regionId Objects.requireNonNull(container, "container"); Objects.requireNonNull(regionId, "regionId"); - World world = BukkitAdapter.adapt(player.getWorld()); + org.bukkit.World bukkitWorld = player.getWorld(); + World world = BukkitAdapter.adapt(bukkitWorld); RegionManager regionManager = container.get(world); if (regionManager == null) { player.sendMessage(ChatColor.RED + "Sorry, region manager for world " + world.getName() + " is not currently accessible."); @@ -143,17 +147,21 @@ private boolean define(Player player, RegionContainer container, String regionId } BlockVector3 origin = BukkitAdapter.asBlockVector(player.getLocation()); - this.define(regionManager, this.createCuboid(regionId, origin, radius)); + this.define(regionManager, this.createCuboid(bukkitWorld, regionId, origin, radius)); this.flagGlobal(regionManager, true); return true; } - private ProtectedCuboidRegion createCuboid(String regionId, BlockVector3 origin, int radius) { + private ProtectedCuboidRegion createCuboid(org.bukkit.World bukkitWorld, String regionId, BlockVector3 origin, int radius) { + Objects.requireNonNull(bukkitWorld, "bukkitWorld"); Objects.requireNonNull(regionId, "regionId"); Objects.requireNonNull(origin, "origin"); - BlockVector3 min = origin.subtract(radius, 0, radius).withY(0); - BlockVector3 max = origin.add(radius, 0, radius).withY(255); + int minY = this.nmsBridge.getMinWorldHeight(bukkitWorld); + int maxY = bukkitWorld.getMaxHeight(); + + BlockVector3 min = origin.subtract(radius, 0, radius).withY(minY); + BlockVector3 max = origin.add(radius, 0, radius).withY(maxY); return new ProtectedCuboidRegion(regionId, min, max); } diff --git a/src/main/java/pl/craftserve/radiation/RadiationPlugin.java b/src/main/java/pl/craftserve/radiation/RadiationPlugin.java index 47c940d..5d120cb 100644 --- a/src/main/java/pl/craftserve/radiation/RadiationPlugin.java +++ b/src/main/java/pl/craftserve/radiation/RadiationPlugin.java @@ -39,6 +39,7 @@ import org.bukkit.plugin.java.JavaPlugin; import pl.craftserve.radiation.nms.RadiationNmsBridge; import pl.craftserve.radiation.nms.V1_14ToV1_15NmsBridge; +import pl.craftserve.radiation.nms.V1_17_R1NmsBridge; import java.util.ArrayList; import java.util.Collections; @@ -92,6 +93,8 @@ private RadiationNmsBridge initializeNmsBridge() { case "v1_16_R2": case "v1_16_R3": return new V1_14ToV1_15NmsBridge(serverVersion); + case "v1_17_R1": + return new V1_17_R1NmsBridge(serverVersion); default: throw new RuntimeException("Unsupported server version: " + serverVersion); } @@ -149,12 +152,12 @@ public void onEnable() { for (Radiation.Config radiationConfig : this.config.radiations()) { String id = radiationConfig.id(); - Radiation.Matcher matcher = new Radiation.FlagMatcher(this.radiationFlag, this.radiationTypeFlag, Collections.singleton(id)); + Radiation.Matcher matcher = new Radiation.FlagMatcher(this.radiationNmsBridge, this.radiationFlag, this.radiationTypeFlag, Collections.singleton(id)); this.activeRadiations.put(id, new Radiation(this, matcher, radiationConfig)); } - RadiationCommandHandler radiationCommandHandler = new RadiationCommandHandler(this.radiationFlag, this.potion); + RadiationCommandHandler radiationCommandHandler = new RadiationCommandHandler(this.radiationNmsBridge, this.radiationFlag, this.potion); radiationCommandHandler.register(this.getCommand("radiation")); this.craftserveListener = new CraftserveListener(this); diff --git a/src/main/java/pl/craftserve/radiation/nms/RadiationNmsBridge.java b/src/main/java/pl/craftserve/radiation/nms/RadiationNmsBridge.java index 60f10e6..b4f25f0 100644 --- a/src/main/java/pl/craftserve/radiation/nms/RadiationNmsBridge.java +++ b/src/main/java/pl/craftserve/radiation/nms/RadiationNmsBridge.java @@ -19,6 +19,7 @@ import org.bukkit.NamespacedKey; import org.bukkit.Server; import org.apache.commons.lang.StringUtils; +import org.bukkit.World; import pl.craftserve.radiation.LugolsIodinePotion; import java.util.Objects; @@ -28,6 +29,8 @@ public interface RadiationNmsBridge { void unregisterLugolsIodinePotion(NamespacedKey potionKey); + int getMinWorldHeight(World bukkitWorld); + static String getServerVersion(Server server) { Objects.requireNonNull(server, "server"); diff --git a/src/main/java/pl/craftserve/radiation/nms/V1_14ToV1_15NmsBridge.java b/src/main/java/pl/craftserve/radiation/nms/V1_14ToV1_15NmsBridge.java index 6509c10..5f35544 100644 --- a/src/main/java/pl/craftserve/radiation/nms/V1_14ToV1_15NmsBridge.java +++ b/src/main/java/pl/craftserve/radiation/nms/V1_14ToV1_15NmsBridge.java @@ -18,6 +18,7 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; +import org.bukkit.World; import pl.craftserve.radiation.LugolsIodinePotion; import java.lang.reflect.Array; @@ -107,4 +108,9 @@ public void registerLugolsIodinePotion(NamespacedKey potionKey, LugolsIodinePoti public void unregisterLugolsIodinePotion(NamespacedKey potionKey) { // todo unregister potion and brewing recipe } + + @Override + public int getMinWorldHeight(World bukkitWorld) { + return 0; + } } diff --git a/src/main/java/pl/craftserve/radiation/nms/V1_17_R1NmsBridge.java b/src/main/java/pl/craftserve/radiation/nms/V1_17_R1NmsBridge.java new file mode 100644 index 0000000..bc8988f --- /dev/null +++ b/src/main/java/pl/craftserve/radiation/nms/V1_17_R1NmsBridge.java @@ -0,0 +1,102 @@ +package pl.craftserve.radiation.nms; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import pl.craftserve.radiation.LugolsIodinePotion; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class V1_17_R1NmsBridge implements RadiationNmsBridge { + static final Logger logger = Logger.getLogger(V1_17_R1NmsBridge.class.getName()); + + private final Class itemClass; + private final Class iRegistryClass; + private final Class mobEffectClass; + private final Class potionRegistryClass; + private final Class potionBrewerClass; + + private final Method getItem; + private final Method newMinecraftKey; + private final Method getPotion; + private final Method minHeightMethod; + + private final Object potionRegistry; + + private final Map minWorldHeightMap = new HashMap<>(); + + public V1_17_R1NmsBridge(String version) { + Objects.requireNonNull(version, "version"); + + try { + this.itemClass = Class.forName("net.minecraft.world.item.Item"); + this.iRegistryClass = Class.forName("net.minecraft.core.IRegistry"); + this.mobEffectClass = Class.forName("net.minecraft.world.effect.MobEffect"); + this.potionRegistryClass = Class.forName("net.minecraft.world.item.alchemy.PotionRegistry"); + this.potionBrewerClass = Class.forName("net.minecraft.world.item.alchemy.PotionBrewer"); + + Class craftMagicNumbers = Class.forName("org.bukkit.craftbukkit." + version + ".util.CraftMagicNumbers"); + this.getItem = craftMagicNumbers.getMethod("getItem", Material.class); + this.minHeightMethod = World.class.getMethod("getMinHeight"); + + Class minecraftKey = Class.forName("net.minecraft.resources.MinecraftKey"); + this.newMinecraftKey = minecraftKey.getMethod("a", String.class); + this.potionRegistry = this.iRegistryClass.getDeclaredField("aa").get(null); + this.getPotion = this.potionRegistry.getClass().getMethod("get", minecraftKey); + } catch (Exception e) { + throw new RuntimeException("Failed to initialize 1.17.1 bridge", e); + } + } + + @Override + public void registerLugolsIodinePotion(NamespacedKey potionKey, LugolsIodinePotion.Config.Recipe config) { + Objects.requireNonNull(potionKey, "potionKey"); + Objects.requireNonNull(config, "config"); + + try { + String basePotionName = config.basePotion().name().toLowerCase(Locale.ROOT); + Object basePotion = this.getPotion.invoke(this.potionRegistry, this.newMinecraftKey.invoke(null, basePotionName)); + Object ingredient = this.getItem.invoke(null, config.ingredient()); + + Object mobEffectArray = Array.newInstance(this.mobEffectClass, 0); + Object newPotion = this.potionRegistryClass.getConstructor(mobEffectArray.getClass()).newInstance(mobEffectArray); + + Method registerMethod = this.iRegistryClass.getDeclaredMethod("a", this.iRegistryClass, String.class, Object.class); + Object potion = registerMethod.invoke(null, this.potionRegistry, potionKey.getKey(), newPotion); + + Method registerBrewingRecipe = this.potionBrewerClass.getDeclaredMethod("a", this.potionRegistryClass, this.itemClass, this.potionRegistryClass); + registerBrewingRecipe.setAccessible(true); + registerBrewingRecipe.invoke(null, basePotion, ingredient, potion); + } catch (Exception e) { + logger.log(Level.SEVERE, "Could not handle reflective operation.", e); + } + } + + @Override + public void unregisterLugolsIodinePotion(NamespacedKey potionKey) { + // todo unregister potion and brewing recipe + } + + @Override + public int getMinWorldHeight(World bukkitWorld) { + Objects.requireNonNull(bukkitWorld, "bukkitWorld"); + + return this.minWorldHeightMap.computeIfAbsent(bukkitWorld.getUID(), worldId -> { + try { + return (int) this.minHeightMethod.invoke(bukkitWorld); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.log(Level.SEVERE, "Could not handle min world height on world '" + bukkitWorld.getName() + "' ('" + worldId + "').", e); + return 0; + } + }); + } +}