summaryrefslogtreecommitdiffstats
path: root/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace
diff options
context:
space:
mode:
Diffstat (limited to 'EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace')
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheck.java99
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheckListener.java97
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceConfig.java37
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceData.java25
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/DirectionCheck.java131
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/ReachCheck.java75
6 files changed, 464 insertions, 0 deletions
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheck.java
new file mode 100644
index 000000000..e20a74ca9
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheck.java
@@ -0,0 +1,99 @@
+package com.earth2me.essentials.anticheat.checks.blockplace;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.actions.ParameterName;
+import com.earth2me.essentials.anticheat.checks.Check;
+import com.earth2me.essentials.anticheat.config.ConfigurationCacheStore;
+import com.earth2me.essentials.anticheat.data.DataStore;
+import com.earth2me.essentials.anticheat.data.SimpleLocation;
+import java.util.Locale;
+
+
+/**
+ * Abstract base class for BlockPlace checks, provides some convenience methods for access to data and config that's
+ * relevant to this checktype
+ */
+public abstract class BlockPlaceCheck extends Check
+{
+ private static final String id = "blockplace";
+
+ public BlockPlaceCheck(NoCheat plugin, String name)
+ {
+ super(plugin, id, name);
+ }
+
+ @Override
+ public String getParameter(ParameterName wildcard, NoCheatPlayer player)
+ {
+ if (wildcard == ParameterName.PLACE_LOCATION)
+ {
+ SimpleLocation l = getData(player).blockPlaced;
+ if (l.isSet())
+ {
+ return String.format(Locale.US, "%d %d %d", l.x, l.y, l.z);
+ }
+ else
+ {
+ return "null";
+ }
+ }
+ else if (wildcard == ParameterName.PLACE_AGAINST)
+ {
+ SimpleLocation l = getData(player).blockPlacedAgainst;
+ if (l.isSet())
+ {
+ return String.format(Locale.US, "%d %d %d", l.x, l.y, l.z);
+ }
+ else
+ {
+ return "null";
+ }
+ }
+ else
+ {
+ return super.getParameter(wildcard, player);
+ }
+ }
+
+ /**
+ * Get the "BlockPlaceData" object that belongs to the player. Will ensure that such a object exists and if not,
+ * create one
+ *
+ * @param player
+ * @return
+ */
+ public static BlockPlaceData getData(NoCheatPlayer player)
+ {
+ DataStore base = player.getDataStore();
+ BlockPlaceData data = base.get(id);
+ if (data == null)
+ {
+ data = new BlockPlaceData();
+ base.set(id, data);
+ }
+ return data;
+ }
+
+ /**
+ * Get the BlockPlaceConfig object that belongs to the world that the player currently resides in.
+ *
+ * @param player
+ * @return
+ */
+ public static BlockPlaceConfig getConfig(NoCheatPlayer player)
+ {
+ return getConfig(player.getConfigurationStore());
+ }
+
+ public static BlockPlaceConfig getConfig(ConfigurationCacheStore cache)
+ {
+ BlockPlaceConfig config = cache.get(id);
+ if (config == null)
+ {
+ config = new BlockPlaceConfig(cache.getConfiguration());
+ cache.set(id, config);
+ }
+ return config;
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheckListener.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheckListener.java
new file mode 100644
index 000000000..253982bd1
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceCheckListener.java
@@ -0,0 +1,97 @@
+package com.earth2me.essentials.anticheat.checks.blockplace;
+
+import java.util.LinkedList;
+import java.util.List;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockPlaceEvent;
+import com.earth2me.essentials.anticheat.EventManager;
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.config.ConfigurationCacheStore;
+import com.earth2me.essentials.anticheat.config.Permissions;
+
+
+/**
+ * Central location to listen to Block-related events and dispatching them to checks
+ *
+ */
+public class BlockPlaceCheckListener implements Listener, EventManager
+{
+ private final ReachCheck reachCheck;
+ private final DirectionCheck directionCheck;
+ private final NoCheat plugin;
+
+ public BlockPlaceCheckListener(NoCheat plugin)
+ {
+
+ this.plugin = plugin;
+
+ reachCheck = new ReachCheck(plugin);
+ directionCheck = new DirectionCheck(plugin);
+ }
+
+ /**
+ * We listen to BlockPlace events for obvious reasons
+ *
+ * @param event the BlockPlace event
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ protected void handleBlockPlaceEvent(BlockPlaceEvent event)
+ {
+
+ if (event.isCancelled() || event.getBlock() == null || event.getBlockAgainst() == null)
+ {
+ return;
+ }
+
+ boolean cancelled = false;
+
+ final NoCheatPlayer player = plugin.getPlayer(event.getPlayer());
+ final BlockPlaceConfig cc = BlockPlaceCheck.getConfig(player);
+ final BlockPlaceData data = BlockPlaceCheck.getData(player);
+
+ // Remember these locations and put them in a simpler "format"
+ data.blockPlaced.set(event.getBlock());
+ data.blockPlacedAgainst.set(event.getBlockAgainst());
+
+ // Now do the actual checks
+
+ // First the reach check
+ if (cc.reachCheck && !player.hasPermission(Permissions.BLOCKPLACE_REACH))
+ {
+ cancelled = reachCheck.check(player, data, cc);
+ }
+
+ // Second the direction check
+ if (!cancelled && cc.directionCheck && !player.hasPermission(Permissions.BLOCKPLACE_DIRECTION))
+ {
+ cancelled = directionCheck.check(player, data, cc);
+ }
+
+ // If one of the checks requested to cancel the event, do so
+ if (cancelled)
+ {
+ event.setCancelled(cancelled);
+ }
+ }
+
+ public List<String> getActiveChecks(ConfigurationCacheStore cc)
+ {
+ LinkedList<String> s = new LinkedList<String>();
+
+ BlockPlaceConfig bp = BlockPlaceCheck.getConfig(cc);
+
+ if (bp.reachCheck)
+ {
+ s.add("blockplace.reach");
+ }
+ if (bp.directionCheck)
+ {
+ s.add("blockplace.direction");
+ }
+
+ return s;
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceConfig.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceConfig.java
new file mode 100644
index 000000000..26c8d0f6d
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceConfig.java
@@ -0,0 +1,37 @@
+package com.earth2me.essentials.anticheat.checks.blockplace;
+
+import com.earth2me.essentials.anticheat.ConfigItem;
+import com.earth2me.essentials.anticheat.actions.types.ActionList;
+import com.earth2me.essentials.anticheat.config.ConfPaths;
+import com.earth2me.essentials.anticheat.config.NoCheatConfiguration;
+import com.earth2me.essentials.anticheat.config.Permissions;
+
+
+/**
+ * Configurations specific for the "BlockPlace" checks Every world gets one of these assigned to it, or if a world
+ * doesn't get it's own, it will use the "global" version
+ *
+ */
+public class BlockPlaceConfig implements ConfigItem
+{
+ public final boolean reachCheck;
+ public final double reachDistance;
+ public final ActionList reachActions;
+ public final boolean directionCheck;
+ public final ActionList directionActions;
+ public final long directionPenaltyTime;
+ public final double directionPrecision;
+
+ public BlockPlaceConfig(NoCheatConfiguration data)
+ {
+
+ reachCheck = data.getBoolean(ConfPaths.BLOCKPLACE_REACH_CHECK);
+ reachDistance = 535D / 100D;
+ reachActions = data.getActionList(ConfPaths.BLOCKPLACE_REACH_ACTIONS, Permissions.BLOCKPLACE_REACH);
+
+ directionCheck = data.getBoolean(ConfPaths.BLOCKPLACE_DIRECTION_CHECK);
+ directionPenaltyTime = data.getInt(ConfPaths.BLOCKPLACE_DIRECTION_PENALTYTIME);
+ directionPrecision = ((double)data.getInt(ConfPaths.BLOCKPLACE_DIRECTION_PRECISION)) / 100D;
+ directionActions = data.getActionList(ConfPaths.BLOCKPLACE_DIRECTION_ACTIONS, Permissions.BLOCKPLACE_DIRECTION);
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceData.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceData.java
new file mode 100644
index 000000000..47ff9d58a
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/BlockPlaceData.java
@@ -0,0 +1,25 @@
+package com.earth2me.essentials.anticheat.checks.blockplace;
+
+import com.earth2me.essentials.anticheat.DataItem;
+import com.earth2me.essentials.anticheat.data.SimpleLocation;
+
+
+/**
+ * Player specific data for the blockbreak checks
+ *
+ */
+public class BlockPlaceData implements DataItem
+{
+ // Keep track of violation levels for the two checks
+ public double reachVL = 0.0D;
+ public double directionVL = 0.0D;
+ // Used for the penalty time feature of the direction check
+ public long directionLastViolationTime = 0;
+ // Have a nicer/simpler way to work with block locations instead of
+ // Bukkits own "Location" class
+ public final SimpleLocation blockPlacedAgainst = new SimpleLocation();
+ public final SimpleLocation blockPlaced = new SimpleLocation();
+ // For logging, remember the reachDistance that was calculated in the
+ // reach check
+ public double reachdistance;
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/DirectionCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/DirectionCheck.java
new file mode 100644
index 000000000..8aa782d19
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/DirectionCheck.java
@@ -0,0 +1,131 @@
+package com.earth2me.essentials.anticheat.checks.blockplace;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.actions.ParameterName;
+import com.earth2me.essentials.anticheat.checks.CheckUtil;
+import com.earth2me.essentials.anticheat.data.SimpleLocation;
+import com.earth2me.essentials.anticheat.data.Statistics.Id;
+import java.util.Locale;
+import org.bukkit.Location;
+
+
+/**
+ * The DirectionCheck will find out if a player tried to interact with something that's not in his field of view.
+ *
+ */
+public class DirectionCheck extends BlockPlaceCheck
+{
+ public DirectionCheck(NoCheat plugin)
+ {
+ super(plugin, "blockplace.direction");
+ }
+
+ public boolean check(NoCheatPlayer player, BlockPlaceData data, BlockPlaceConfig cc)
+ {
+
+ boolean cancel = false;
+
+ final SimpleLocation blockPlaced = data.blockPlaced;
+ final SimpleLocation blockPlacedAgainst = data.blockPlacedAgainst;
+
+ // How far "off" is the player with his aim. We calculate from the
+ // players eye location and view direction to the center of the target
+ // block. If the line of sight is more too far off, "off" will be
+ // bigger than 0
+ double off = CheckUtil.directionCheck(player, blockPlacedAgainst.x + 0.5D, blockPlacedAgainst.y + 0.5D, blockPlacedAgainst.z + 0.5D, 1D, 1D, cc.directionPrecision);
+
+ // now check if the player is looking at the block from the correct side
+ double off2 = 0.0D;
+
+ // Find out against which face the player tried to build, and if he
+ // stood on the correct side of it
+ Location eyes = player.getPlayer().getEyeLocation();
+ if (blockPlaced.x > blockPlacedAgainst.x)
+ {
+ off2 = blockPlacedAgainst.x + 0.5D - eyes.getX();
+ }
+ else if (blockPlaced.x < blockPlacedAgainst.x)
+ {
+ off2 = -(blockPlacedAgainst.x + 0.5D - eyes.getX());
+ }
+ else if (blockPlaced.y > blockPlacedAgainst.y)
+ {
+ off2 = blockPlacedAgainst.y + 0.5D - eyes.getY();
+ }
+ else if (blockPlaced.y < blockPlacedAgainst.y)
+ {
+ off2 = -(blockPlacedAgainst.y + 0.5D - eyes.getY());
+ }
+ else if (blockPlaced.z > blockPlacedAgainst.z)
+ {
+ off2 = blockPlacedAgainst.z + 0.5D - eyes.getZ();
+ }
+ else if (blockPlaced.z < blockPlacedAgainst.z)
+ {
+ off2 = -(blockPlacedAgainst.z + 0.5D - eyes.getZ());
+ }
+
+ // If he wasn't on the correct side, add that to the "off" value
+ if (off2 > 0.0D)
+ {
+ off += off2;
+ }
+
+ final long time = System.currentTimeMillis();
+
+ if (off < 0.1D)
+ {
+ // Player did nothing wrong
+ // reduce violation counter to reward him
+ data.directionVL *= 0.9D;
+ }
+ else
+ {
+ // Player failed the check
+ // Increment violation counter and statistics
+ data.directionVL += off;
+ incrementStatistics(player, Id.BP_DIRECTION, off);
+
+ // Execute whatever actions are associated with this check and the
+ // violation level and find out if we should cancel the event
+ cancel = executeActions(player, cc.directionActions, data.directionVL);
+
+ if (cancel)
+ {
+ // if we should cancel, remember the current time too
+ data.directionLastViolationTime = time;
+ }
+ }
+
+ // If the player is still in penalty time, cancel the event anyway
+ if (data.directionLastViolationTime + cc.directionPenaltyTime > time)
+ {
+ // A safeguard to avoid people getting stuck in penalty time
+ // indefinitely in case the system time of the server gets changed
+ if (data.directionLastViolationTime > time)
+ {
+ data.directionLastViolationTime = 0;
+ }
+
+ // He is in penalty time, therefore request cancelling of the event
+ return true;
+ }
+
+ return cancel;
+ }
+
+ @Override
+ public String getParameter(ParameterName wildcard, NoCheatPlayer player)
+ {
+
+ if (wildcard == ParameterName.VIOLATIONS)
+ {
+ return String.format(Locale.US, "%d", (int)getData(player).directionVL);
+ }
+ else
+ {
+ return super.getParameter(wildcard, player);
+ }
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/ReachCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/ReachCheck.java
new file mode 100644
index 000000000..6e13a9348
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/blockplace/ReachCheck.java
@@ -0,0 +1,75 @@
+package com.earth2me.essentials.anticheat.checks.blockplace;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.actions.ParameterName;
+import com.earth2me.essentials.anticheat.checks.CheckUtil;
+import com.earth2me.essentials.anticheat.data.SimpleLocation;
+import com.earth2me.essentials.anticheat.data.Statistics.Id;
+import java.util.Locale;
+
+
+/**
+ * The reach check will find out if a player interacts with something that's too far away
+ *
+ */
+public class ReachCheck extends BlockPlaceCheck
+{
+ public ReachCheck(NoCheat plugin)
+ {
+ super(plugin, "blockplace.reach");
+ }
+
+ public boolean check(NoCheatPlayer player, BlockPlaceData data, BlockPlaceConfig cc)
+ {
+
+ boolean cancel = false;
+
+ final SimpleLocation placedAgainstBlock = data.blockPlacedAgainst;
+
+ // Distance is calculated from eye location to center of targeted block
+ // If the player is further away from his target than allowed, the
+ // difference will be assigned to "distance"
+ final double distance = CheckUtil.reachCheck(player, placedAgainstBlock.x + 0.5D, placedAgainstBlock.y + 0.5D, placedAgainstBlock.z + 0.5D, player.isCreative() ? cc.reachDistance + 2 : cc.reachDistance);
+
+ if (distance <= 0D)
+ {
+ // Player passed the check, reward him
+ data.reachVL *= 0.9D;
+ }
+ else
+ {
+ // He failed, increment violation level and statistics
+ data.reachVL += distance;
+ incrementStatistics(player, Id.BP_REACH, distance);
+
+ // Remember how much further than allowed he tried to reach for
+ // logging, if necessary
+ data.reachdistance = distance;
+
+ // Execute whatever actions are associated with this check and the
+ // violation level and find out if we should cancel the event
+ cancel = executeActions(player, cc.reachActions, data.reachVL);
+ }
+
+ return cancel;
+ }
+
+ @Override
+ public String getParameter(ParameterName wildcard, NoCheatPlayer player)
+ {
+
+ if (wildcard == ParameterName.VIOLATIONS)
+ {
+ return String.format(Locale.US, "%d", (int)getData(player).reachVL);
+ }
+ else if (wildcard == ParameterName.REACHDISTANCE)
+ {
+ return String.format(Locale.US, "%.2f", getData(player).reachdistance);
+ }
+ else
+ {
+ return super.getParameter(wildcard, player);
+ }
+ }
+}