summaryrefslogtreecommitdiffstats
path: root/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/CheckUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/CheckUtil.java')
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/CheckUtil.java372
1 files changed, 372 insertions, 0 deletions
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/CheckUtil.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/CheckUtil.java
new file mode 100644
index 000000000..390d2207d
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/CheckUtil.java
@@ -0,0 +1,372 @@
+package com.earth2me.essentials.anticheat.checks;
+
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.data.PreciseLocation;
+import java.util.HashSet;
+import java.util.Set;
+import net.minecraft.server.Block;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Vector;
+
+
+/**
+ * Some stuff that's used by different checks or just too complex to keep in other places
+ *
+ */
+public class CheckUtil
+{
+ /**
+ * Check if a player looks at a target of a specific size, with a specific precision value (roughly)
+ */
+ public static double directionCheck(final NoCheatPlayer player, final double targetX, final double targetY, final double targetZ, final double targetWidth, final double targetHeight, final double precision)
+ {
+
+ // Eye location of the player
+ final Location eyes = player.getPlayer().getEyeLocation();
+
+ final double factor = Math.sqrt(Math.pow(eyes.getX() - targetX, 2) + Math.pow(eyes.getY() - targetY, 2) + Math.pow(eyes.getZ() - targetZ, 2));
+
+ // View direction of the player
+ final Vector direction = eyes.getDirection();
+
+ final double x = targetX - eyes.getX();
+ final double y = targetY - eyes.getY();
+ final double z = targetZ - eyes.getZ();
+
+ final double xPrediction = factor * direction.getX();
+ final double yPrediction = factor * direction.getY();
+ final double zPrediction = factor * direction.getZ();
+
+ double off = 0.0D;
+
+ off += Math.max(Math.abs(x - xPrediction) - (targetWidth / 2 + precision), 0.0D);
+ off += Math.max(Math.abs(z - zPrediction) - (targetWidth / 2 + precision), 0.0D);
+ off += Math.max(Math.abs(y - yPrediction) - (targetHeight / 2 + precision), 0.0D);
+
+ if (off > 1)
+ {
+ off = Math.sqrt(off);
+ }
+
+ return off;
+ }
+
+ /**
+ * Check if a player is close enough to a target, based on his eye location
+ *
+ * @param player
+ * @param targetX
+ * @param targetY
+ * @param targetZ
+ * @param limit
+ * @return
+ */
+ public static final double reachCheck(final NoCheatPlayer player, final double targetX, final double targetY, final double targetZ, final double limit)
+ {
+
+ final Location eyes = player.getPlayer().getEyeLocation();
+
+ final double distance = Math.sqrt(Math.pow(eyes.getX() - targetX, 2) + Math.pow(eyes.getY() - targetY, 2) + Math.pow(eyes.getZ() - targetZ, 2));
+
+ return Math.max(distance - limit, 0.0D);
+ }
+ private final static double magic = 0.45D;
+ private final static double magic2 = 0.55D;
+ private static final int NONSOLID = 1; // 0x00000001
+ private static final int SOLID = 2; // 0x00000010
+ // All liquids are "nonsolid" too
+ private static final int LIQUID = 4 | NONSOLID; // 0x00000101
+ // All ladders are "nonsolid" and "solid" too
+ private static final int LADDER = 8 | NONSOLID | SOLID; // 0x00001011
+ // All fences are solid - fences are treated specially due
+ // to being 1.5 blocks high
+ private static final int FENCE = 16 | SOLID | NONSOLID; // 0x00010011
+ private static final int INGROUND = 128;
+ private static final int ONGROUND = 256;
+ // Until I can think of a better way to determine if a block is solid or
+ // not, this is what I'll do
+ private static final int types[];
+ private static final Set<Material> foods = new HashSet<Material>();
+
+ static
+ {
+ types = new int[256];
+
+ // Find and define properties of all other blocks
+ for (int i = 0; i < types.length; i++)
+ {
+
+ // Everything unknown is considered nonsolid and solid
+ types[i] = NONSOLID | SOLID;
+
+ if (Block.byId[i] != null)
+ {
+ if (Block.byId[i].material.isSolid())
+ {
+ // STONE, CAKE, LEAFS, ...
+ types[i] = SOLID;
+ }
+ else if (Block.byId[i].material.isLiquid())
+ {
+ // WATER, LAVA, ...
+ types[i] = LIQUID;
+ }
+ else
+ {
+ // AIR, SAPLINGS, ...
+ types[i] = NONSOLID;
+ }
+ }
+ }
+
+ // Some exceptions where the above method fails
+
+ // du'h
+ types[Material.AIR.getId()] = NONSOLID;
+
+ // Webs slow down a players fall extremely, so it makes
+ // sense to treat them as optionally solid
+ types[Material.WEB.getId()] = SOLID | NONSOLID;
+
+ // Obvious
+ types[Material.LADDER.getId()] = LADDER;
+ types[Material.WATER_LILY.getId()] = LADDER;
+ types[Material.VINE.getId()] = LADDER;
+
+ types[Material.FENCE.getId()] = FENCE;
+ types[Material.FENCE_GATE.getId()] = FENCE;
+ types[Material.NETHER_FENCE.getId()] = FENCE;
+
+ // These are sometimes solid, sometimes not
+ types[Material.IRON_FENCE.getId()] = SOLID | NONSOLID;
+ types[Material.THIN_GLASS.getId()] = SOLID | NONSOLID;
+
+ // Signs are NOT solid, despite the game claiming they are
+ types[Material.WALL_SIGN.getId()] = NONSOLID;
+ types[Material.SIGN_POST.getId()] = NONSOLID;
+
+ // (trap)doors can be solid or not
+ types[Material.WOODEN_DOOR.getId()] = SOLID | NONSOLID;
+ types[Material.IRON_DOOR_BLOCK.getId()] = SOLID | NONSOLID;
+ types[Material.TRAP_DOOR.getId()] = SOLID | NONSOLID;
+
+ // repeaters are technically half blocks
+ types[Material.DIODE_BLOCK_OFF.getId()] = SOLID | NONSOLID;
+ types[Material.DIODE_BLOCK_ON.getId()] = SOLID | NONSOLID;
+
+ // pressure plates are so slim, you can consider them
+ // nonsolid too
+ types[Material.STONE_PLATE.getId()] = SOLID | NONSOLID;
+ types[Material.WOOD_PLATE.getId()] = SOLID | NONSOLID;
+
+ // We need to know what is considered food for the instanteat check
+ foods.add(Material.APPLE);
+ foods.add(Material.BREAD);
+ foods.add(Material.COOKED_BEEF);
+ foods.add(Material.COOKED_CHICKEN);
+ foods.add(Material.COOKED_FISH);
+ foods.add(Material.COOKIE);
+ foods.add(Material.GOLDEN_APPLE);
+ foods.add(Material.GRILLED_PORK);
+ foods.add(Material.MELON);
+ foods.add(Material.MUSHROOM_SOUP);
+ foods.add(Material.PORK);
+ foods.add(Material.RAW_BEEF);
+ foods.add(Material.RAW_CHICKEN);
+ foods.add(Material.RAW_FISH);
+ foods.add(Material.ROTTEN_FLESH);
+ foods.add(Material.SPIDER_EYE);
+ }
+
+ /**
+ * Ask NoCheat what it thinks about a certain location. Is it a place where a player can safely stand, should it be
+ * considered as being inside a liquid etc.
+ *
+ * @param world The world the coordinates belong to
+ * @param location The precise location in the world
+ *
+ * @return
+ */
+ public static final int evaluateLocation(final World world, final PreciseLocation location)
+ {
+
+ final int lowerX = lowerBorder(location.x);
+ final int upperX = upperBorder(location.x);
+ final int Y = (int)location.y;
+ final int lowerZ = lowerBorder(location.z);
+ final int upperZ = upperBorder(location.z);
+
+ // Check the four borders of the players hitbox for something he could
+ // be standing on, and combine the results
+ int result = 0;
+
+ result |= evaluateSimpleLocation(world, lowerX, Y, lowerZ);
+ result |= evaluateSimpleLocation(world, upperX, Y, lowerZ);
+ result |= evaluateSimpleLocation(world, upperX, Y, upperZ);
+ result |= evaluateSimpleLocation(world, lowerX, Y, upperZ);
+
+ if (!isInGround(result))
+ {
+ // Original location: X, Z (allow standing in walls this time)
+ if (isSolid(types[world.getBlockTypeIdAt(Location.locToBlock(location.x), Location.locToBlock(location.y), Location.locToBlock(location.z))]))
+ {
+ result |= INGROUND;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Evaluate a location by only looking at a specific "column" of the map to find out if that "column" would allow a
+ * player to stand, swim etc. there
+ *
+ * @param world
+ * @param x
+ * @param y
+ * @param z
+ * @return Returns INGROUND, ONGROUND, LIQUID, combination of the three or 0
+ */
+ private static final int evaluateSimpleLocation(final World world, final int x, final int y, final int z)
+ {
+
+ // First we need to know about the block itself, the block
+ // below it and the block above it
+ final int top = types[world.getBlockTypeIdAt(x, y + 1, z)];
+ final int base = types[world.getBlockTypeIdAt(x, y, z)];
+ final int below = types[world.getBlockTypeIdAt(x, y - 1, z)];
+
+ int type = 0;
+ // Special case: Standing on a fence
+ // Behave as if there is a block on top of the fence
+ if ((below == FENCE) && base != FENCE && isNonSolid(top))
+ {
+ type = INGROUND;
+ }
+ // Special case: Fence
+ // Being a bit above a fence
+ else if (below != FENCE && isNonSolid(base) && types[world.getBlockTypeIdAt(x, y - 2, z)] == FENCE)
+ {
+ type = ONGROUND;
+ }
+ else if (isNonSolid(top))
+ {
+ // Simplest (and most likely) case:
+ // Below the player is a solid block
+ if (isSolid(below) && isNonSolid(base))
+ {
+ type = ONGROUND;
+ }
+ // Next (likely) case:
+ // There is a ladder
+ else if (isLadder(base) || isLadder(top))
+ {
+ type = ONGROUND;
+ }
+ // Next (likely) case:
+ // At least the block the player stands
+ // in is solid
+ else if (isSolid(base))
+ {
+ type = INGROUND;
+ }
+ }
+
+ // (In every case, check for water)
+ if (isLiquid(base) || isLiquid(top))
+ {
+ type |= LIQUID | INGROUND;
+ }
+
+ return type;
+ }
+
+ public static final boolean isSolid(final int value)
+ {
+ return (value & SOLID) == SOLID;
+ }
+
+ public static final boolean isLiquid(final int value)
+ {
+ return (value & LIQUID) == LIQUID;
+ }
+
+ private static final boolean isNonSolid(final int value)
+ {
+ return ((value & NONSOLID) == NONSOLID);
+ }
+
+ private static final boolean isLadder(final int value)
+ {
+ return ((value & LADDER) == LADDER);
+ }
+
+ public static final boolean isOnGround(final int fromType)
+ {
+ return (fromType & ONGROUND) == ONGROUND;
+ }
+
+ public static final boolean isInGround(final int fromType)
+ {
+ return (fromType & INGROUND) == INGROUND;
+ }
+
+ /**
+ * Personal Rounding function to determine if a player is still touching a block or not
+ *
+ * @param d1
+ * @return
+ */
+ private static final int lowerBorder(final double d1)
+ {
+
+ final double floor = Math.floor(d1);
+
+ if (floor + magic <= d1)
+ {
+ return (int)(floor);
+ }
+ else
+ {
+ return (int)(floor - 1);
+ }
+ }
+
+ /**
+ * Personal Rounding function to determine if a player is still touching a block or not
+ *
+ * @param d1
+ * @return
+ */
+ private static final int upperBorder(final double d1)
+ {
+
+ final double floor = Math.floor(d1);
+
+ if (floor + magic2 < d1)
+ {
+ return (int)(floor + 1);
+ }
+ else
+ {
+ return (int)floor;
+ }
+ }
+
+ public static int getType(final int typeId)
+ {
+ return types[typeId];
+ }
+
+ public static boolean isFood(ItemStack item)
+ {
+ if (item == null)
+ {
+ return false;
+ }
+ return foods.contains(item.getType());
+ }
+}