From c098171759f68f58954e7135ab35b3211e961253 Mon Sep 17 00:00:00 2001 From: Olof Larsson Date: Thu, 18 Apr 2013 14:02:39 +0200 Subject: [PATCH] Decouple and put all exploit fixes in their own listener. --- src/com/massivecraft/factions/Factions.java | 13 +- .../listeners/FactionsEntityListener.java | 29 +-- .../listeners/FactionsExploitListener.java | 68 ------- .../listeners/FactionsListenerExploit.java | 191 ++++++++++++++++++ .../FactionsListenerMain.java} | 17 +- .../listeners/FactionsPlayerListener.java | 41 ---- 6 files changed, 212 insertions(+), 147 deletions(-) delete mode 100644 src/com/massivecraft/factions/listeners/FactionsExploitListener.java create mode 100644 src/com/massivecraft/factions/listeners/FactionsListenerExploit.java rename src/com/massivecraft/factions/{MainListener.java => listeners/FactionsListenerMain.java} (92%) diff --git a/src/com/massivecraft/factions/Factions.java b/src/com/massivecraft/factions/Factions.java index debd0922..ac1b0107 100644 --- a/src/com/massivecraft/factions/Factions.java +++ b/src/com/massivecraft/factions/Factions.java @@ -14,7 +14,8 @@ import com.massivecraft.factions.integration.SpoutFeatures; import com.massivecraft.factions.integration.Worldguard; import com.massivecraft.factions.listeners.FactionsChatListener; import com.massivecraft.factions.listeners.FactionsEntityListener; -import com.massivecraft.factions.listeners.FactionsExploitListener; +import com.massivecraft.factions.listeners.FactionsListenerExploit; +import com.massivecraft.factions.listeners.FactionsListenerMain; import com.massivecraft.factions.listeners.FactionsPlayerListener; import com.massivecraft.factions.task.AutoLeaveTask; import com.massivecraft.factions.task.EconLandRewardTask; @@ -45,7 +46,6 @@ public class Factions extends MPlugin public FactionsPlayerListener playerListener; public FactionsChatListener chatListener; public FactionsEntityListener entityListener; - public FactionsExploitListener exploitListener; // -------------------------------------------- // // OVERRIDE @@ -83,8 +83,12 @@ public class Factions extends MPlugin EconLandRewardTask.get().schedule(this); // Register Event Handlers - MainListener.get().setup(); + FactionsListenerMain.get().setup(); + // TODO: Chat goes here + FactionsListenerExploit.get().setup(); + + // TODO: Get rid of these this.playerListener = new FactionsPlayerListener(); getServer().getPluginManager().registerEvents(this.playerListener, this); @@ -94,8 +98,7 @@ public class Factions extends MPlugin this.entityListener = new FactionsEntityListener(); getServer().getPluginManager().registerEvents(this.entityListener, this); - this.exploitListener = new FactionsExploitListener(); - getServer().getPluginManager().registerEvents(this.exploitListener, this); + postEnable(); } diff --git a/src/com/massivecraft/factions/listeners/FactionsEntityListener.java b/src/com/massivecraft/factions/listeners/FactionsEntityListener.java index 98a6934a..a33d99dd 100644 --- a/src/com/massivecraft/factions/listeners/FactionsEntityListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsEntityListener.java @@ -1,11 +1,9 @@ package com.massivecraft.factions.listeners; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; import org.bukkit.Bukkit; @@ -16,7 +14,6 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; -import org.bukkit.entity.TNTPrimed; import org.bukkit.entity.Wither; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -88,7 +85,7 @@ public class FactionsEntityListener implements Listener final String msg = powerLossEvent.getMessage(); if (msg != null && !msg.isEmpty()) { - fplayer.msg(msg,fplayer.getPowerRounded(),fplayer.getPowerMaxRounded()); + fplayer.msg(msg, fplayer.getPowerRounded(), fplayer.getPowerMaxRounded()); } } @@ -127,30 +124,6 @@ public class FactionsEntityListener implements Listener event.setCancelled(true); return; } - - - // TNT in water/lava doesn't normally destroy any surrounding blocks, which is usually desired behavior, but... - // this optional change below provides workaround for waterwalling providing perfect protection, - // and makes cheap (non-obsidian) TNT cannons require minor maintenance between shots - Block center = event.getLocation().getBlock(); - if (event.getEntity() instanceof TNTPrimed && ConfServer.handleExploitTNTWaterlog && center.isLiquid()) - { - // a single surrounding block in all 6 directions is broken if the material is weak enough - List targets = new ArrayList(); - targets.add(center.getRelative(0, 0, 1)); - targets.add(center.getRelative(0, 0, -1)); - targets.add(center.getRelative(0, 1, 0)); - targets.add(center.getRelative(0, -1, 0)); - targets.add(center.getRelative(1, 0, 0)); - targets.add(center.getRelative(-1, 0, 0)); - for (Block target : targets) - { - int id = target.getTypeId(); - // ignore air, bedrock, water, lava, obsidian, enchanting table, etc.... too bad we can't get a blast resistance value through Bukkit yet - if (id != 0 && (id < 7 || id > 11) && id != 49 && id != 90 && id != 116 && id != 119 && id != 120 && id != 130) - target.breakNaturally(); - } - } } // mainly for flaming arrows; don't want allies or people in safe zones to be ignited even after damage event is cancelled diff --git a/src/com/massivecraft/factions/listeners/FactionsExploitListener.java b/src/com/massivecraft/factions/listeners/FactionsExploitListener.java deleted file mode 100644 index f115557d..00000000 --- a/src/com/massivecraft/factions/listeners/FactionsExploitListener.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.massivecraft.factions.listeners; - -import org.bukkit.block.Block; -import org.bukkit.event.block.BlockFromToEvent; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.Location; -import org.bukkit.Material; - -import com.massivecraft.factions.ConfServer; - - -public class FactionsExploitListener implements Listener -{ - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void obsidianGenerator(BlockFromToEvent event) - { - if (!ConfServer.handleExploitObsidianGenerators) return; - - // thanks to ObGenBlocker and WorldGuard for this method - Block block = event.getToBlock(); - int source = event.getBlock().getTypeId(); - int target = block.getTypeId(); - if ((target == 55 || target == 132) && (source == 0 || source == 10 || source == 11)) - block.setTypeId(0); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void enderPearlTeleport(PlayerTeleportEvent event) - { - if (!ConfServer.handleExploitEnderPearlClipping) return; - if (event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) return; - - // this exploit works when the target location is within 0.31 blocks or so of a door or glass block or similar... - Location target = event.getTo(); - Location from = event.getFrom(); - - // blocks who occupy less than 1 block width or length wise need to be handled differently - Material mat = event.getTo().getBlock().getType(); - if ( - ((mat == Material.THIN_GLASS || mat == Material.IRON_FENCE) && clippingThrough(target, from, 0.65)) - || ((mat == Material.FENCE || mat == Material.NETHER_FENCE) && clippingThrough(target, from, 0.45)) - ) - { - event.setTo(from); - return; - } - - // simple fix otherwise: ender pearl target locations are standardized to be in the center (X/Z) of the target block, not at the edges - target.setX(target.getBlockX() + 0.5); - target.setZ(target.getBlockZ() + 0.5); - event.setTo(target); - - } - - public static boolean clippingThrough(Location target, Location from, double thickness) - { - return - ( - (from.getX() > target.getX() && (from.getX() - target.getX() < thickness)) - || (target.getX() > from.getX() && (target.getX() - from.getX() < thickness)) - || (from.getZ() > target.getZ() && (from.getZ() - target.getZ() < thickness)) - || (target.getZ() > from.getZ() && (target.getZ() - from.getZ() < thickness)) - ); - } -} diff --git a/src/com/massivecraft/factions/listeners/FactionsListenerExploit.java b/src/com/massivecraft/factions/listeners/FactionsListenerExploit.java new file mode 100644 index 00000000..c61970cb --- /dev/null +++ b/src/com/massivecraft/factions/listeners/FactionsListenerExploit.java @@ -0,0 +1,191 @@ +package com.massivecraft.factions.listeners; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.util.NumberConversions; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; + +import com.massivecraft.factions.ConfServer; +import com.massivecraft.factions.Factions; +import com.massivecraft.mcore.util.SenderUtil; +import com.massivecraft.mcore.util.Txt; + + +public class FactionsListenerExploit implements Listener +{ + // -------------------------------------------- // + // INSTANCE & CONSTRUCT + // -------------------------------------------- // + + private static FactionsListenerExploit i = new FactionsListenerExploit(); + public static FactionsListenerExploit get() { return i; } + + // -------------------------------------------- // + // SETUP + // -------------------------------------------- // + + public void setup() + { + Bukkit.getPluginManager().registerEvents(this, Factions.get()); + } + + // -------------------------------------------- // + // INTERACT SPAM + // -------------------------------------------- // + // TODO: Now that I decoupled this one it may be to sensitive. + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void interactSpam(PlayerInteractEvent event) + { + if (!ConfServer.handleExploitInteractionSpam) return; + + Player player = event.getPlayer(); + String playerId = SenderUtil.getSenderId(player); + + InteractAttemptSpam attempt = interactSpammers.get(playerId); + if (attempt == null) + { + attempt = new InteractAttemptSpam(); + interactSpammers.put(playerId, attempt); + } + + int count = attempt.increment(); + if (count >= 10) + { + player.sendMessage(Txt.parse("Ouch, that is starting to hurt. You should give it a rest.")); + player.damage(NumberConversions.floor((double)count / 10)); + } + } + + // for handling people who repeatedly spam attempts to open a door (or similar) in another faction's territory + private Map interactSpammers = new HashMap(); + private static class InteractAttemptSpam + { + private int attempts = 0; + private long lastAttempt = System.currentTimeMillis(); + + // returns the current attempt count + public int increment() + { + long Now = System.currentTimeMillis(); + if (Now > lastAttempt + 2000) + attempts = 1; + else + attempts++; + lastAttempt = Now; + return attempts; + } + } + + // -------------------------------------------- // + // OBSIDIAN GENERATORS + // -------------------------------------------- // + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void obsidianGenerators(BlockFromToEvent event) + { + if (!ConfServer.handleExploitObsidianGenerators) return; + + // thanks to ObGenBlocker and WorldGuard for this method + Block block = event.getToBlock(); + int source = event.getBlock().getTypeId(); + int target = block.getTypeId(); + if ((target == 55 || target == 132) && (source == 0 || source == 10 || source == 11)) + { + block.setTypeId(0); + } + } + + // -------------------------------------------- // + // ENDER PEARL CLIPPING + // -------------------------------------------- // + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void enderPearlClipping(PlayerTeleportEvent event) + { + if (!ConfServer.handleExploitEnderPearlClipping) return; + if (event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) return; + + // this exploit works when the target location is within 0.31 blocks or so of a door or glass block or similar... + Location target = event.getTo(); + Location from = event.getFrom(); + + // blocks who occupy less than 1 block width or length wise need to be handled differently + Material mat = event.getTo().getBlock().getType(); + if ( + ((mat == Material.THIN_GLASS || mat == Material.IRON_FENCE) && clippingThrough(target, from, 0.65)) + || ((mat == Material.FENCE || mat == Material.NETHER_FENCE) && clippingThrough(target, from, 0.45)) + ) + { + event.setTo(from); + return; + } + + // simple fix otherwise: ender pearl target locations are standardized to be in the center (X/Z) of the target block, not at the edges + target.setX(target.getBlockX() + 0.5); + target.setZ(target.getBlockZ() + 0.5); + event.setTo(target); + + } + + public static boolean clippingThrough(Location target, Location from, double thickness) + { + return + ( + (from.getX() > target.getX() && (from.getX() - target.getX() < thickness)) + || (target.getX() > from.getX() && (target.getX() - from.getX() < thickness)) + || (from.getZ() > target.getZ() && (from.getZ() - target.getZ() < thickness)) + || (target.getZ() > from.getZ() && (target.getZ() - from.getZ() < thickness)) + ); + } + + // -------------------------------------------- // + // TNT WATERLOG + // -------------------------------------------- // + // TNT in water/lava doesn't normally destroy any surrounding blocks, which is usually desired behavior, but... + // this optional change below provides workaround for waterwalling providing perfect protection, + // and makes cheap (non-obsidian) TNT cannons require minor maintenance between shots + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void tntWaterlog(EntityExplodeEvent event) + { + if (!ConfServer.handleExploitEnderPearlClipping) return; + if (!(event.getEntity() instanceof TNTPrimed)) return; + + Block center = event.getLocation().getBlock(); + if (!center.isLiquid()) return; + + // a single surrounding block in all 6 directions is broken if the material is weak enough + List targets = new ArrayList(); + targets.add(center.getRelative(0, 0, 1)); + targets.add(center.getRelative(0, 0, -1)); + targets.add(center.getRelative(0, 1, 0)); + targets.add(center.getRelative(0, -1, 0)); + targets.add(center.getRelative(1, 0, 0)); + targets.add(center.getRelative(-1, 0, 0)); + for (Block target : targets) + { + int id = target.getTypeId(); + // ignore air, bedrock, water, lava, obsidian, enchanting table, etc.... too bad we can't get a blast resistance value through Bukkit yet + if (id != 0 && (id < 7 || id > 11) && id != 49 && id != 90 && id != 116 && id != 119 && id != 120 && id != 130) + { + target.breakNaturally(); + } + } + } +} diff --git a/src/com/massivecraft/factions/MainListener.java b/src/com/massivecraft/factions/listeners/FactionsListenerMain.java similarity index 92% rename from src/com/massivecraft/factions/MainListener.java rename to src/com/massivecraft/factions/listeners/FactionsListenerMain.java index 54848f64..5e879b58 100644 --- a/src/com/massivecraft/factions/MainListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsListenerMain.java @@ -1,4 +1,4 @@ -package com.massivecraft.factions; +package com.massivecraft.factions.listeners; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -30,18 +30,25 @@ import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.server.PluginEnableEvent; +import com.massivecraft.factions.BoardColl; +import com.massivecraft.factions.ConfServer; +import com.massivecraft.factions.FFlag; +import com.massivecraft.factions.FPerm; +import com.massivecraft.factions.FPlayer; +import com.massivecraft.factions.Faction; +import com.massivecraft.factions.Factions; import com.massivecraft.factions.integration.SpoutFeatures; import com.massivecraft.mcore.ps.PS; -public class MainListener implements Listener +public class FactionsListenerMain implements Listener { // -------------------------------------------- // // INSTANCE & CONSTRUCT // -------------------------------------------- // - private static MainListener i = new MainListener(); - public static MainListener get() { return i; } - public MainListener() {} + private static FactionsListenerMain i = new FactionsListenerMain(); + public static FactionsListenerMain get() { return i; } + public FactionsListenerMain() {} // -------------------------------------------- // // SETUP diff --git a/src/com/massivecraft/factions/listeners/FactionsPlayerListener.java b/src/com/massivecraft/factions/listeners/FactionsPlayerListener.java index cded6260..8f7be299 100644 --- a/src/com/massivecraft/factions/listeners/FactionsPlayerListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsPlayerListener.java @@ -1,9 +1,7 @@ package com.massivecraft.factions.listeners; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; -import java.util.Map; import org.bukkit.Location; import org.bukkit.Material; @@ -20,7 +18,6 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.util.NumberConversions; import com.massivecraft.factions.BoardColl; import com.massivecraft.factions.ConfServer; @@ -137,23 +134,6 @@ public class FactionsPlayerListener implements Listener if ( ! canPlayerUseBlock(player, block, false)) { event.setCancelled(true); - if (ConfServer.handleExploitInteractionSpam) - { - String name = player.getName(); - InteractAttemptSpam attempt = interactSpammers.get(name); - if (attempt == null) - { - attempt = new InteractAttemptSpam(); - interactSpammers.put(name, attempt); - } - int count = attempt.increment(); - if (count >= 10) - { - FPlayer me = FPlayerColl.get().get(name); - me.msg("Ouch, that is starting to hurt. You should give it a rest."); - player.damage(NumberConversions.floor((double)count / 10)); - } - } return; } @@ -167,27 +147,6 @@ public class FactionsPlayerListener implements Listener } - // for handling people who repeatedly spam attempts to open a door (or similar) in another faction's territory - private Map interactSpammers = new HashMap(); - private static class InteractAttemptSpam - { - private int attempts = 0; - private long lastAttempt = System.currentTimeMillis(); - - // returns the current attempt count - public int increment() - { - long Now = System.currentTimeMillis(); - if (Now > lastAttempt + 2000) - attempts = 1; - else - attempts++; - lastAttempt = Now; - return attempts; - } - } - - // TODO: Refactor ! justCheck -> to informIfNot // TODO: Possibly incorporate pain build... public static boolean playerCanUseItemHere(Player player, Location loc, Material material, boolean justCheck)