2014-10-08 06:38:26 +02:00
|
|
|
package com.massivecraft.factions.engine;
|
2013-04-18 14:02:39 +02:00
|
|
|
|
2017-01-03 11:47:51 +01:00
|
|
|
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;
|
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.Material;
|
2016-02-26 20:44:34 +01:00
|
|
|
import org.bukkit.World;
|
2013-04-18 14:02:39 +02:00
|
|
|
import org.bukkit.block.Block;
|
2015-10-26 02:09:03 +01:00
|
|
|
import org.bukkit.entity.Player;
|
2013-04-18 14:02:39 +02:00
|
|
|
import org.bukkit.entity.TNTPrimed;
|
2017-01-03 11:47:51 +01:00
|
|
|
import org.bukkit.event.EventHandler;
|
|
|
|
import org.bukkit.event.EventPriority;
|
2013-04-18 14:02:39 +02:00
|
|
|
import org.bukkit.event.block.BlockFromToEvent;
|
|
|
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
2015-10-26 02:09:03 +01:00
|
|
|
import org.bukkit.event.player.PlayerMoveEvent;
|
2013-04-18 14:02:39 +02:00
|
|
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
2015-10-26 02:09:03 +01:00
|
|
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
2013-04-18 14:02:39 +02:00
|
|
|
|
2017-01-03 11:47:51 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.UUID;
|
2013-04-18 14:02:39 +02:00
|
|
|
|
2016-02-25 22:28:09 +01:00
|
|
|
public class EngineExploit extends Engine
|
2013-04-18 14:02:39 +02:00
|
|
|
{
|
|
|
|
// -------------------------------------------- //
|
|
|
|
// INSTANCE & CONSTRUCT
|
|
|
|
// -------------------------------------------- //
|
|
|
|
|
2014-10-08 06:38:26 +02:00
|
|
|
private static EngineExploit i = new EngineExploit();
|
|
|
|
public static EngineExploit get() { return i; }
|
2013-04-18 14:02:39 +02:00
|
|
|
|
|
|
|
// -------------------------------------------- //
|
|
|
|
// OBSIDIAN GENERATORS
|
|
|
|
// -------------------------------------------- //
|
|
|
|
|
2013-09-20 12:50:32 +02:00
|
|
|
@SuppressWarnings("deprecation")
|
2013-04-18 14:02:39 +02:00
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
|
|
|
public void obsidianGenerators(BlockFromToEvent event)
|
|
|
|
{
|
2013-04-22 10:05:03 +02:00
|
|
|
if (!MConf.get().handleExploitObsidianGenerators) return;
|
2013-04-18 14:02:39 +02:00
|
|
|
|
|
|
|
// 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))
|
|
|
|
{
|
2013-09-20 12:50:32 +02:00
|
|
|
block.setType(Material.AIR);
|
2013-04-18 14:02:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------- //
|
|
|
|
// ENDER PEARL CLIPPING
|
|
|
|
// -------------------------------------------- //
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
|
|
|
|
public void enderPearlClipping(PlayerTeleportEvent event)
|
|
|
|
{
|
2013-04-22 10:05:03 +02:00
|
|
|
if (!MConf.get().handleExploitEnderPearlClipping) return;
|
2013-04-18 14:02:39 +02:00
|
|
|
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))
|
|
|
|
)
|
2016-10-09 10:59:43 +02:00
|
|
|
{
|
2013-04-18 14:02:39 +02:00
|
|
|
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
|
|
|
|
// -------------------------------------------- //
|
2014-11-14 08:41:58 +01:00
|
|
|
// 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.
|
2013-04-18 14:02:39 +02:00
|
|
|
|
2013-09-20 12:50:32 +02:00
|
|
|
@SuppressWarnings("deprecation")
|
2013-04-18 14:02:39 +02:00
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void tntWaterlog(EntityExplodeEvent event)
|
|
|
|
{
|
2013-05-09 17:29:35 +02:00
|
|
|
if (!MConf.get().handleExploitTNTWaterlog) return;
|
2013-04-18 14:02:39 +02:00
|
|
|
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<Block> targets = new ArrayList<Block>();
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 02:09:03 +01:00
|
|
|
|
|
|
|
// -------------------------------------------- //
|
|
|
|
// NETHER PORTAL TRAP
|
|
|
|
// -------------------------------------------- //
|
|
|
|
// 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.
|
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
private static final int NETHER_TRAP_RADIUS_CHECK = 5;
|
|
|
|
private static final int NETHER_TRAP_RESET_RADIUS_SQUARED = 9;
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
private HashMap<UUID, List<Block>> portalTraps = new HashMap<UUID, List<Block>>();
|
2015-10-26 02:09:03 +01:00
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
2016-02-26 20:44:34 +01:00
|
|
|
public void portalTrapRemoveAnimation(PlayerTeleportEvent event)
|
2015-10-26 02:09:03 +01:00
|
|
|
{
|
2016-02-26 20:44:34 +01:00
|
|
|
// If there is a teleport caused by a nether portal ...
|
|
|
|
if ( ! MConf.get().handleNetherPortalTrap || event.getCause() != TeleportCause.NETHER_PORTAL) return;
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
Player player = event.getPlayer();
|
2015-10-26 02:09:03 +01:00
|
|
|
Block from = event.getTo().getBlock();
|
2016-02-26 20:44:34 +01:00
|
|
|
|
|
|
|
// ... and the player can't build at the destination ...
|
2017-01-03 11:47:51 +01:00
|
|
|
if (EnginePermBuild.canPlayerBuildAt(player, PS.valueOf(from), false)) return;
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
// ... reset the old portal blocks stored ...
|
|
|
|
this.portalReset(player);
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
// ... get all the portal blocks belonging to the new portal at the destination ...
|
|
|
|
List<Block> portalTrap = getPortal(from);
|
|
|
|
if (portalTrap.isEmpty()) return;
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
// ... and then store those blocks and send an update as if they were air.
|
|
|
|
this.portalTraps.put(player.getUniqueId(), portalTrap);
|
|
|
|
portalUpdateAir(player, portalTrap);
|
2015-10-26 02:09:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
2016-02-26 20:44:34 +01:00
|
|
|
public void portalUpdate(PlayerMoveEvent event)
|
2015-10-26 02:09:03 +01:00
|
|
|
{
|
2016-02-26 20:44:34 +01:00
|
|
|
// If a player moves ...
|
|
|
|
if ( ! MConf.get().handleNetherPortalTrap || MUtil.isSameBlock(event)) return;
|
2015-10-26 02:09:03 +01:00
|
|
|
|
|
|
|
Player player = event.getPlayer();
|
|
|
|
UUID uuid = player.getUniqueId();
|
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
// ... and he recently used a portal ...
|
|
|
|
List<Block> 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)
|
2015-10-26 02:09:03 +01:00
|
|
|
{
|
2016-02-26 20:44:34 +01:00
|
|
|
portalUpdateReset(player, portalTrap);
|
2015-10-26 02:09:03 +01:00
|
|
|
return;
|
|
|
|
}
|
2016-02-26 20:44:34 +01:00
|
|
|
|
|
|
|
// ... or send an update as if the portal blocks were air.
|
|
|
|
portalUpdateAir(player, portalTrap);
|
2015-10-26 02:09:03 +01:00
|
|
|
}
|
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
public void portalReset(Player player)
|
2015-10-26 02:09:03 +01:00
|
|
|
{
|
|
|
|
UUID uuid = player.getUniqueId();
|
2016-02-26 20:44:34 +01:00
|
|
|
|
|
|
|
// If a player has already a portal registered to him ...
|
|
|
|
List<Block> portalTrap = this.portalTraps.get(uuid);
|
|
|
|
if (portalTrap == null) return;
|
|
|
|
|
|
|
|
// ... remove them from the registry ...
|
|
|
|
this.portalTraps.remove(uuid);
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
// ... 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);
|
2015-10-26 02:09:03 +01:00
|
|
|
}
|
2016-02-26 20:44:34 +01:00
|
|
|
|
|
|
|
public static void portalUpdateReset(Player player, List<Block> portal) { portalUpdate(player, portal, null, null); }
|
|
|
|
public static void portalUpdateAir(Player player, List<Block> portal) { portalUpdate(player, portal, Material.AIR, (byte) 0); }
|
|
|
|
|
2015-10-26 02:09:03 +01:00
|
|
|
@SuppressWarnings("deprecation")
|
2016-02-26 20:44:34 +01:00
|
|
|
private static void portalUpdate(Player player, List<Block> portal, Material material, Byte data)
|
2015-10-26 02:09:03 +01:00
|
|
|
{
|
2016-02-26 20:44:34 +01:00
|
|
|
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);
|
|
|
|
}
|
2015-10-26 02:09:03 +01:00
|
|
|
}
|
2016-02-26 20:44:34 +01:00
|
|
|
|
|
|
|
public static List<Block> getPortal(Block from)
|
|
|
|
{
|
|
|
|
// Create
|
|
|
|
List<Block> ret = new MassiveList<>();
|
2015-10-26 02:09:03 +01:00
|
|
|
|
2016-02-26 20:44:34 +01:00
|
|
|
// Fill - Check in a radius of the block to find the portal blocks
|
2015-10-26 02:09:03 +01:00
|
|
|
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 ++)
|
|
|
|
{
|
2016-02-26 20:44:34 +01:00
|
|
|
if (from.getRelative(x, y, z).getType() == Material.PORTAL) ret.add(from.getRelative(x, y, z));
|
2015-10-26 02:09:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-02-26 20:44:34 +01:00
|
|
|
|
|
|
|
// Return
|
|
|
|
return ret;
|
2015-10-26 02:09:03 +01:00
|
|
|
}
|
2016-02-26 20:44:34 +01:00
|
|
|
|
2013-04-18 14:02:39 +02:00
|
|
|
}
|