diff --git a/NEXT_RELEASE_CHANGELOG.md b/NEXT_RELEASE_CHANGELOG.md index 961302d5c..897194fa4 100644 --- a/NEXT_RELEASE_CHANGELOG.md +++ b/NEXT_RELEASE_CHANGELOG.md @@ -1 +1,2 @@ - Fix support for version before MC 1.16.5. +- Fixed a way to dupe the BigDoors stick. Thanks, 1Pootis1, for the bug report! diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java b/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java index 839c99fd1..e24e0bbab 100644 --- a/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java +++ b/core/src/main/java/nl/pim16aap2/bigDoors/BigDoors.java @@ -42,6 +42,7 @@ import nl.pim16aap2.bigDoors.handlers.EventHandlers; import nl.pim16aap2.bigDoors.handlers.FailureCommandHandler; import nl.pim16aap2.bigDoors.handlers.GUIHandler; +import nl.pim16aap2.bigDoors.handlers.GrindstoneListener; import nl.pim16aap2.bigDoors.handlers.LoginMessageHandler; import nl.pim16aap2.bigDoors.handlers.LoginResourcePackHandler; import nl.pim16aap2.bigDoors.handlers.RedstoneHandler; @@ -273,6 +274,7 @@ else if (config.unsafeModeNotification()) Bukkit.getPluginManager().registerEvents(new EventHandlers(this), this); Bukkit.getPluginManager().registerEvents(new GUIHandler(this), this); Bukkit.getPluginManager().registerEvents(new ChunkUnloadHandler(this), this); + GrindstoneListener.tryRegister(this); // No need to put these in init, as they should not be reloaded. pbCache = new TimedCache<>(config.cacheTimeout()); diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/handlers/EventHandlers.java b/core/src/main/java/nl/pim16aap2/bigDoors/handlers/EventHandlers.java index 9bbf198e4..b5c0d19e0 100644 --- a/core/src/main/java/nl/pim16aap2/bigDoors/handlers/EventHandlers.java +++ b/core/src/main/java/nl/pim16aap2/bigDoors/handlers/EventHandlers.java @@ -1,7 +1,9 @@ package nl.pim16aap2.bigDoors.handlers; -import java.text.MessageFormat; - +import nl.pim16aap2.bigDoors.BigDoors; +import nl.pim16aap2.bigDoors.Door; +import nl.pim16aap2.bigDoors.events.DoorEventToggleStart; +import nl.pim16aap2.bigDoors.toolUsers.ToolUser; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -20,10 +22,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.PlayerInventory; -import nl.pim16aap2.bigDoors.BigDoors; -import nl.pim16aap2.bigDoors.Door; -import nl.pim16aap2.bigDoors.events.DoorEventToggleStart; -import nl.pim16aap2.bigDoors.toolUsers.ToolUser; +import java.text.MessageFormat; public class EventHandlers implements Listener { diff --git a/core/src/main/java/nl/pim16aap2/bigDoors/handlers/GrindstoneListener.java b/core/src/main/java/nl/pim16aap2/bigDoors/handlers/GrindstoneListener.java new file mode 100644 index 000000000..ba3a66a88 --- /dev/null +++ b/core/src/main/java/nl/pim16aap2/bigDoors/handlers/GrindstoneListener.java @@ -0,0 +1,128 @@ +package nl.pim16aap2.bigDoors.handlers; + +import nl.pim16aap2.bigDoors.BigDoors; +import nl.pim16aap2.bigDoors.reflection.ReflectionBuilder; +import org.bukkit.Bukkit; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nullable; +import java.lang.reflect.Method; + +public class GrindstoneListener implements Listener +{ + private static final String EVENT_CLASS_NAME = "org.bukkit.event.inventory.PrepareGrindstoneEvent"; + + private final BigDoors bigDoors; + + GrindstoneListener(BigDoors bigDoors) + { + this.bigDoors = bigDoors; + } + + private boolean tryRegisterOnGrindstoneInventoryClick(GrindstoneListener listener) + { + final @Nullable InventoryType grindStoneInventoryType = (InventoryType) ReflectionBuilder.findEnumValues() + .inClass(InventoryType.class) + .withName("GRINDSTONE") + .setNullable() + .get(); + + // Grindstone inventory type was introduced in 1.14; clzPrepareGrindstoneEvent in 1.16. + if (grindStoneInventoryType == null) + return false; + + Bukkit.getPluginManager().registerEvent( + InventoryClickEvent.class, + listener, + EventPriority.HIGHEST, + (ignored, event) -> listener.onGrindstoneInventoryClick(event, grindStoneInventoryType), + bigDoors, + true + ); + + return true; + } + + @SuppressWarnings("unchecked") + private void tryRegisterOnPrepareGrindstone(GrindstoneListener listener) + { + final @Nullable Class clzPrepareGrindstoneEvent = (Class) ReflectionBuilder + .findClass() + .withNames(EVENT_CLASS_NAME) + .setNullable() + .get(); + if (clzPrepareGrindstoneEvent == null) + return; + + final @Nullable Method methodSetResult = ReflectionBuilder.findMethod() + .inClass(clzPrepareGrindstoneEvent) + .withName("setResult") + .withParameters(ItemStack.class) + .setNullable() + .get(); + if (methodSetResult == null) + return; + + + Bukkit.getPluginManager().registerEvent( + clzPrepareGrindstoneEvent, + listener, + EventPriority.HIGHEST, + (ignored, event) -> listener.onPrepareGrindstone(event, clzPrepareGrindstoneEvent, methodSetResult), + bigDoors, + true + ); + } + + public static void tryRegister(BigDoors bigDoors) + { + final GrindstoneListener listener = new GrindstoneListener(bigDoors); + + if (!listener.tryRegisterOnGrindstoneInventoryClick(listener)) + return; + + listener.tryRegisterOnPrepareGrindstone(listener); + } + + void onGrindstoneInventoryClick(Event event, InventoryType grindStoneInventoryType) + { + if (!(event instanceof InventoryClickEvent)) + return; + + final InventoryClickEvent ice = (InventoryClickEvent) event; + if (ice.getClickedInventory() == null) + return; + + if (ice.getClickedInventory().getType() != grindStoneInventoryType) + return; + + if (bigDoors.getTF().isTool(ice.getCurrentItem()) || bigDoors.getTF().isTool(ice.getCursor())) + ice.setCancelled(true); + } + + void onPrepareGrindstone(Event event, Class clzPrepareGrindstoneEvent, Method methodSetResult) + { + if (!clzPrepareGrindstoneEvent.isInstance(event)) + return; + + final Inventory inventory = ((InventoryEvent) event).getInventory(); + if (!bigDoors.getTF().isTool(inventory.getItem(0)) && !bigDoors.getTF().isTool(inventory.getItem(1))) + return; + + try + { + methodSetResult.invoke(event, (Object) null); + } + catch (ReflectiveOperationException exception) + { + bigDoors.getMyLogger().log(exception); + } + } +}