diff --git a/src/com/massivecraft/factions/engine/EngineExploit.java b/src/com/massivecraft/factions/engine/EngineExploit.java index af2b098f..fb27499f 100644 --- a/src/com/massivecraft/factions/engine/EngineExploit.java +++ b/src/com/massivecraft/factions/engine/EngineExploit.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.UUID; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; @@ -14,16 +15,16 @@ import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; +import org.bukkit.event.EventPriority; import org.bukkit.Location; import org.bukkit.Material; import com.massivecraft.factions.entity.MConf; import com.massivecraft.massivecore.Engine; +import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.ps.PS; import com.massivecraft.massivecore.util.MUtil; - public class EngineExploit extends Engine { // -------------------------------------------- // @@ -131,7 +132,6 @@ public class EngineExploit extends Engine } } } - // -------------------------------------------- // // NETHER PORTAL TRAP @@ -139,114 +139,115 @@ public class EngineExploit extends Engine // A nether portal trap can be created by the destination portal being enclosed (trapped) - resulting in the player not being able to run commands. // This fix removes the portal blocks (client side) from the destination until they are away from the portal. - private int NETHER_TRAP_RADIUS_CHECK = 5; - private int NETHER_TRAP_RESET_RADIUS = 3; + private static final int NETHER_TRAP_RADIUS_CHECK = 5; + private static final int NETHER_TRAP_RESET_RADIUS_SQUARED = 9; - private HashMap> netherTrapBlockSet = new HashMap>(); + private HashMap> portalTraps = new HashMap>(); - // Detect teleport from a nether portal and remove animation if required @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void netherportalTrapRemoveAnimation(PlayerTeleportEvent event) + public void portalTrapRemoveAnimation(PlayerTeleportEvent event) { - if ( ! MConf.get().handleNetherPortalTrap) return; + // If there is a teleport caused by a nether portal ... + if ( ! MConf.get().handleNetherPortalTrap || event.getCause() != TeleportCause.NETHER_PORTAL) return; - if (event.getCause() != TeleportCause.NETHER_PORTAL) return; - - // If they can build at the target destination then we will not do any further checks - if (EngineMain.canPlayerBuildAt(event.getPlayer(), PS.valueOf(event.getTo()), false)) return; - - final Player player = event.getPlayer(); - final UUID uuid = player.getUniqueId(); - + Player player = event.getPlayer(); Block from = event.getTo().getBlock(); - - // If a list exists, then we're dealing with a new portal - so revert the old portal blocks - this.netherportalReset(player); - - // Store some temporary data - this.netherTrapBlockSet.put(uuid, this.getPortalBlocks(from)); - - // Send the air update - this.netherportalSendAir(player); + // ... and the player can't build at the destination ... + if (EngineMain.canPlayerBuildAt(player, PS.valueOf(from), false)) return; + + // ... reset the old portal blocks stored ... + this.portalReset(player); + + // ... get all the portal blocks belonging to the new portal at the destination ... + List portalTrap = getPortal(from); + if (portalTrap.isEmpty()) return; + + // ... and then store those blocks and send an update as if they were air. + this.portalTraps.put(player.getUniqueId(), portalTrap); + portalUpdateAir(player, portalTrap); } - // When they leave the portal we will update it, otherwise send the updates again @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void netherportalTrapUpdate(PlayerMoveEvent event) + public void portalUpdate(PlayerMoveEvent event) { - if ( ! MConf.get().handleNetherPortalTrap) return; - - // Only check if we're changing blocks - if (MUtil.isSameBlock(event)) return; + // If a player moves ... + if ( ! MConf.get().handleNetherPortalTrap || MUtil.isSameBlock(event)) return; Player player = event.getPlayer(); UUID uuid = player.getUniqueId(); - // Check if we're sending updates to this player - if ( ! this.netherTrapBlockSet.containsKey(uuid)) return; - - // If they've changed worlds we don't bother checking this - if (event.getTo().getWorld() != this.netherTrapBlockSet.get(uuid).get(0).getWorld()) + // ... and he recently used a portal ... + List portalTrap = this.portalTraps.get(uuid); + if (portalTrap == null) return; + + Location locationTo = event.getTo(); + Location locationFrom = portalTrap.get(0).getLocation(); + + World worldTo = locationTo.getWorld(); + World worldFrom = locationFrom.getWorld(); + + // ... update reset the portal near them, if they have moved away too far ... + if ( ! worldTo.equals(worldFrom) || locationTo.distanceSquared(locationFrom) > NETHER_TRAP_RESET_RADIUS_SQUARED) { - this.netherportalReset(player); + portalUpdateReset(player, portalTrap); return; } - - // When the player moves away from the portal, we put it back to normal - if (event.getTo().distance(this.netherTrapBlockSet.get(uuid).get(0).getLocation()) > NETHER_TRAP_RESET_RADIUS) - { - this.netherportalReset(player); - } - else - { - // Send updates as air - this.netherportalSendAir(player); - } + + // ... or send an update as if the portal blocks were air. + portalUpdateAir(player, portalTrap); } - // Sends block update to player with original blocks (if required) - @SuppressWarnings("deprecation") - public void netherportalReset(Player player) + public void portalReset(Player player) { UUID uuid = player.getUniqueId(); + + // If a player has already a portal registered to him ... + List portalTrap = this.portalTraps.get(uuid); + if (portalTrap == null) return; + + // ... remove them from the registry ... + this.portalTraps.remove(uuid); - if ( ! this.netherTrapBlockSet.containsKey(uuid)) return; - - // Only send updates if they're in the same world - if (this.netherTrapBlockSet.get(uuid).get(0).getWorld() == player.getWorld()) for (Block block : this.netherTrapBlockSet.get(uuid)) player.sendBlockChange(block.getLocation(), block.getType(), block.getData()); - - // Remove the block set - this.netherTrapBlockSet.remove(uuid); + // ... and send updates if the player and portal are in the same world. + if ( ! player.getWorld().equals(portalTrap.get(0).getWorld())) return; + portalUpdateReset(player, portalTrap); } - - // Send air block updates to player + + public static void portalUpdateReset(Player player, List portal) { portalUpdate(player, portal, null, null); } + public static void portalUpdateAir(Player player, List portal) { portalUpdate(player, portal, Material.AIR, (byte) 0); } + @SuppressWarnings("deprecation") - public void netherportalSendAir(Player player) + private static void portalUpdate(Player player, List portal, Material material, Byte data) { - for (Block block : this.netherTrapBlockSet.get(player.getUniqueId())) player.sendBlockChange(block.getLocation(), Material.AIR, (byte) 0); + boolean usingDefault = material == null && data == null; + for (Block block : portal) + { + Material updateMaterial = usingDefault ? block.getType() : material; + byte updateData = usingDefault ? block.getData() : data; + player.sendBlockChange(block.getLocation(), updateMaterial, updateData); + } } - - // Get portal blocks near a block - public List getPortalBlocks(Block from) { - List blocks = new ArrayList(); + + public static List getPortal(Block from) + { + // Create + List ret = new MassiveList<>(); - // Check in a radius of the block to find the portal blocks + // Fill - Check in a radius of the block to find the portal blocks for (int x = -(NETHER_TRAP_RADIUS_CHECK); x <= NETHER_TRAP_RADIUS_CHECK; x ++) { for (int y = -(NETHER_TRAP_RADIUS_CHECK); y <= NETHER_TRAP_RADIUS_CHECK; y ++) { for (int z = -(NETHER_TRAP_RADIUS_CHECK); z <= NETHER_TRAP_RADIUS_CHECK; z ++) { - if (from.getRelative(x, y, z).getType() == Material.PORTAL) - { - // Store block - blocks.add(from.getRelative(x, y, z)); - } + if (from.getRelative(x, y, z).getType() == Material.PORTAL) ret.add(from.getRelative(x, y, z)); } } } - - return blocks; + + // Return + return ret; } + }