diff --git a/src/fr/neatmonster/nocheatplus/CommandHandler.java b/src/fr/neatmonster/nocheatplus/CommandHandler.java index 0ce20b65..cde51e0f 100644 --- a/src/fr/neatmonster/nocheatplus/CommandHandler.java +++ b/src/fr/neatmonster/nocheatplus/CommandHandler.java @@ -10,6 +10,7 @@ import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakConfig; import fr.neatmonster.nocheatplus.checks.blockplace.BlockPlaceConfig; import fr.neatmonster.nocheatplus.checks.chat.ChatConfig; import fr.neatmonster.nocheatplus.checks.fight.FightConfig; +import fr.neatmonster.nocheatplus.checks.inventory.InventoryConfig; import fr.neatmonster.nocheatplus.checks.moving.MovingConfig; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigManager; @@ -67,6 +68,7 @@ public class CommandHandler implements CommandExecutor { BlockPlaceConfig.clear(); ChatConfig.clear(); FightConfig.clear(); + InventoryConfig.clear(); MovingConfig.clear(); sender.sendMessage(ChatColor.RED + "NCP: " + ChatColor.WHITE + "Configuration reloaded!"); diff --git a/src/fr/neatmonster/nocheatplus/NoCheatPlus.java b/src/fr/neatmonster/nocheatplus/NoCheatPlus.java index b6dc52b7..f8907bf5 100644 --- a/src/fr/neatmonster/nocheatplus/NoCheatPlus.java +++ b/src/fr/neatmonster/nocheatplus/NoCheatPlus.java @@ -17,6 +17,7 @@ import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakListener; import fr.neatmonster.nocheatplus.checks.blockplace.BlockPlaceListener; import fr.neatmonster.nocheatplus.checks.chat.ChatListener; import fr.neatmonster.nocheatplus.checks.fight.FightListener; +import fr.neatmonster.nocheatplus.checks.inventory.InventoryListener; import fr.neatmonster.nocheatplus.checks.moving.MovingListener; import fr.neatmonster.nocheatplus.config.ConfPaths; import fr.neatmonster.nocheatplus.config.ConfigManager; @@ -74,6 +75,7 @@ public class NoCheatPlus extends JavaPlugin implements Listener { listeners.add(new BlockPlaceListener()); listeners.add(new ChatListener()); listeners.add(new FightListener()); + listeners.add(new InventoryListener()); listeners.add(new MovingListener()); listeners.add(new Workarounds()); diff --git a/src/fr/neatmonster/nocheatplus/actions/ParameterName.java b/src/fr/neatmonster/nocheatplus/actions/ParameterName.java index 2b17862c..087bb480 100644 --- a/src/fr/neatmonster/nocheatplus/actions/ParameterName.java +++ b/src/fr/neatmonster/nocheatplus/actions/ParameterName.java @@ -24,13 +24,14 @@ public enum ParameterName { ATTACKS_LIMIT("attackslimit"), CHECK("check"), DISTANCE("distance"), - FALLDISTANCE("falldistance"), + FALL_DISTANCE("falldistance"), + FOOD("food"), IP("ip"), LOCATION_FROM("locationfrom"), LOCATION_TO("locationto"), PACKETS("packets"), PLAYER("player"), - REACHDISTANCE("reachdistance"), + REACH_DISTANCE("reachdistance"), VIOLATIONS("violations"), WORLD("world"); /** diff --git a/src/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java b/src/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java index 86094255..c6c6cb8f 100644 --- a/src/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java +++ b/src/fr/neatmonster/nocheatplus/checks/blockbreak/Reach.java @@ -90,7 +90,7 @@ public class Reach extends Check { public String getParameter(final ParameterName wildcard, final Player player) { if (wildcard == ParameterName.VIOLATIONS) return String.valueOf(Math.round(BlockBreakData.getData(player).reachVL)); - else if (wildcard == ParameterName.REACHDISTANCE) + else if (wildcard == ParameterName.REACH_DISTANCE) return String.valueOf(Math.round(BlockBreakData.getData(player).reachDistance)); else return super.getParameter(wildcard, player); diff --git a/src/fr/neatmonster/nocheatplus/checks/blockplace/Reach.java b/src/fr/neatmonster/nocheatplus/checks/blockplace/Reach.java index 7491e8b8..38d11ca9 100644 --- a/src/fr/neatmonster/nocheatplus/checks/blockplace/Reach.java +++ b/src/fr/neatmonster/nocheatplus/checks/blockplace/Reach.java @@ -89,7 +89,7 @@ public class Reach extends Check { public String getParameter(final ParameterName wildcard, final Player player) { if (wildcard == ParameterName.VIOLATIONS) return String.valueOf(Math.round(BlockPlaceData.getData(player).reachVL)); - else if (wildcard == ParameterName.REACHDISTANCE) + else if (wildcard == ParameterName.REACH_DISTANCE) return String.valueOf(Math.round(BlockPlaceData.getData(player).reachDistance)); else return super.getParameter(wildcard, player); diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java index fe83c9f1..06ccd524 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/ChatListener.java @@ -5,7 +5,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; @@ -38,7 +38,7 @@ public class ChatListener implements Listener { */ @EventHandler( ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerChat(final PlayerChatEvent event) { + public void onPlayerChat(final AsyncPlayerChatEvent event) { /* * ____ _ ____ _ _ * | _ \| | __ _ _ _ ___ _ __ / ___| |__ __ _| |_ diff --git a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java index ac290453..03544285 100644 --- a/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java +++ b/src/fr/neatmonster/nocheatplus/checks/chat/NoPwnage.java @@ -4,7 +4,7 @@ import java.util.Random; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerEvent; @@ -128,8 +128,8 @@ public class NoPwnage extends Check { if (!data.noPwnageHasFilledCaptcha) { String message = ""; - if (event instanceof PlayerChatEvent) - message = ((PlayerChatEvent) event).getMessage(); + if (event instanceof AsyncPlayerChatEvent) + message = ((AsyncPlayerChatEvent) event).getMessage(); else if (event instanceof PlayerCommandPreprocessEvent) message = ((PlayerCommandPreprocessEvent) event).getMessage(); final boolean isCommand = event instanceof PlayerCommandPreprocessEvent; @@ -164,8 +164,8 @@ public class NoPwnage extends Check { } // Cancel the event and return. - if (event instanceof PlayerChatEvent) - ((PlayerChatEvent) event).setCancelled(true); + if (event instanceof AsyncPlayerChatEvent) + ((AsyncPlayerChatEvent) event).setCancelled(true); else if (event instanceof PlayerCommandPreprocessEvent) ((PlayerCommandPreprocessEvent) event).setCancelled(true); return cancel; @@ -234,8 +234,8 @@ public class NoPwnage extends Check { player.sendMessage(replaceColors(cc.noPwnageCaptchaQuestion.replace("[captcha]", data.noPwnageGeneratedCaptcha))); data.noPwnageHasStartedCaptcha = true; - if (event instanceof PlayerChatEvent) - ((PlayerChatEvent) event).setCancelled(true); + if (event instanceof AsyncPlayerChatEvent) + ((AsyncPlayerChatEvent) event).setCancelled(true); else if (event instanceof PlayerCommandPreprocessEvent) ((PlayerCommandPreprocessEvent) event).setCancelled(true); } else { @@ -244,8 +244,8 @@ public class NoPwnage extends Check { if (cc.noPwnageWarnOthersCheck) Bukkit.broadcastMessage(replaceColors(cc.noPwnageWarnOthersMessage.replace("[player]", player.getName()))); - if (event instanceof PlayerChatEvent) - ((PlayerChatEvent) event).setCancelled(true); + if (event instanceof AsyncPlayerChatEvent) + ((AsyncPlayerChatEvent) event).setCancelled(true); else if (event instanceof PlayerCommandPreprocessEvent) ((PlayerCommandPreprocessEvent) event).setCancelled(true); diff --git a/src/fr/neatmonster/nocheatplus/checks/inventory/Drop.java b/src/fr/neatmonster/nocheatplus/checks/inventory/Drop.java new file mode 100644 index 00000000..12fe2314 --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/inventory/Drop.java @@ -0,0 +1,103 @@ +package fr.neatmonster.nocheatplus.checks.inventory; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.actions.ParameterName; +import fr.neatmonster.nocheatplus.checks.Check; +import fr.neatmonster.nocheatplus.checks.CheckEvent; +import fr.neatmonster.nocheatplus.players.Permissions; + +/* + * M""""""'YMM + * M mmmm. `M + * M MMMMM M 88d888b. .d8888b. 88d888b. + * M MMMMM M 88' `88 88' `88 88' `88 + * M MMMM' .M 88 88. .88 88. .88 + * M .MM dP `88888P' 88Y888P' + * MMMMMMMMMMM 88 + * dP + */ +/** + * The Drop check will find out if a player drops too many items within a short amount of time. + */ +public class Drop extends Check { + + /** + * The event triggered by this check. + */ + public class DropEvent extends CheckEvent { + + /** + * Instantiates a new drop event. + * + * @param player + * the player + */ + public DropEvent(final Player player) { + super(player); + } + } + + /** + * Checks a player. + * + * @param player + * the player + * @return true, if successful + */ + public boolean check(final Player player) { + final InventoryConfig cc = InventoryConfig.getConfig(player); + final InventoryData data = InventoryData.getData(player); + + boolean cancel = false; + + // Has the configured time passed? If so, reset the counter. + if (data.dropLastTime + cc.dropTimeFrame <= System.currentTimeMillis()) { + data.dropLastTime = System.currentTimeMillis(); + data.dropCount = 0; + data.dropVL = 0D; + } + + // Security check, if the system time changes. + else if (data.dropLastTime > System.currentTimeMillis()) + data.dropLastTime = Integer.MIN_VALUE; + + data.dropCount++; + + // The player dropped more than he should. + if (data.dropCount > cc.dropLimit) { + // Set his violation level. + data.dropVL = data.dropCount - cc.dropLimit; + + // Dispatch a drop event (API). + final DropEvent e = new DropEvent(player); + Bukkit.getPluginManager().callEvent(e); + + // Execute whatever actions are associated with this check and the violation level and find out if we should + // cancel the event. + cancel = !e.isCancelled() && executeActions(player, cc.dropActions, data.dropVL); + } + + return cancel; + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#getParameter(fr.neatmonster.nocheatplus.actions.ParameterName, org.bukkit.entity.Player) + */ + @Override + public String getParameter(final ParameterName wildcard, final Player player) { + if (wildcard == ParameterName.VIOLATIONS) + return String.valueOf(Math.round(InventoryData.getData(player).dropVL)); + else + return super.getParameter(wildcard, player); + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#isEnabled(org.bukkit.entity.Player) + */ + @Override + protected boolean isEnabled(final Player player) { + return !player.hasPermission(Permissions.INVENTORY_DROP) && InventoryConfig.getConfig(player).dropCheck; + } +} diff --git a/src/fr/neatmonster/nocheatplus/checks/inventory/InstantBow.java b/src/fr/neatmonster/nocheatplus/checks/inventory/InstantBow.java new file mode 100644 index 00000000..e60d46fe --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/inventory/InstantBow.java @@ -0,0 +1,100 @@ +package fr.neatmonster.nocheatplus.checks.inventory; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.actions.ParameterName; +import fr.neatmonster.nocheatplus.checks.Check; +import fr.neatmonster.nocheatplus.checks.CheckEvent; +import fr.neatmonster.nocheatplus.players.Permissions; + +/* + * M""M dP dP M#"""""""'M + * M M 88 88 ## mmmm. `M + * M M 88d888b. .d8888b. d8888P .d8888b. 88d888b. d8888P #' .M .d8888b. dP dP dP + * M M 88' `88 Y8ooooo. 88 88' `88 88' `88 88 M# MMMb.'YM 88' `88 88 88 88 + * M M 88 88 88 88 88. .88 88 88 88 M# MMMM' M 88. .88 88.88b.88' + * M M dP dP `88888P' dP `88888P8 dP dP dP M# .;M `88888P' 8888P Y8P + * MMMM M#########M + */ +/** + * The InstantBow check will find out if a player pulled the string of his bow too fast. + */ +public class InstantBow extends Check { + + /** + * The event triggered by this check. + */ + public class InstantBowEvent extends CheckEvent { + + /** + * Instantiates a new instant bow event. + * + * @param player + * the player + */ + public InstantBowEvent(final Player player) { + super(player); + } + } + + /** + * Checks a player. + * + * @param player + * the player + * @param force + * the force + * @return true, if successful + */ + public boolean check(final Player player, final float force) { + final InventoryConfig cc = InventoryConfig.getConfig(player); + final InventoryData data = InventoryData.getData(player); + + boolean cancel = false; + + // Rough estimation of how long pulling the string should've taken. + final long expectedTimeWhenStringDrawn = data.instantBowLastTime + (int) (force * force * 700F); + + if (expectedTimeWhenStringDrawn < System.currentTimeMillis()) + // The player was slow enough, reward him by lowering his violation level. + data.instantBowVL *= 0.9D; + else if (data.instantBowLastTime > System.currentTimeMillis()) + // Security check if time ran backwards, reset + data.instantBowLastTime = 0L; + else { + // Player was too fast, increase his violation level. + data.instantBowVL += (expectedTimeWhenStringDrawn - System.currentTimeMillis()) / 100D; + + // Dispatch an instant bow event (API). + final InstantBowEvent e = new InstantBowEvent(player); + Bukkit.getPluginManager().callEvent(e); + + // Execute whatever actions are associated with this check and the + // violation level and find out if we should cancel the event + cancel = !e.isCancelled() && executeActions(player, cc.instantBowActions, data.instantBowVL); + } + + return cancel; + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#getParameter(fr.neatmonster.nocheatplus.actions.ParameterName, org.bukkit.entity.Player) + */ + @Override + public String getParameter(final ParameterName wildcard, final Player player) { + if (wildcard == ParameterName.VIOLATIONS) + return String.valueOf(Math.round(InventoryData.getData(player).instantBowVL)); + else + return super.getParameter(wildcard, player); + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#isEnabled(org.bukkit.entity.Player) + */ + @Override + protected boolean isEnabled(final Player player) { + return !player.hasPermission(Permissions.INVENTORY_INSTANTBOW) + && InventoryConfig.getConfig(player).instantBowCheck; + } +} diff --git a/src/fr/neatmonster/nocheatplus/checks/inventory/InstantEat.java b/src/fr/neatmonster/nocheatplus/checks/inventory/InstantEat.java new file mode 100644 index 00000000..c8d23909 --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/inventory/InstantEat.java @@ -0,0 +1,106 @@ +package fr.neatmonster.nocheatplus.checks.inventory; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.actions.ParameterName; +import fr.neatmonster.nocheatplus.checks.Check; +import fr.neatmonster.nocheatplus.checks.CheckEvent; +import fr.neatmonster.nocheatplus.players.Permissions; + +/* + * M""M dP dP MM""""""""`M dP + * M M 88 88 MM mmmmmmmM 88 + * M M 88d888b. .d8888b. d8888P .d8888b. 88d888b. d8888P M` MMMM .d8888b. d8888P + * M M 88' `88 Y8ooooo. 88 88' `88 88' `88 88 MM MMMMMMMM 88' `88 88 + * M M 88 88 88 88 88. .88 88 88 88 MM MMMMMMMM 88. .88 88 + * M M dP dP `88888P' dP `88888P8 dP dP dP MM .M `88888P8 dP + * MMMM MMMMMMMMMMMM + */ +/** + * The InstantEat check will find out if a player eats his food too fast. + */ +public class InstantEat extends Check { + + /** + * The event triggered by this check. + */ + public class InstantEatEvent extends CheckEvent { + + /** + * Instantiates a new instant eat event. + * + * @param player + * the player + */ + public InstantEatEvent(final Player player) { + super(player); + } + } + + /** + * Checks a player. + * + * @param player + * the player + * @param level + * the level + * @return true, if successful + */ + public boolean check(final Player player, final int level) { + final InventoryConfig cc = InventoryConfig.getConfig(player); + final InventoryData data = InventoryData.getData(player); + + boolean cancel = false; + + // Hunger level change seems to not be the result of eating. + if (data.instantEatFood == null || level <= player.getFoodLevel()) + return false; + + // rough estimation about how long it should take to eat + final long expectedTimeWhenEatingFinished = data.instantEatLastTime + 700L; + + if (expectedTimeWhenEatingFinished < System.currentTimeMillis()) + // Acceptable, reduce VL to reward the player. + data.instantEatVL *= 0.6D; + else if (data.instantEatLastTime > System.currentTimeMillis()) + // Security test, if time ran backwards, reset. + data.instantEatLastTime = 0; + else { + // Player was too fast, increase his violation level. + data.instantEatVL += (expectedTimeWhenEatingFinished - System.currentTimeMillis()) / 100D; + + // Dispatch an instant eat event (API). + final InstantEatEvent e = new InstantEatEvent(player); + Bukkit.getPluginManager().callEvent(e); + + // Execute whatever actions are associated with this check and the violation level and find out if we should + // cancel the event. + cancel = !e.isCancelled() && executeActions(player, cc.instantEatActions, data.instantEatVL); + } + + return cancel; + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#getParameter(fr.neatmonster.nocheatplus.actions.ParameterName, org.bukkit.entity.Player) + */ + @Override + public String getParameter(final ParameterName wildcard, final Player player) { + if (wildcard == ParameterName.VIOLATIONS) + return String.valueOf(Math.round(InventoryData.getData(player).instantEatVL)); + else if (wildcard == ParameterName.FOOD) + return InventoryData.getData(player).instantEatFood.toString(); + else + return super.getParameter(wildcard, player); + } + + /* (non-Javadoc) + * @see fr.neatmonster.nocheatplus.checks.Check#isEnabled(org.bukkit.entity.Player) + */ + @Override + protected boolean isEnabled(final Player player) { + return !player.hasPermission(Permissions.INVENTORY_INSTANTEAT) + && InventoryConfig.getConfig(player).instantEatCheck; + } +} diff --git a/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryConfig.java b/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryConfig.java new file mode 100644 index 00000000..9f606fa7 --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryConfig.java @@ -0,0 +1,94 @@ +package fr.neatmonster.nocheatplus.checks.inventory; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.entity.Player; + +import fr.neatmonster.nocheatplus.actions.types.ActionList; +import fr.neatmonster.nocheatplus.config.ConfPaths; +import fr.neatmonster.nocheatplus.config.ConfigFile; +import fr.neatmonster.nocheatplus.config.ConfigManager; +import fr.neatmonster.nocheatplus.players.Permissions; + +/* + * M""M dP + * M M 88 + * M M 88d888b. dP .dP .d8888b. 88d888b. d8888P .d8888b. 88d888b. dP dP + * M M 88' `88 88 d8' 88ooood8 88' `88 88 88' `88 88' `88 88 88 + * M M 88 88 88 .88' 88. ... 88 88 88 88. .88 88 88. .88 + * M M dP dP 8888P' `88888P' dP dP dP `88888P' dP `8888P88 + * MMMM .88 + * d8888P + * + * MM'""""'YMM .8888b oo + * M' .mmm. `M 88 " + * M MMMMMooM .d8888b. 88d888b. 88aaa dP .d8888b. + * M MMMMMMMM 88' `88 88' `88 88 88 88' `88 + * M. `MMM' .M 88. .88 88 88 88 88 88. .88 + * MM. .dM `88888P' dP dP dP dP `8888P88 + * MMMMMMMMMMM .88 + * d8888P + */ +/** + * 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 { + + /** The map containing the configurations per world. */ + private static Map worldsMap = new HashMap(); + + /** + * Clear all the configurations. + */ + public static void clear() { + worldsMap.clear(); + } + + /** + * Gets the configuration for a specified player. + * + * @param player + * the player + * @return the configuration + */ + public static InventoryConfig getConfig(final Player player) { + if (!worldsMap.containsKey(player.getWorld().getName())) + worldsMap.put(player.getWorld().getName(), + new InventoryConfig(ConfigManager.getConfigFile(player.getWorld().getName()))); + return worldsMap.get(player.getWorld().getName()); + } + + public final boolean dropCheck; + public final int dropLimit; + public final long dropTimeFrame; + public final ActionList dropActions; + + public final boolean instantBowCheck; + public final ActionList instantBowActions; + + public final boolean instantEatCheck; + public final ActionList instantEatActions; + + /** + * Instantiates a new inventory configuration. + * + * @param data + * the data + */ + public InventoryConfig(final ConfigFile data) { + dropCheck = data.getBoolean(ConfPaths.INVENTORY_DROP_CHECK); + dropLimit = data.getInt(ConfPaths.INVENTORY_DROP_LIMIT); + dropTimeFrame = data.getLong(ConfPaths.INVENTORY_DROP_TIMEFRAME); + dropActions = data.getActionList(ConfPaths.INVENTORY_DROP_ACTIONS, Permissions.INVENTORY_DROP); + + instantBowCheck = data.getBoolean(ConfPaths.INVENTORY_INSTANTBOW_CHECK); + instantBowActions = data + .getActionList(ConfPaths.INVENTORY_INSTANTBOW_ACTIONS, Permissions.INVENTORY_INSTANTBOW); + + instantEatCheck = data.getBoolean(ConfPaths.INVENTORY_INSTANTEAT_CHECK); + instantEatActions = data + .getActionList(ConfPaths.INVENTORY_INSTANTEAT_ACTIONS, Permissions.INVENTORY_INSTANTEAT); + } +} diff --git a/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java b/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java new file mode 100644 index 00000000..4a437b26 --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java @@ -0,0 +1,55 @@ +package fr.neatmonster.nocheatplus.checks.inventory; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Material; +import org.bukkit.entity.Player; + +/* + * M""M dP M""""""'YMM dP + * M M 88 M mmmm. `M 88 + * M M 88d888b. dP .dP .d8888b. 88d888b. d8888P .d8888b. 88d888b. dP dP M MMMMM M .d8888b. d8888P .d8888b. + * M M 88' `88 88 d8' 88ooood8 88' `88 88 88' `88 88' `88 88 88 M MMMMM M 88' `88 88 88' `88 + * M M 88 88 88 .88' 88. ... 88 88 88 88. .88 88 88. .88 M MMMM' .M 88. .88 88 88. .88 + * M M dP dP 8888P' `88888P' dP dP dP `88888P' dP `8888P88 M .MM `88888P8 dP `88888P8 + * MMMM .88 MMMMMMMMMMM + * d8888P + */ +/** + * Player specific data for the inventory checks. + */ +public class InventoryData { + + /** The map containing the data per players. */ + private static Map playersMap = new HashMap(); + + /** + * Gets the data of a specified player. + * + * @param player + * the player + * @return the data + */ + public static InventoryData getData(final Player player) { + if (!playersMap.containsKey(player.getName())) + playersMap.put(player.getName(), new InventoryData()); + return playersMap.get(player.getName()); + } + + // Violation levels. + public double dropVL; + public double instantBowVL; + public double instantEatVL; + + // Data of the drop check. + public int dropCount; + public long dropLastTime; + + // Data of the instant bow check. + public long instantBowLastTime; + + // Data of the instant eat check. + public Material instantEatFood; + public long instantEatLastTime; +} diff --git a/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java b/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java new file mode 100644 index 00000000..249ca9fe --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java @@ -0,0 +1,127 @@ +package fr.neatmonster.nocheatplus.checks.inventory; + +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; + +/* + * M""M dP + * M M 88 + * M M 88d888b. dP .dP .d8888b. 88d888b. d8888P .d8888b. 88d888b. dP dP + * M M 88' `88 88 d8' 88ooood8 88' `88 88 88' `88 88' `88 88 88 + * M M 88 88 88 .88' 88. ... 88 88 88 88. .88 88 88. .88 + * M M dP dP 8888P' `88888P' dP dP dP `88888P' dP `8888P88 + * MMMM .88 + * d8888P + * + * M""MMMMMMMM oo dP + * M MMMMMMMM 88 + * M MMMMMMMM dP .d8888b. d8888P .d8888b. 88d888b. .d8888b. 88d888b. + * M MMMMMMMM 88 Y8ooooo. 88 88ooood8 88' `88 88ooood8 88' `88 + * M MMMMMMMM 88 88 88 88. ... 88 88 88. ... 88 + * M M dP `88888P' dP `88888P' dP dP `88888P' dP + * MMMMMMMMMMM + */ +/** + * Central location to listen to events that are relevant for the inventory checks. + */ +public class InventoryListener implements Listener { + private final Drop drop = new Drop(); + private final InstantBow instantBow = new InstantBow(); + private final InstantEat instantEat = new InstantEat(); + + /** + * We listen to EntityShootBow events for the InstantBow check. + * + * @param event + * the event + */ + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onEntityShootBow(final EntityShootBowEvent event) { + // Only if a player shot the arrow. + if (event.getEntity() instanceof Player) { + final Player player = (Player) event.getEntity(); + if (instantBow.isEnabled(player) && instantBow.check(player, event.getForce())) + // The check requested the event to be cancelled. + event.setCancelled(true); + } + } + + /** + * We listen to FoodLevelChange events because Bukkit doesn't provide a PlayerFoodEating Event (or whatever it would + * be called). + * + * @param event + * the event + */ + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onFoodLevelChange(final FoodLevelChangeEvent event) { + // Only if a player ate food. + if (event.getEntity() instanceof Player) { + final Player player = (Player) event.getEntity(); + if (instantEat.isEnabled(player) && instantEat.check(player, event.getFoodLevel())) + event.setCancelled(true); + // Forget the food material, as the info is no longer needed. + InventoryData.getData(player).instantEatFood = null; + } + } + + /** + * We listen to DropItem events for the Drop check. + * + * @param event + * the event + */ + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + protected void onPlayerDropItem(final PlayerDropItemEvent event) { + // If the player died, all his items are dropped so ignore him. + if (event.getPlayer().isDead()) + return; + + if (drop.isEnabled(event.getPlayer()) && drop.check(event.getPlayer())) + // 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.getPlayer().kickPlayer("You're not allowed to crash the server by dropping items!"); + } + + /** + * We listen to PlayerInteract events for the InstantEat and InstantBow checks. + * + * @param event + * the event + */ + @EventHandler( + priority = EventPriority.LOWEST) + public void onPlayerInteractEvent(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; + + final InventoryData data = InventoryData.getData(event.getPlayer()); + + if (event.getItem().getType() == Material.BOW) + // It was a bow, the player starts to pull the string, remember this time. + data.instantBowLastTime = System.currentTimeMillis(); + else if (event.getItem().getType().isEdible()) { + // It was food, the player starts to eat some food, remember this time and the type of food. + data.instantEatFood = event.getItem().getType(); + data.instantEatLastTime = System.currentTimeMillis(); + } else { + // Nothing that we are interested in, reset data. + data.instantBowLastTime = 0; + data.instantEatLastTime = 0; + data.instantEatFood = null; + } + } +} diff --git a/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java b/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java index 3c846efe..c5c742ed 100644 --- a/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java +++ b/src/fr/neatmonster/nocheatplus/checks/moving/NoFall.java @@ -151,7 +151,7 @@ public class NoFall extends Check { public String getParameter(final ParameterName wildcard, final Player player) { if (wildcard == ParameterName.VIOLATIONS) return String.valueOf(Math.round(MovingData.getData(player).noFallVL)); - else if (wildcard == ParameterName.FALLDISTANCE) + else if (wildcard == ParameterName.FALL_DISTANCE) return String.format(Locale.US, "%.2f", MovingData.getData(player).noFallDistance); else return super.getParameter(wildcard, player); diff --git a/src/fr/neatmonster/nocheatplus/config/ConfPaths.java b/src/fr/neatmonster/nocheatplus/config/ConfPaths.java index 71a079cc..87f6c76f 100644 --- a/src/fr/neatmonster/nocheatplus/config/ConfPaths.java +++ b/src/fr/neatmonster/nocheatplus/config/ConfPaths.java @@ -240,6 +240,31 @@ public abstract class ConfPaths { public static final String FIGHT_SPEED_LIMIT = FIGHT_SPEED + "limit"; public static final String FIGHT_SPEED_ACTIONS = FIGHT_SPEED + "actions"; + /* + * 888 d8 + * 888 888 8e Y8b Y888P ,e e, 888 8e d88 e88 88e 888,8, Y8b Y888P + * 888 888 88b Y8b Y8P d88 88b 888 88b d88888 d888 888b 888 " Y8b Y8P + * 888 888 888 Y8b " 888 , 888 888 888 Y888 888P 888 Y8b Y + * 888 888 888 Y8P "YeeP" 888 888 888 "88 88" 888 888 + * 888 + * 888 + */ + private static final String INVENTORY = CHECKS + "inventory."; + + private static final String INVENTORY_DROP = INVENTORY + "drop."; + public static final String INVENTORY_DROP_CHECK = INVENTORY_DROP + "active"; + public static final String INVENTORY_DROP_LIMIT = INVENTORY_DROP + "limit"; + public static final String INVENTORY_DROP_TIMEFRAME = INVENTORY_DROP + "timeframe"; + public static final String INVENTORY_DROP_ACTIONS = INVENTORY_DROP + "actions"; + + private static final String INVENTORY_INSTANTBOW = INVENTORY + "instantbow."; + public static final String INVENTORY_INSTANTBOW_CHECK = INVENTORY_INSTANTBOW + "active"; + public static final String INVENTORY_INSTANTBOW_ACTIONS = INVENTORY_INSTANTBOW + "actions"; + + private static final String INVENTORY_INSTANTEAT = INVENTORY + "instanteat."; + public static final String INVENTORY_INSTANTEAT_CHECK = INVENTORY_INSTANTEAT + "active"; + public static final String INVENTORY_INSTANTEAT_ACTIONS = INVENTORY_INSTANTEAT + "actions"; + /* * e e ,e, * d8b d8b e88 88e Y8b Y888P " 888 8e e88 888 diff --git a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java index 16586394..d864fb0e 100644 --- a/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java +++ b/src/fr/neatmonster/nocheatplus/config/DefaultConfig.java @@ -212,6 +212,26 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.FIGHT_SPEED_LIMIT, 15); set(ConfPaths.FIGHT_SPEED_ACTIONS, "log:fspeed:0:5:if cancel"); + /* + * 888 d8 + * 888 888 8e Y8b Y888P ,e e, 888 8e d88 e88 88e 888,8, Y8b Y888P + * 888 888 88b Y8b Y8P d88 88b 888 88b d88888 d888 888b 888 " Y8b Y8P + * 888 888 888 Y8b " 888 , 888 888 888 Y888 888P 888 Y8b Y + * 888 888 888 Y8P "YeeP" 888 888 888 "88 88" 888 888 + * 888 + * 888 + */ + set(ConfPaths.INVENTORY_DROP_CHECK, true); + set(ConfPaths.INVENTORY_DROP_LIMIT, 100); + set(ConfPaths.INVENTORY_DROP_TIMEFRAME, 20L); + set(ConfPaths.INVENTORY_DROP_ACTIONS, "log:drop:0:1:cif cmd:kick"); + + set(ConfPaths.INVENTORY_INSTANTBOW_CHECK, true); + set(ConfPaths.INVENTORY_INSTANTBOW_ACTIONS, "log:instantbow:2:5:if cancel"); + + set(ConfPaths.INVENTORY_INSTANTEAT_CHECK, true); + set(ConfPaths.INVENTORY_INSTANTEAT_ACTIONS, "log:instanteat:2:5:if cancel"); + /* * e e ,e, * d8b d8b e88 88e Y8b Y888P " 888 8e e88 888 @@ -274,6 +294,7 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.STRINGS + ".breach", start + "tried to interact with a block over distance [reachdistance] block(s)" + end); set(ConfPaths.STRINGS + ".critical", start + "tried to do a critical hit but wasn't technically jumping" + end); + set(ConfPaths.STRINGS + ".drop", start + "tried to drop more items than allowed" + end); set(ConfPaths.STRINGS + ".fastbreak", start + "tried to break too much blocks" + end); set(ConfPaths.STRINGS + ".fastplace", start + "tried to place too much blocks" + end); set(ConfPaths.STRINGS + ".fdirection", start + "tried to hit an entity out of line of sight" + end); @@ -283,6 +304,8 @@ public class DefaultConfig extends ConfigFile { set(ConfPaths.STRINGS + ".freach", start + "tried to attack entity out of reach" + end); set(ConfPaths.STRINGS + ".fspeed", start + "tried to attack more than [attackslimit] times per second" + end); set(ConfPaths.STRINGS + ".godmode", start + "avoided taking damage or lagging" + end); + set(ConfPaths.STRINGS + ".instantbow", start + "fires bow to fast" + end); + set(ConfPaths.STRINGS + ".instanteat", start + "eats food [food] too fast" + end); set(ConfPaths.STRINGS + ".instantheal", start + "tried to regenerate health faster than normal" + end); set(ConfPaths.STRINGS + ".kick", "kick [player]"); set(ConfPaths.STRINGS + ".knockback", start + "tried to do a knockback but wasn't technically sprinting" + end); diff --git a/src/fr/neatmonster/nocheatplus/players/Permissions.java b/src/fr/neatmonster/nocheatplus/players/Permissions.java index ad76ff98..efb168a1 100644 --- a/src/fr/neatmonster/nocheatplus/players/Permissions.java +++ b/src/fr/neatmonster/nocheatplus/players/Permissions.java @@ -123,6 +123,20 @@ public class Permissions { public static final String FIGHT_REACH = FIGHT + ".reach"; public static final String FIGHT_SPEED = FIGHT + ".speed"; + /* + * 888 d8 + * 888 888 8e Y8b Y888P ,e e, 888 8e d88 e88 88e 888,8, Y8b Y888P + * 888 888 88b Y8b Y8P d88 88b 888 88b d88888 d888 888b 888 " Y8b Y8P + * 888 888 888 Y8b " 888 , 888 888 888 Y888 888P 888 Y8b Y + * 888 888 888 Y8P "YeeP" 888 888 888 "88 88" 888 888 + * 888 + * 888 + */ + private static final String INVENTORY = CHECKS + ".inventory"; + public static final String INVENTORY_DROP = INVENTORY + ".drop"; + public static final String INVENTORY_INSTANTBOW = INVENTORY + ".instantbow"; + public static final String INVENTORY_INSTANTEAT = INVENTORY + ".instanteat"; + /* * e e ,e, * d8b d8b e88 88e Y8b Y888P " 888 8e e88 888