diff --git a/pom.xml b/pom.xml index f8f23e8..955ed47 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ LWC LWC jar - 3.53 + 3.55 UTF-8 @@ -35,7 +35,7 @@ BOSEconomy 1.0 system - ${project.basedir}/lib/BOSEConomy.jar + ${project.basedir}/lib/BOSEconomy.jar com.earth2me.essentials @@ -157,4 +157,4 @@ - \ No newline at end of file + diff --git a/src/main/java/cb1060/RDEB.java b/src/main/java/cb1060/RDEB.java new file mode 100644 index 0000000..fc72d4b --- /dev/null +++ b/src/main/java/cb1060/RDEB.java @@ -0,0 +1,63 @@ +package cb1060; + + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.bukkit.Bukkit; + +import java.util.HashMap; +import java.util.Map; + +/** + * Recursion-Detection-Early-Break + * Because betajankā„¢ + */ +public class RDEB { + private static final int THRESHOLD = 10; + + private static final Map tracker = new HashMap<>(); + + public static void up() { + String k = key(getCaller()); + Integer v = tracker.get(k); + + if (v == null) { + v = 0; + } + + tracker.put(k, v + 1); + } + + public static void down() { + String k = key(getCaller()); + Integer v = tracker.get(k); + + if (v == null) { + v = 0; + } + + tracker.put(k, Math.max(0, v - 1)); + } + + public static boolean shouldBreak() { + String k = key(getCaller()); + Integer v = tracker.get(k); + + if (v == null || v < THRESHOLD) { + return false; + } + + tracker.remove(k); + + Bukkit.getLogger().severe("[RDEB_REPORT] Detected invalid recursion, please investigate!\n" + ExceptionUtils.getStackTrace(new Throwable())); + + return true; + } + + private static StackTraceElement getCaller() { + return Thread.currentThread().getStackTrace()[3]; + } + + private static String key(StackTraceElement element) { + return element.getClassName() + "::" + element.getMethodName() + "()"; + } +} diff --git a/src/main/java/com/griefcraft/listeners/LWCBlockListener.java b/src/main/java/com/griefcraft/listeners/LWCBlockListener.java index 932c98d..f1b6219 100644 --- a/src/main/java/com/griefcraft/listeners/LWCBlockListener.java +++ b/src/main/java/com/griefcraft/listeners/LWCBlockListener.java @@ -1,5 +1,6 @@ package com.griefcraft.listeners; +import cb1060.RDEB; import com.griefcraft.lwc.LWC; import com.griefcraft.lwc.LWCPlugin; import com.griefcraft.model.Protection; @@ -15,21 +16,48 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockListener; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.block.BlockRedstoneEvent; -import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.block.*; +import org.bukkit.material.Attachable; import org.bukkit.material.MaterialData; import org.bukkit.material.PistonBaseMaterial; +import java.util.*; + public class LWCBlockListener extends BlockListener { /** * The plugin instance */ private LWCPlugin plugin; + private Set attachmentsTopToCheck = new HashSet<>( + Arrays.asList( + Material.SAPLING, + Material.POWERED_RAIL, + Material.DETECTOR_RAIL, + Material.LONG_GRASS, + Material.DEAD_BUSH, + Material.YELLOW_FLOWER, + Material.RED_ROSE, + Material.BROWN_MUSHROOM, + Material.RED_MUSHROOM, + Material.TORCH, + Material.FIRE, + Material.REDSTONE_WIRE, + Material.SIGN_POST, + Material.WOODEN_DOOR, + Material.RAILS, + Material.LEVER, + Material.STONE_PLATE, + Material.IRON_DOOR_BLOCK, + Material.WOOD_PLATE, + Material.REDSTONE_TORCH_OFF, + Material.REDSTONE_TORCH_ON, + Material.SNOW, + Material.CACTUS, + Material.SUGAR_CANE_BLOCK, + Material.CAKE_BLOCK + ) + ); public LWCBlockListener(LWCPlugin plugin) { this.plugin = plugin; @@ -135,6 +163,58 @@ public void onBlockBreak(BlockBreakEvent event) { } } + @Override + public void onBlockPhysics(BlockPhysicsEvent event) { + RDEB.up(); + if (RDEB.shouldBreak()) { + event.setCancelled(true); + + return; + } + + try { + if (event.isCancelled()) { + return; + } + + if (!LWC.ENABLED) { + return; + } + + if (event.getBlock().getType() != Material.SAND && event.getBlock().getType() != Material.GRAVEL) { + return; + } + + LWC lwc = plugin.getLWC(); + Block upNeighbor = event.getBlock().getRelative(BlockFace.UP); + if (attachmentsTopToCheck.contains(upNeighbor.getType()) && lwc.findProtection(upNeighbor) != null) { + event.setCancelled(true); + + return; + } + + List horizontals = Arrays.asList( + BlockFace.NORTH, + BlockFace.EAST, + BlockFace.SOUTH, + BlockFace.WEST + ); + for (BlockFace face: horizontals) { + Block neighbor = event.getBlock().getRelative(face); + if (neighbor.getState() != null && (neighbor.getState().getData() instanceof Attachable)) { + Attachable data = (Attachable) neighbor.getState().getData(); + if (data.getAttachedFace() == face.getOppositeFace() && lwc.findProtection(neighbor) != null) { + event.setCancelled(true); + + return; + } + } + } + } finally { + RDEB.down(); + } + } + @Override public void onBlockPistonExtend(BlockPistonExtendEvent event) { if (!LWC.ENABLED) { diff --git a/src/main/java/com/griefcraft/listeners/LWCPlayerListener.java b/src/main/java/com/griefcraft/listeners/LWCPlayerListener.java index 18f3e79..0dd5b84 100644 --- a/src/main/java/com/griefcraft/listeners/LWCPlayerListener.java +++ b/src/main/java/com/griefcraft/listeners/LWCPlayerListener.java @@ -12,6 +12,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.ContainerBlock; import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.CraftWorld; @@ -26,9 +27,21 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; public class LWCPlayerListener extends PlayerListener { + private final Set invalidPrivates = new HashSet<>(Arrays.asList( + Material.AIR, + Material.WATER, + Material.STATIONARY_WATER, + Material.LAVA, + Material.STATIONARY_LAVA, + Material.SNOW, + Material.FIRE + )); /** * The plugin instance @@ -76,15 +89,32 @@ public void onPlayerChat(PlayerChatEvent event) { @Override public void onPlayerInteract(PlayerInteractEvent event) { - if (event.getAction() != Action.LEFT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_BLOCK) { + if (event.isCancelled()) { return; } + LWC lwc = plugin.getLWC(); + if (!LWC.ENABLED) { return; } - LWC lwc = plugin.getLWC(); + BlockFace face = event.getBlockFace(); + Block target = event.getClickedBlock(); + if (face != null) { + target = event.getClickedBlock().getRelative(face); + } + if (invalidPrivates.contains(target.getType())) { + Protection protection = lwc.findProtection(target); + if (protection != null) { + protection.remove(); + } + } + + if (event.getAction() != Action.LEFT_CLICK_BLOCK && event.getAction() != Action.RIGHT_CLICK_BLOCK) { + return; + } + Player player = event.getPlayer(); Block clickedBlock = event.getClickedBlock(); Location location = clickedBlock.getLocation(); diff --git a/src/main/java/com/griefcraft/lwc/LWCPlugin.java b/src/main/java/com/griefcraft/lwc/LWCPlugin.java index 126066d..84fc85c 100644 --- a/src/main/java/com/griefcraft/lwc/LWCPlugin.java +++ b/src/main/java/com/griefcraft/lwc/LWCPlugin.java @@ -399,6 +399,7 @@ private void registerEvents() { registerEvent(blockListener, Type.REDSTONE_CHANGE); registerEvent(blockListener, Type.SIGN_CHANGE); registerEvent(blockListener, Type.BLOCK_PISTON_EXTEND); + registerEvent(blockListener, Type.BLOCK_PHYSICS); /* Server events */ registerEvent(serverListener, Type.PLUGIN_DISABLE);