summaryrefslogtreecommitdiffstats
path: root/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory
diff options
context:
space:
mode:
Diffstat (limited to 'EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory')
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/DropCheck.java71
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantBowCheck.java72
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantEatCheck.java78
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheck.java63
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheckListener.java196
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryConfig.java40
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryData.java25
7 files changed, 545 insertions, 0 deletions
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/DropCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/DropCheck.java
new file mode 100644
index 000000000..2e9d030f7
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/DropCheck.java
@@ -0,0 +1,71 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.actions.ParameterName;
+import com.earth2me.essentials.anticheat.data.Statistics.Id;
+import java.util.Locale;
+
+
+/**
+ * The DropCheck will find out if a player drops too many items within a short amount of time
+ *
+ */
+public class DropCheck extends InventoryCheck
+{
+ public DropCheck(NoCheat plugin)
+ {
+ super(plugin, "inventory.drop");
+ }
+
+ public boolean check(NoCheatPlayer player, InventoryData data, InventoryConfig cc)
+ {
+
+ boolean cancel = false;
+
+ final long time = System.currentTimeMillis();
+
+ // Has the configured time passed? If so, reset the counter
+ if (data.dropLastTime + cc.dropTimeFrame <= time)
+ {
+ data.dropLastTime = time;
+ data.dropCount = 0;
+ data.dropVL = 0;
+ }
+ // Security check, if the system time changes
+ else if (data.dropLastTime > time)
+ {
+ data.dropLastTime = Integer.MIN_VALUE;
+ }
+
+ data.dropCount++;
+
+ // The player dropped more than he should
+ if (data.dropCount > cc.dropLimit)
+ {
+ // Set vl and increment statistics
+ data.dropVL = data.dropCount - cc.dropLimit;
+ incrementStatistics(player, Id.INV_DROP, 1);
+
+ // 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.dropActions, data.dropVL);
+ }
+
+ return cancel;
+ }
+
+ @Override
+ public String getParameter(ParameterName wildcard, NoCheatPlayer player)
+ {
+
+ if (wildcard == ParameterName.VIOLATIONS)
+ {
+ return String.format(Locale.US, "%d", getData(player).dropVL);
+ }
+ else
+ {
+ return super.getParameter(wildcard, player);
+ }
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantBowCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantBowCheck.java
new file mode 100644
index 000000000..7d4fcf3bb
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantBowCheck.java
@@ -0,0 +1,72 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.actions.ParameterName;
+import com.earth2me.essentials.anticheat.data.Statistics.Id;
+import java.util.Locale;
+import org.bukkit.event.entity.EntityShootBowEvent;
+
+
+/**
+ * The InstantBowCheck will find out if a player pulled the string of his bow too fast
+ */
+public class InstantBowCheck extends InventoryCheck
+{
+ public InstantBowCheck(NoCheat plugin)
+ {
+ super(plugin, "inventory.instantbow");
+ }
+
+ public boolean check(NoCheatPlayer player, EntityShootBowEvent event, InventoryData data, InventoryConfig cc)
+ {
+
+ boolean cancelled = false;
+
+ long time = System.currentTimeMillis();
+
+ // How fast will the arrow be?
+ float bowForce = event.getForce();
+
+ // Rough estimation of how long pulling the string should've taken
+ long expectedTimeWhenStringDrawn = data.lastBowInteractTime + (int)(bowForce * bowForce * 700F);
+
+ if (expectedTimeWhenStringDrawn < time)
+ {
+ // The player was slow enough, reward him by lowering the vl
+ data.instantBowVL *= 0.90D;
+ }
+ else if (data.lastBowInteractTime > time)
+ {
+ // Security check if time ran backwards, reset
+ data.lastBowInteractTime = 0;
+ }
+ else
+ {
+ // Player was too fast, increase violation level and statistics
+ int vl = ((int)(expectedTimeWhenStringDrawn - time)) / 100;
+ data.instantBowVL += vl;
+ incrementStatistics(player, Id.INV_BOW, vl);
+
+ // Execute whatever actions are associated with this check and the
+ // violation level and find out if we should cancel the event
+ cancelled = executeActions(player, cc.bowActions, data.instantBowVL);
+ }
+
+ return cancelled;
+ }
+
+ @Override
+ public String getParameter(ParameterName wildcard, NoCheatPlayer player)
+ {
+
+ if (wildcard == ParameterName.VIOLATIONS)
+ {
+ return String.format(Locale.US, "%d", getData(player).instantBowVL);
+ }
+ else
+ {
+ return super.getParameter(wildcard, player);
+ }
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantEatCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantEatCheck.java
new file mode 100644
index 000000000..05a668dd7
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InstantEatCheck.java
@@ -0,0 +1,78 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.actions.ParameterName;
+import com.earth2me.essentials.anticheat.data.Statistics.Id;
+import java.util.Locale;
+import org.bukkit.event.entity.FoodLevelChangeEvent;
+
+
+/**
+ * The InstantEatCheck will find out if a player eats his food too fast
+ */
+public class InstantEatCheck extends InventoryCheck
+{
+ public InstantEatCheck(NoCheat plugin)
+ {
+ super(plugin, "inventory.instanteat");
+ }
+
+ public boolean check(NoCheatPlayer player, FoodLevelChangeEvent event, InventoryData data, InventoryConfig cc)
+ {
+
+ // Hunger level change seems to not be the result of eating
+ if (data.foodMaterial == null || event.getFoodLevel() <= player.getPlayer().getFoodLevel())
+ {
+ return false;
+ }
+
+ boolean cancelled = false;
+
+ long time = System.currentTimeMillis();
+ // rough estimation about how long it should take to eat
+ long expectedTimeWhenEatingFinished = data.lastEatInteractTime + 700;
+
+ if (expectedTimeWhenEatingFinished < time)
+ {
+ // Acceptable, reduce VL to reward the player
+ data.instantEatVL *= 0.60D;
+ }
+ else if (data.lastEatInteractTime > time)
+ {
+ // Security test, if time ran backwards, reset
+ data.lastEatInteractTime = 0;
+ }
+ else
+ {
+ // Player was too fast, increase violation level and statistics
+ int vl = ((int)(expectedTimeWhenEatingFinished - time)) / 100;
+ data.instantEatVL += vl;
+ incrementStatistics(player, Id.INV_EAT, vl);
+
+ // Execute whatever actions are associated with this check and the
+ // violation level and find out if we should cancel the event
+ cancelled = executeActions(player, cc.eatActions, data.instantEatVL);
+ }
+
+ return cancelled;
+ }
+
+ @Override
+ public String getParameter(ParameterName wildcard, NoCheatPlayer player)
+ {
+
+ if (wildcard == ParameterName.VIOLATIONS)
+ {
+ return String.format(Locale.US, "%d", (int)getData(player).instantEatVL);
+ }
+ else if (wildcard == ParameterName.FOOD)
+ {
+ return getData(player).foodMaterial.toString();
+ }
+ else
+ {
+ return super.getParameter(wildcard, player);
+ }
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheck.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheck.java
new file mode 100644
index 000000000..ad60ffa3e
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheck.java
@@ -0,0 +1,63 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.checks.Check;
+import com.earth2me.essentials.anticheat.config.ConfigurationCacheStore;
+import com.earth2me.essentials.anticheat.data.DataStore;
+
+
+/**
+ * Abstract base class for Inventory checks, provides some convenience methods for access to data and config that's
+ * relevant to this checktype
+ */
+public abstract class InventoryCheck extends Check
+{
+ private static final String id = "inventory";
+
+ public InventoryCheck(NoCheat plugin, String name)
+ {
+ super(plugin, id, name);
+ }
+
+ /**
+ * Get the "InventoryData" object that belongs to the player. Will ensure that such a object exists and if not,
+ * create one
+ *
+ * @param player
+ * @return
+ */
+ public static InventoryData getData(NoCheatPlayer player)
+ {
+ DataStore base = player.getDataStore();
+ InventoryData data = base.get(id);
+ if (data == null)
+ {
+ data = new InventoryData();
+ base.set(id, data);
+ }
+ return data;
+ }
+
+ /**
+ * Get the InventoryConfig object that belongs to the world that the player currently resides in.
+ *
+ * @param player
+ * @return
+ */
+ public static InventoryConfig getConfig(NoCheatPlayer player)
+ {
+ return getConfig(player.getConfigurationStore());
+ }
+
+ public static InventoryConfig getConfig(ConfigurationCacheStore cache)
+ {
+ InventoryConfig config = cache.get(id);
+ if (config == null)
+ {
+ config = new InventoryConfig(cache.getConfiguration());
+ cache.set(id, config);
+ }
+ return config;
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheckListener.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheckListener.java
new file mode 100644
index 000000000..f42a37185
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryCheckListener.java
@@ -0,0 +1,196 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+import com.earth2me.essentials.anticheat.EventManager;
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.checks.CheckUtil;
+import com.earth2me.essentials.anticheat.config.ConfigurationCacheStore;
+import com.earth2me.essentials.anticheat.config.Permissions;
+import java.util.LinkedList;
+import java.util.List;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.entity.EntityShootBowEvent;
+import org.bukkit.event.entity.FoodLevelChangeEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+
+
+/**
+ * Central location to listen to events that are relevant for the inventory checks
+ *
+ */
+public class InventoryCheckListener implements Listener, EventManager
+{
+ private final DropCheck dropCheck;
+ private final InstantBowCheck instantBowCheck;
+ private final InstantEatCheck instantEatCheck;
+ private final NoCheat plugin;
+
+ public InventoryCheckListener(NoCheat plugin)
+ {
+
+ this.dropCheck = new DropCheck(plugin);
+ this.instantBowCheck = new InstantBowCheck(plugin);
+ this.instantEatCheck = new InstantEatCheck(plugin);
+
+ this.plugin = plugin;
+ }
+
+ /**
+ * We listen to DropItem Event for the dropCheck
+ *
+ * @param event The PlayerDropItem Event
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ protected void handlePlayerDropItemEvent(final PlayerDropItemEvent event)
+ {
+
+ if (event.isCancelled() || event.getPlayer().isDead())
+ {
+ return;
+ }
+
+ boolean cancelled = false;
+
+ final NoCheatPlayer player = plugin.getPlayer(event.getPlayer());
+ final InventoryConfig cc = InventoryCheck.getConfig(player);
+ final InventoryData data = InventoryCheck.getData(player);
+
+ // If it should be executed, do it
+ if (cc.dropCheck && !player.hasPermission(Permissions.INVENTORY_DROP))
+ {
+ cancelled = dropCheck.check(player, data, cc);
+ }
+
+ if (cancelled)
+ {
+ // Cancelling drop events is not save (in certain circumstances
+ // items will disappear completely). So don't do it and kick
+ // players instead by default
+ // event.setCancelled(true);
+ }
+ }
+
+ /**
+ * We listen to PlayerInteractEvent for the instantEat and instantBow checks
+ *
+ * @param event The PlayerInteractEvent
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void interact(final PlayerInteractEvent event)
+ {
+
+ // Only interested in right-clicks while holding an item
+ if (!event.hasItem() || !(event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK))
+ {
+ return;
+ }
+
+ NoCheatPlayer player = plugin.getPlayer(event.getPlayer());
+ final InventoryData data = InventoryCheck.getData(player);
+
+ if (event.getItem().getType() == Material.BOW)
+ {
+ // It was a bow, the player starts to pull the string
+ // Remember this time
+ data.lastBowInteractTime = System.currentTimeMillis();
+ }
+ else if (CheckUtil.isFood(event.getItem()))
+ {
+ // It was food, the player starts to eat some food
+ // Remember this time and the type of food
+ data.foodMaterial = event.getItem().getType();
+ data.lastEatInteractTime = System.currentTimeMillis();
+ }
+ else
+ {
+ // Nothing that we are interested in, reset data
+ data.lastBowInteractTime = 0;
+ data.lastEatInteractTime = 0;
+ data.foodMaterial = null;
+ }
+ }
+
+ /**
+ * We listen to FoodLevelChange Event because Bukkit doesn't provide a PlayerFoodEating Event (or whatever it would
+ * be called).
+ *
+ * @param event The FoodLevelChangeEvent
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void foodchanged(final FoodLevelChangeEvent event)
+ {
+ // Only if a player ate food
+ if (!event.isCancelled() && event.getEntity() instanceof Player)
+ {
+ final NoCheatPlayer player = plugin.getPlayer((Player)event.getEntity());
+ final InventoryConfig cc = InventoryCheck.getConfig(player);
+ final InventoryData data = InventoryCheck.getData(player);
+
+ // Only if he should get checked
+ if (cc.eatCheck && !player.hasPermission(Permissions.INVENTORY_INSTANTEAT))
+ {
+
+ boolean cancelled = instantEatCheck.check(player, event, data, cc);
+
+ // The check requested the foodlevelchange to get cancelled
+ event.setCancelled(cancelled);
+ }
+
+ // Forget the food material, as the info is no longer needed
+ data.foodMaterial = null;
+ }
+
+ }
+
+ /**
+ * We listen to EntityShootBowEvent for the instantbow check
+ *
+ * @param event The EntityShootBowEvent
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void bowfired(final EntityShootBowEvent event)
+ {
+ // Only if a player shot the arrow
+ if (!event.isCancelled() && event.getEntity() instanceof Player)
+ {
+ final NoCheatPlayer player = plugin.getPlayer((Player)event.getEntity());
+ final InventoryConfig cc = InventoryCheck.getConfig(player);
+
+ // Only if he should get checked
+ if (cc.bowCheck && !player.hasPermission(Permissions.INVENTORY_INSTANTBOW))
+ {
+ final InventoryData data = InventoryCheck.getData(player);
+ boolean cancelled = instantBowCheck.check(player, event, data, cc);
+
+ // The check requested the bowshooting to get cancelled
+ event.setCancelled(cancelled);
+ }
+ }
+ }
+
+ public List<String> getActiveChecks(ConfigurationCacheStore cc)
+ {
+ LinkedList<String> s = new LinkedList<String>();
+
+ InventoryConfig i = InventoryCheck.getConfig(cc);
+ if (i.dropCheck)
+ {
+ s.add("inventory.dropCheck");
+ }
+ if (i.bowCheck)
+ {
+ s.add("inventory.instantbow");
+ }
+ if (i.eatCheck)
+ {
+ s.add("inventory.instanteat");
+ }
+ return s;
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryConfig.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryConfig.java
new file mode 100644
index 000000000..44f59ff04
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryConfig.java
@@ -0,0 +1,40 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+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 "Inventory" 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 InventoryConfig implements ConfigItem
+{
+ public final boolean dropCheck;
+ public final long dropTimeFrame;
+ public final int dropLimit;
+ public final ActionList dropActions;
+ public final boolean bowCheck;
+ public final ActionList bowActions;
+ public final boolean eatCheck;
+ public final ActionList eatActions;
+
+ public InventoryConfig(NoCheatConfiguration data)
+ {
+
+ dropCheck = data.getBoolean(ConfPaths.INVENTORY_DROP_CHECK);
+ dropTimeFrame = data.getInt(ConfPaths.INVENTORY_DROP_TIMEFRAME) * 1000;
+ dropLimit = data.getInt(ConfPaths.INVENTORY_DROP_LIMIT);
+ dropActions = data.getActionList(ConfPaths.INVENTORY_DROP_ACTIONS, Permissions.INVENTORY_DROP);
+
+ bowCheck = data.getBoolean(ConfPaths.INVENTORY_INSTANTBOW_CHECK);
+ bowActions = data.getActionList(ConfPaths.INVENTORY_INSTANTBOW_ACTIONS, Permissions.INVENTORY_INSTANTBOW);
+
+ eatCheck = data.getBoolean(ConfPaths.INVENTORY_INSTANTEAT_CHECK);
+ eatActions = data.getActionList(ConfPaths.INVENTORY_INSTANTEAT_ACTIONS, Permissions.INVENTORY_INSTANTEAT);
+ }
+}
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryData.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryData.java
new file mode 100644
index 000000000..daeef8679
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/inventory/InventoryData.java
@@ -0,0 +1,25 @@
+package com.earth2me.essentials.anticheat.checks.inventory;
+
+import com.earth2me.essentials.anticheat.DataItem;
+import org.bukkit.Material;
+
+
+/**
+ * Player specific data for the inventory checks
+ *
+ */
+public class InventoryData implements DataItem
+{
+ // Keep track of the violation levels of the three checks
+ public int dropVL;
+ public int instantBowVL;
+ public double instantEatVL;
+ // Time and amount of dropped items
+ public long dropLastTime;
+ public int dropCount;
+ // Times when bow shootinhg and eating started
+ public long lastBowInteractTime;
+ public long lastEatInteractTime;
+ // What the player is eating
+ public Material foodMaterial;
+}