diff --git a/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InventoryUtil.java b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InventoryUtil.java new file mode 100644 index 00000000..9a764048 --- /dev/null +++ b/NCPCompat/src/main/java/fr/neatmonster/nocheatplus/utilities/InventoryUtil.java @@ -0,0 +1,61 @@ +package fr.neatmonster.nocheatplus.utilities; + +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; + +public class InventoryUtil { + + /** + * Does not account for special slots like armor. + * @param inventory + * @return + */ + public static int getFreeSlots(final Inventory inventory){ + final ItemStack[] contents = inventory.getContents(); + int count = 0; + for (int i = 0; i < contents.length; i++){ + final ItemStack stack = contents[i]; + if (stack == null || stack.getTypeId() == 0){ + count ++; + } + } + return count; + } + + /** + * Count slots with type-id and data (enchantments are ignored at present). + * @param inventory + * @param reference + * @return + */ + public static int getStackCount(final Inventory inventory, final ItemStack reference) { + if (inventory == null) return 0; + if (reference == null) return getFreeSlots(inventory); + final int id = reference.getTypeId(); + final int durability = reference.getDurability(); + final ItemStack[] contents = inventory.getContents(); + int count = 0; + for (int i = 0; i < contents.length; i++){ + final ItemStack stack = contents[i]; + if (stack == null){ + continue; + } + else if (stack.getTypeId() == id && stack.getDurability() == durability){ + count ++; + } + } + return count; + } + + /** + * Sum of bottom + top inventory slots with item type / data, see: getStackCount(Inventory, reference). + * @param view + * @param reference + * @return + */ + public static int getStackCount(final InventoryView view, final ItemStack reference) { + return getStackCount(view.getBottomInventory(), reference) + getStackCount(view.getTopInventory(), reference); + } + +} diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastClick.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastClick.java index c30df2c5..91fa45ea 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastClick.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/FastClick.java @@ -2,12 +2,14 @@ package fr.neatmonster.nocheatplus.checks.inventory; import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; import fr.neatmonster.nocheatplus.checks.Check; import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.ViolationData; import fr.neatmonster.nocheatplus.permissions.Permissions; +import fr.neatmonster.nocheatplus.utilities.InventoryUtil; import fr.neatmonster.nocheatplus.utilities.TickTask; /* @@ -81,32 +83,34 @@ public class FastClick extends Check { // return cancel; // } - public boolean check(final Player player, final long now, final int slot, final ItemStack cursor, final ItemStack clicked, final InventoryData data, final InventoryConfig cc) { + public boolean check(final Player player, final long now, final InventoryView view, final int slot, final ItemStack cursor, final ItemStack clicked, final boolean isShiftClick, final InventoryData data, final InventoryConfig cc) { // Take time once. final float amount; if (cursor != null && cc.fastClickTweaks1_5){ - final Material mat = cursor.getType(); - final int size = cursor.getAmount(); - if (mat != data.fastClickLastMat || mat == Material.AIR || size != data.fastClickLastAmount || clicked == null){ + final Material cursorMat = cursor.getType(); + final int cursorAmount = Math.max(1, cursor.getAmount()); + final Material clickedMat = clicked == null ? Material.AIR : clicked.getType(); + if (cursorMat != data.fastClickLastCursor && (!isShiftClick || clicked == null || clicked.getType() != data.fastClickLastClicked) || cursorMat == Material.AIR || cursorAmount != data.fastClickLastCursorAmount){ amount = 1f; } else{ - final Material cMat = clicked.getType(); - if (cMat == Material.AIR || cMat == mat){ - amount = Math.min(cc.fastClickNormalLimit , cc.fastClickShortTermLimit) / (float) size * 0.75f; + if (clickedMat == Material.AIR || clickedMat == cursorMat || isShiftClick && clickedMat == data.fastClickLastClicked ){ + amount = Math.min(cc.fastClickNormalLimit , cc.fastClickShortTermLimit) / (float) (isShiftClick && clickedMat != Material.AIR ? (1.0 + Math.max(cursorAmount, InventoryUtil.getStackCount(view, clicked))) : cursorAmount) * 0.75f; } else{ amount = 1f; } } - data.fastClickLastMat = mat; - data.fastClickLastAmount = size; + data.fastClickLastCursor = cursorMat; + data.fastClickLastClicked = clickedMat; + data.fastClickLastCursorAmount = cursorAmount; } else{ - data.fastClickLastMat = null; - data.fastClickLastAmount = 0; + data.fastClickLastCursor = null; + data.fastClickLastClicked = null; + data.fastClickLastCursorAmount = 0; amount = 1f; } @@ -137,7 +141,7 @@ public class FastClick extends Check { } if (cc.debug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){ - player.sendMessage("FastClick: " + data.fastClickFreq.bucketScore(0) + " / " + data.fastClickFreq.score(1f)); + player.sendMessage("FastClick: " + data.fastClickFreq.bucketScore(0) + " | " + data.fastClickFreq.score(1f) + " | cursor=" + cursor + " | clicked=" + clicked); } return cancel; diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java index a9e50d7b..df2a087e 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryData.java @@ -84,8 +84,9 @@ public class InventoryData extends ACheckData { // Data of the fast click check. // public boolean fastClickLastCancelled; public final ActionFrequency fastClickFreq = new ActionFrequency(5, 200L); - public Material fastClickLastMat = null; - public int fastClickLastAmount = 0; + public Material fastClickLastCursor = null; + public Material fastClickLastClicked = null; + public int fastClickLastCursorAmount = 0; // Data of the instant bow check. public long instantBowInteract; diff --git a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java index ceddd498..33735844 100644 --- a/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java +++ b/NCPPlugin/src/main/java/fr/neatmonster/nocheatplus/checks/inventory/InventoryListener.java @@ -186,7 +186,7 @@ public class InventoryListener extends CheckListener { if (fastClick.isEnabled(player)){ final InventoryConfig cc = InventoryConfig.getConfig(player); if (player.getGameMode() != GameMode.CREATIVE || !cc.fastClickSpareCreative){ - if (fastClick.check(player, now, slot, cursor, clicked, data, cc)){ + if (fastClick.check(player, now, event.getView(), slot, cursor, clicked, event.isShiftClick(), data, cc)){ // The check requested the event to be cancelled. event.setCancelled(true); }