Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions API/src/main/java/fr/maxlego08/menu/api/Inventory.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,6 @@ public interface Inventory {
List<Action> getCloseActions();

ClearInvType getClearInvType();

boolean isClickLimiterEnabled();
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@ public interface BaseInventory extends InventoryHolder {

@Contract("_, null -> null")
@Nullable
ItemButton addItem(int slot,@Nullable ItemStack itemStack);
ItemButton addItem(int slot, @Nullable ItemStack itemStack);

@Contract("_, null,_ -> null")
@Nullable
ItemButton addItem(int slot,@Nullable ItemStack itemStack, boolean enableAntiDupe);
ItemButton addItem(int slot, @Nullable ItemStack itemStack, boolean enableAntiDupe);

@Contract("_, _, null -> null")
@Nullable
ItemButton addItem(boolean inPlayerInventory, int slot,@Nullable ItemStack itemStack);
ItemButton addItem(boolean inPlayerInventory, int slot, @Nullable ItemStack itemStack);

@Contract("_, _, null, _ -> null")
@Nullable
ItemButton addItem(boolean inPlayerInventory, int slot,@Nullable ItemStack itemStack, boolean enableAntiDupe);
ItemButton addItem(boolean inPlayerInventory, int slot, @Nullable ItemStack itemStack, boolean enableAntiDupe);

@Contract(pure = true)
@Nullable
Expand Down Expand Up @@ -97,4 +97,9 @@ public interface BaseInventory extends InventoryHolder {
void setClearInvType(ClearInvType clearInvType);

ClearInvType getClearInvType();

void setClickLimiterEnabled(boolean enabled);

boolean isClickLimiterEnabled();

}
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,15 @@ private static void parseMap(@NotNull Map<String, Object> map, @NotNull Map<Stri
}
case Map<?,?> nestedMap -> {
Map<String, Object> parsedMap = new HashMap<>();
//noinspection unchecked
parseMap((Map<String, Object>) nestedMap, parsedMap, placeholders);
Map<String, Object> convertedMap = convertMapKeys(nestedMap);
parseMap(convertedMap, parsedMap, placeholders);
destination.put(key, parsedMap);
}
case Integer i -> destination.put(key, i);
case Double d -> destination.put(key, d);
case Float f -> destination.put(key, f);
case Long l -> destination.put(key, l);
case Boolean b -> destination.put(key, b);
case null, default -> destination.put(key, value);
}
}
Expand All @@ -126,10 +131,15 @@ private static List<Object> parseList(@NotNull List<?> list, @NotNull Map<String
case String string -> processStringValue(string, listPlaceholders, placeholders, result::add);
case Map<?,?> map -> {
Map<String, Object> parsedMap = new HashMap<>();
//noinspection unchecked
parseMap((Map<String, Object>) map, parsedMap, placeholders);
Map<String, Object> convertedMap = convertMapKeys(map);
parseMap(convertedMap, parsedMap, placeholders);
result.add(parsedMap);
}
case Integer i -> result.add(i);
case Double d -> result.add(d);
case Float f -> result.add(f);
case Long l -> result.add(l);
case Boolean b -> result.add(b);
case null, default -> result.add(item);
}
}
Expand Down Expand Up @@ -232,4 +242,21 @@ private static String findListPlaceholderInString(@NotNull String string, @NotNu
}
return null;
}

/**
* Converts a Map with potentially non-String keys to a Map with String keys.
* This is necessary because YAML can have integer keys or other types.
*
* @param map the map to convert
* @return a new map with String keys
*/
@NotNull
private static Map<String, Object> convertMapKeys(@NotNull Map<?, ?> map) {
Map<String, Object> result = new HashMap<>();
for (Map.Entry<?, ?> entry : map.entrySet()) {
String key = entry.getKey() != null ? entry.getKey().toString() : "null";
result.put(key, entry.getValue());
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import fr.maxlego08.menu.api.configuration.Configuration;
import fr.maxlego08.menu.api.engine.BaseInventory;
import fr.maxlego08.menu.api.utils.CompatibilityUtil;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -16,19 +19,27 @@ public class PacketEventClickLimiterListener implements PacketListener {

@Override
public void onPacketReceive(PacketReceiveEvent event) {
if (!Configuration.enablePacketEventClickLimiter) return;
PacketTypeCommon packetType = event.getPacketType();
if (packetType == PacketType.Play.Client.CLICK_WINDOW){
if (packetType == PacketType.Play.Client.CLICK_WINDOW) {
Player player = event.getPlayer();
UUID playerUniqueId = player.getUniqueId();
Inventory topInventory = CompatibilityUtil.getTopInventory(player);
try {
if (topInventory != null && topInventory.getHolder() instanceof BaseInventory baseInventory && baseInventory.isClickLimiterEnabled()) {
UUID playerUniqueId = player.getUniqueId();

long currentTime = System.currentTimeMillis();
Long lastClickTime = this.lastClickTimes.get(playerUniqueId);
if (lastClickTime != null && (currentTime - lastClickTime) < Configuration.packetEventClickLimiterMilliseconds){
event.setCancelled(true);
return;
long currentTime = System.currentTimeMillis();
Long lastClickTime = this.lastClickTimes.get(playerUniqueId);
if (lastClickTime != null && (currentTime - lastClickTime) < Configuration.packetEventClickLimiterMilliseconds) {
event.setCancelled(true);
return;
}
this.lastClickTimes.put(playerUniqueId, currentTime);
}
} catch (Exception ignored) {
}
this.lastClickTimes.put(playerUniqueId, currentTime);
} if (packetType == PacketType.Play.Client.CLOSE_WINDOW) {

} else if (packetType == PacketType.Play.Client.CLOSE_WINDOW) {
Player player = event.getPlayer();
UUID playerUniqueId = player.getUniqueId();
this.lastClickTimes.remove(playerUniqueId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,10 @@ public void updateLore(@NonNull ItemMeta itemMeta, @NonNull List<String> lore, @
private Inventory createInventoryInternal(String inventoryName, InventoryHolder inventoryHolder, Object inventoryTypeOrSize) {
Component component = this.cache.get(inventoryName, () -> this.MINI_MESSAGE.deserialize(colorMiniMessage(inventoryName)));
try {
if (inventoryTypeOrSize instanceof Integer) {
return (Inventory) inventoryMethod.invoke(null, inventoryHolder, inventoryTypeOrSize, component);
} else if (inventoryTypeOrSize instanceof InventoryType) {
return (Inventory) inventoryTypeMethod.invoke(null, inventoryHolder, inventoryTypeOrSize, component);
if (inventoryTypeOrSize instanceof Integer integer) {
return (Inventory) inventoryMethod.invoke(null, inventoryHolder, integer, component);
} else if (inventoryTypeOrSize instanceof InventoryType inventoryType) {
return (Inventory) inventoryTypeMethod.invoke(null, inventoryHolder, inventoryType, component);
}
} catch (IllegalAccessException | InvocationTargetException exception) {
exception.printStackTrace();
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/fr/maxlego08/menu/ZInventory.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class ZInventory extends ZUtils implements Inventory {
private boolean clearInventory;
private ClearInvType clearInvType = ClearInvType.DEFAULT;
private boolean ItemPickupDisabled;
private boolean isClickLimiterEnabled = true;
private Requirement openRequirement;
private OpenWithItem openWithItem;
private InventoryType type = InventoryType.CHEST;
Expand Down Expand Up @@ -416,6 +417,15 @@ public ClearInvType getClearInvType() {
return this.clearInvType;
}

@Override
public boolean isClickLimiterEnabled() {
return this.isClickLimiterEnabled;
}

public void setClickLimiterEnabled(boolean enabled) {
this.isClickLimiterEnabled = enabled;
}

public void setClearInvType(ClearInvType clearInvType) {
this.clearInvType = clearInvType;
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/fr/maxlego08/menu/inventory/VInventory.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public abstract class VInventory extends ZUtils implements Cloneable, BaseInvent
protected String guiName;
protected boolean disableClick = true;
protected boolean disablePlayerInventoryClick = true;
protected boolean isClickLimiterEnabled = true;
private TitleAnimation titleAnimation;
private PlayerTitleAnimation playerTitleAnimation;
private ClearInvType clearInvType = ClearInvType.DEFAULT;
Expand Down Expand Up @@ -288,6 +289,16 @@ public ClearInvType getClearInvType() {
return this.clearInvType;
}

@Override
public void setClickLimiterEnabled(boolean enabled) {
this.isClickLimiterEnabled = enabled;
}

@Override
public boolean isClickLimiterEnabled() {
return this.isClickLimiterEnabled;
}

public void onInventoryClick(InventoryClickEvent event, ZMenuPlugin plugin, Player player) {

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public InventoryResult openInventory(ZMenuPlugin main, Player player, int page,
}

super.setClearInvType(this.inventory.getClearInvType());
super.setClickLimiterEnabled(this.inventory.isClickLimiterEnabled());

this.oldInventories = extractOldInventories(args);

Expand Down
6 changes: 5 additions & 1 deletion src/main/java/fr/maxlego08/menu/loader/InventoryLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class InventoryLoader extends ZUtils implements Loader<Inventory> {

Expand Down Expand Up @@ -137,6 +140,7 @@ public Inventory load(@NonNull YamlConfiguration configuration, @NonNull String
Logger.info("Clear inventory type " + clearInvTypeStr + " is not valid in " + file.getAbsolutePath(), Logger.LogType.ERROR);
}
}
inventory.setClickLimiterEnabled(configuration.getBoolean(path + "click-limiter-enabled", true));
inventory.setFile(file);

this.loadFillItem(configuration, inventory, menuItemStackLoader, file);
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ enable-cooldown-click: true
# Cooldown duration in milliseconds between clicks.
cooldown-click-milliseconds: 100

# Enable the packet event click limiter. Limits all click packets received from players (not just inside zMenu inventories).
# Enable packet event click limiter. Limits all click packets received from players (only for zMenu inventories).
# Prevents players from sending excessive click packets. Helps reduce packet spam and potential exploits. (Requires PacketEvent plugin)
enable-packet-event-click-limiter: true

Expand Down