Factions/src/com/massivecraft/factions/engine/EngineExploit.java

265 lines
9.2 KiB
Java
Raw Normal View History

package com.massivecraft.factions.engine;
import java.util.ArrayList;
2015-10-26 02:09:03 +01:00
import java.util.HashMap;
import java.util.List;
2015-10-26 02:09:03 +01:00
import java.util.UUID;
import org.bukkit.block.Block;
2015-10-26 02:09:03 +01:00
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
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;
import org.bukkit.event.player.PlayerTeleportEvent;
2015-10-26 02:09:03 +01:00
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.plugin.Plugin;
import org.bukkit.Location;
import org.bukkit.Material;
import com.massivecraft.factions.Factions;
import com.massivecraft.factions.entity.MConf;
import com.massivecraft.massivecore.EngineAbstract;
2015-10-26 02:09:03 +01:00
import com.massivecraft.massivecore.ps.PS;
import com.massivecraft.massivecore.util.MUtil;
public class EngineExploit extends EngineAbstract
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static EngineExploit i = new EngineExploit();
public static EngineExploit get() { return i; }
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public Plugin getPlugin()
{
return Factions.get();
}
// -------------------------------------------- //
// OBSIDIAN GENERATORS
// -------------------------------------------- //
@SuppressWarnings("deprecation")
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void obsidianGenerators(BlockFromToEvent event)
{
if (!MConf.get().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.setType(Material.AIR);
}
}
// -------------------------------------------- //
// ENDER PEARL CLIPPING
// -------------------------------------------- //
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void enderPearlClipping(PlayerTeleportEvent event)
{
if (!MConf.get().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.
@SuppressWarnings("deprecation")
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void tntWaterlog(EntityExplodeEvent event)
{
2013-05-09 17:29:35 +02:00
if (!MConf.get().handleExploitTNTWaterlog) 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<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.
private int NETHER_TRAP_RADIUS_CHECK = 5;
private int NETHER_TRAP_RESET_RADIUS = 3;
private HashMap<UUID, List<Block>> netherTrapBlockSet = new HashMap<UUID, List<Block>>();
// Detect teleport from a nether portal and remove animation if required
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void netherportalTrapRemoveAnimation(PlayerTeleportEvent event)
{
if ( ! MConf.get().handleNetherPortalTrap) 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();
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);
}
// 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)
{
if ( ! MConf.get().handleNetherPortalTrap) return;
// Only check if we're changing blocks
if (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())
{
this.netherportalReset(player);
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);
}
}
// Sends block update to player with original blocks (if required)
@SuppressWarnings("deprecation")
public void netherportalReset(Player player)
{
UUID uuid = player.getUniqueId();
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);
}
// Send air block updates to player
@SuppressWarnings("deprecation")
public void netherportalSendAir(Player player)
{
for (Block block : this.netherTrapBlockSet.get(player.getUniqueId())) player.sendBlockChange(block.getLocation(), Material.AIR, (byte) 0);
}
// Get portal blocks near a block
public List<Block> getPortalBlocks(Block from) {
List<Block> blocks = new ArrayList<Block>();
// 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));
}
}
}
}
return blocks;
}
}