Factions3/src/main/java/net/knarcraft/factions/engine/EngineExploit.java

227 lines
8.5 KiB
Java
Raw Normal View History

2022-08-05 01:17:53 +02:00
package net.knarcraft.factions.engine;
2022-08-05 00:34:54 +02:00
2022-08-05 01:17:53 +02:00
import net.knarcraft.factions.entity.MConf;
2022-08-05 00:34:54 +02:00
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;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
public class EngineExploit extends Engine {
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static EngineExploit i = new EngineExploit();
public static EngineExploit get() {
return i;
}
// -------------------------------------------- //
// OBSIDIAN GENERATORS
// -------------------------------------------- //
@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();
Material source = event.getBlock().getType();
Material target = block.getType();
if ((target == Material.REDSTONE_WIRE || target == Material.TRIPWIRE) && (source == Material.AIR || source == Material.LAVA)) {
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.GLASS_PANE || mat == Material.IRON_BARS) && clippingThrough(target, from, 0.65))
|| ((MUtil.list(Material.ACACIA_FENCE, Material.BIRCH_FENCE, Material.DARK_OAK_FENCE, Material.JUNGLE_FENCE, Material.NETHER_BRICK_FENCE, Material.OAK_FENCE, Material.SPRUCE_FENCE).contains(mat)) && 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))
);
}
// -------------------------------------------- //
// 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 static final int NETHER_TRAP_RADIUS_CHECK = 5;
private static final int NETHER_TRAP_RESET_RADIUS_SQUARED = 9;
private HashMap<UUID, List<Block>> portalTraps = new HashMap<>();
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void portalTrapRemoveAnimation(PlayerTeleportEvent event) {
// If there is a teleport caused by a nether portal ...
if (!MConf.get().handleNetherPortalTrap || event.getCause() != TeleportCause.NETHER_PORTAL) {
return;
}
Player player = event.getPlayer();
Block from = event.getTo().getBlock();
// ... and the player can't build at the destination ...
if (EnginePermBuild.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<Block> 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);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void portalUpdate(PlayerMoveEvent event) {
// If a player moves ...
if (!MConf.get().handleNetherPortalTrap || MUtil.isSameBlock(event)) {
return;
}
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
// ... 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) {
portalUpdateReset(player, portalTrap);
return;
}
// ... or send an update as if the portal blocks were air.
portalUpdateAir(player, portalTrap);
}
public void portalReset(Player player) {
UUID uuid = player.getUniqueId();
// 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);
// ... 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);
}
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);
}
@SuppressWarnings("deprecation")
private static void portalUpdate(Player player, List<Block> portal, Material material, Byte data) {
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);
}
}
public static List<Block> getPortal(Block from) {
// Create
List<Block> ret = new MassiveList<>();
// 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.NETHER_PORTAL) {
ret.add(from.getRelative(x, y, z));
}
}
}
}
// Return
return ret;
}
}