diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/fight/FightCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/fight/FightCheck.java index 84f4f207..fef7cf8c 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/fight/FightCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/fight/FightCheck.java @@ -7,8 +7,8 @@ import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; import cc.co.evenprime.bukkit.nocheat.data.DataStore; /** - * Check various things related to fighting players/entities - * + * Abstract base class for Fight checks, provides some convenience + * methods for access to data and config that's relevant to this checktype */ public abstract class FightCheck extends Check { diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/DropCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/DropCheck.java index 83428ca3..87ccc0b1 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/DropCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/DropCheck.java @@ -6,6 +6,11 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer; import cc.co.evenprime.bukkit.nocheat.actions.ParameterName; import cc.co.evenprime.bukkit.nocheat.data.Statistics.Id; +/** + * 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) { @@ -16,11 +21,13 @@ public class DropCheck extends InventoryCheck { boolean cancel = false; - final long time = System.currentTimeMillis() / 1000; + 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) { @@ -29,21 +36,25 @@ public class DropCheck extends InventoryCheck { 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.getDataStore()).dropVL); + return String.format(Locale.US, "%d", getData(player).dropVL); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantBowCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantBowCheck.java index 45f512e2..a777f2a8 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantBowCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantBowCheck.java @@ -7,6 +7,10 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer; import cc.co.evenprime.bukkit.nocheat.actions.ParameterName; import cc.co.evenprime.bukkit.nocheat.data.Statistics.Id; +/** + * 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) { @@ -18,30 +22,38 @@ public class InstantBowCheck extends InventoryCheck { 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) { - // Acceptable, reduce VL + // The player was slow enough, reward him by lowering the vl data.instantBowVL *= 0.90D; } else if(data.lastBowInteractTime > time) { - // Security, if time ran backwards, reset + // Security check if time ran backwards, reset data.lastBowInteractTime = 0; } else { - // Seems fishy, increase violation level + // 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", (int) getData(player.getDataStore()).instantBowVL); + return String.format(Locale.US, "%d", (int) getData(player).instantBowVL); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantEatCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantEatCheck.java index b9d4d6e1..d499b79b 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantEatCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InstantEatCheck.java @@ -7,6 +7,9 @@ import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer; import cc.co.evenprime.bukkit.nocheat.actions.ParameterName; import cc.co.evenprime.bukkit.nocheat.data.Statistics.Id; +/** + * The InstantEatCheck will find out if a player eats his food too fast + */ public class InstantEatCheck extends InventoryCheck { public InstantEatCheck(NoCheat plugin) { @@ -15,38 +18,43 @@ public class InstantEatCheck extends InventoryCheck { public boolean check(NoCheatPlayer player, FoodLevelChangeEvent event, InventoryData data, InventoryConfig cc) { - // Seems to be not the result of eating + // 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 - data.instantEatVL *= 0.98D; + // Acceptable, reduce VL to reward the player + data.instantEatVL *= 0.60D; } else if(data.lastEatInteractTime > time) { - // Security, if time ran backwards, reset + // Security test, if time ran backwards, reset data.lastEatInteractTime = 0; } else { - // Seems fishy, increase violation level + // 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.getDataStore()).instantEatVL); + return String.format(Locale.US, "%d", (int) getData(player).instantEatVL); else if(wildcard == ParameterName.FOOD) - return getData(player.getDataStore()).foodMaterial.toString(); + return getData(player).foodMaterial.toString(); else return super.getParameter(wildcard, player); } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheck.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheck.java index 5e0f4577..9d06ab94 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheck.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheck.java @@ -1,10 +1,15 @@ package cc.co.evenprime.bukkit.nocheat.checks.inventory; import cc.co.evenprime.bukkit.nocheat.NoCheat; +import cc.co.evenprime.bukkit.nocheat.NoCheatPlayer; import cc.co.evenprime.bukkit.nocheat.checks.Check; import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; import cc.co.evenprime.bukkit.nocheat.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"; @@ -13,7 +18,15 @@ public abstract class InventoryCheck extends Check { super(plugin, id, name); } - public static InventoryData getData(DataStore base) { + /** + * 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(); @@ -22,6 +35,17 @@ public abstract class InventoryCheck extends Check { 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) { diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheckListener.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheckListener.java index 0552e5cb..a87e9161 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheckListener.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryCheckListener.java @@ -19,6 +19,11 @@ import cc.co.evenprime.bukkit.nocheat.checks.CheckUtil; import cc.co.evenprime.bukkit.nocheat.config.ConfigurationCacheStore; import cc.co.evenprime.bukkit.nocheat.config.Permissions; +/** + * Central location to listen to events that are + * relevant for the inventory checks + * + */ public class InventoryCheckListener implements Listener, EventManager { private final DropCheck dropCheck; @@ -36,6 +41,10 @@ public class InventoryCheckListener implements Listener, EventManager { 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) { @@ -45,8 +54,8 @@ public class InventoryCheckListener implements Listener, EventManager { boolean cancelled = false; final NoCheatPlayer player = plugin.getPlayer(event.getPlayer()); - final InventoryConfig cc = InventoryCheck.getConfig(player.getConfigurationStore()); - final InventoryData data = InventoryCheck.getData(player.getDataStore()); + 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)) { @@ -54,62 +63,93 @@ public class InventoryCheckListener implements Listener, EventManager { } if(cancelled) { - // Cancelling drop events is not save. So don't do it - // and kick players instead by default - //event.setCancelled(true); + // 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.getDataStore()); + 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())) { - // Remember food Material, because we don't have that info in the other event + // 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.getConfigurationStore()); - final InventoryData data = InventoryCheck.getData(player.getDataStore()); + 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.getConfigurationStore()); + 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.getDataStore()); + 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); } } diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryConfig.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryConfig.java index 176d123a..4b8f738d 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryConfig.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryConfig.java @@ -6,6 +6,12 @@ import cc.co.evenprime.bukkit.nocheat.config.ConfPaths; import cc.co.evenprime.bukkit.nocheat.config.NoCheatConfiguration; import cc.co.evenprime.bukkit.nocheat.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; @@ -22,7 +28,7 @@ public class InventoryConfig implements ConfigItem { public InventoryConfig(NoCheatConfiguration data) { dropCheck = data.getBoolean(ConfPaths.INVENTORY_DROP_CHECK); - dropTimeFrame = data.getInt(ConfPaths.INVENTORY_DROP_TIMEFRAME); + 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); diff --git a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryData.java b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryData.java index c8421fe5..808a825c 100644 --- a/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryData.java +++ b/src/cc/co/evenprime/bukkit/nocheat/checks/inventory/InventoryData.java @@ -3,16 +3,25 @@ package cc.co.evenprime.bukkit.nocheat.checks.inventory; import org.bukkit.Material; import cc.co.evenprime.bukkit.nocheat.DataItem; +/** + * 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; - public int instantBowVL; + // Times when bow shootinhg and eating started public long lastBowInteractTime; - - public double instantEatVL; public long lastEatInteractTime; + + // What the player is eating public Material foodMaterial; }