diff --git a/src/main/java/com/songoda/epicvouchers/EpicVouchers.java b/src/main/java/com/songoda/epicvouchers/EpicVouchers.java index 6d9486b..686f3f7 100644 --- a/src/main/java/com/songoda/epicvouchers/EpicVouchers.java +++ b/src/main/java/com/songoda/epicvouchers/EpicVouchers.java @@ -30,6 +30,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.plugin.PluginManager; import java.io.File; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -166,13 +167,17 @@ public class EpicVouchers extends SongodaPlugin { } private void saveVouchers() { + Collection voucherList = voucherManager.getVouchers(); + for (String voucherName : vouchersConfig.getConfigurationSection("vouchers").getKeys(false)) { - if (voucherManager.getVouchers().stream().noneMatch(voucher -> voucher.getKey().equals(voucherName))) + if (voucherList.stream().noneMatch(voucher -> voucher.getKey().equals(voucherName))) { vouchersConfig.set("vouchers." + voucherName, null); + } } - for (Voucher voucher : voucherManager.getVouchers()) { + for (Voucher voucher : voucherList) { String prefix = "vouchers." + voucher.getKey() + "."; + vouchersConfig.set(prefix + "permission", voucher.getPermission()); vouchersConfig.set(prefix + "material", voucher.getMaterial().name()); vouchersConfig.set(prefix + "data", voucher.getData()); @@ -204,13 +209,16 @@ public class EpicVouchers extends SongodaPlugin { vouchersConfig.set(prefix + "effects.amplifier", voucher.getEffectAmplifier()); vouchersConfig.set(prefix + "itemstack", voucher.getItemStack()); } + vouchersConfig.saveChanges(); } @Override public void onConfigReload() { vouchersConfig.load(); + loadVouchersFromFile(); + this.setLocale(getConfig().getString("System.Language Mode"), true); this.locale.reloadMessages(); } diff --git a/src/main/java/com/songoda/epicvouchers/listeners/PlayerInteractListener.java b/src/main/java/com/songoda/epicvouchers/listeners/PlayerInteractListener.java index 3aa9107..248dc5f 100644 --- a/src/main/java/com/songoda/epicvouchers/listeners/PlayerInteractListener.java +++ b/src/main/java/com/songoda/epicvouchers/listeners/PlayerInteractListener.java @@ -3,6 +3,7 @@ package com.songoda.epicvouchers.listeners; import com.songoda.core.nms.NmsManager; import com.songoda.core.nms.nbt.NBTItem; import com.songoda.epicvouchers.EpicVouchers; +import com.songoda.epicvouchers.utils.CachedSet; import com.songoda.epicvouchers.voucher.Voucher; import org.bukkit.ChatColor; import org.bukkit.event.EventHandler; @@ -15,44 +16,62 @@ import org.bukkit.inventory.meta.ItemMeta; public class PlayerInteractListener implements Listener { private final EpicVouchers instance; + private final CachedSet checkedLegacyVouchers = new CachedSet<>(3 * 60); + public PlayerInteractListener(EpicVouchers instance) { this.instance = instance; } @EventHandler - public void voucherListener(PlayerInteractEvent event) { - final ItemStack item = event.getItem(); - if (item == null || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK)) - return; + public void voucherListener(PlayerInteractEvent e) { + ItemStack item = e.getItem(); - final NBTItem itemNbt = NmsManager.getNbt().of(item); + if (item != null && (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)) { + NBTItem itemNbt = NmsManager.getNbt().of(item); - for (Voucher voucher : instance.getVoucherManager().getVouchers()) { - final ItemStack voucherItem = voucher.toItemStack(); + boolean itemHasVoucher = itemNbt.has("epicvouchers:voucher"); + String itemVoucherValue = itemNbt.getString("epicvouchers:voucher"); - // Check voucher NBT. - if (itemNbt.has("epicvouchers:voucher") && itemNbt.getNBTObject("epicvouchers:voucher").asString().equals(voucher.getKey())) { - event.setCancelled(true); - voucher.redeemVoucher(event); - continue; + boolean legacyChecked = checkedLegacyVouchers.contains(item); + + if (itemHasVoucher || !legacyChecked) { + boolean shouldBeLegacyCached = !itemHasVoucher; + + for (Voucher voucher : instance.getVoucherManager().getVouchers()) { + // Check voucher NBT. + if (itemHasVoucher && itemVoucherValue.equals(voucher.getKey())) { + e.setCancelled(true); + voucher.redeemVoucher(e); + break; + } + + // TODO: eventually make the legacy check configurable as a lot of players (and vouchers) quickly cause lag + // Legacy crap. + // does the item they're holding match this voucher? + ItemStack voucherItem = voucher.toItemStack(); + + if ((voucherItem == null || voucherItem.isSimilar(item)) && + item.getType() == voucher.getMaterial() && + item.getDurability() == voucher.getData()) { + // material matches - verify the name + lore + ItemMeta meta = item.getItemMeta(); + + if (meta != null && meta.hasDisplayName() + && ChatColor.stripColor(meta.getDisplayName()).equals(ChatColor.stripColor(voucher.getName(true))) + && (!meta.hasLore() || meta.getLore().equals(voucher.getLore(true)))) { + e.setCancelled(true); + voucher.redeemVoucher(e); + + shouldBeLegacyCached = false; + break; + } + } + } + + if (shouldBeLegacyCached) { + this.checkedLegacyVouchers.add(item); + } } - - // Legacy crap. - // does the item they're holding match this voucher? - - if (voucherItem != null && !voucherItem.isSimilar(item)) continue; - else if (item.getType() != voucher.getMaterial() || item.getDurability() != voucher.getData()) continue; - else { - // material matches - verify the name + lore - final ItemMeta meta = item.getItemMeta(); - if (meta == null || !meta.hasDisplayName() - || !ChatColor.stripColor(meta.getDisplayName()).equals(ChatColor.stripColor(voucher.getName(true))) - || (meta.hasLore() && !meta.getLore().equals(voucher.getLore(true)))) - continue; - } - - event.setCancelled(true); - voucher.redeemVoucher(event); } } } diff --git a/src/main/java/com/songoda/epicvouchers/utils/CachedSet.java b/src/main/java/com/songoda/epicvouchers/utils/CachedSet.java new file mode 100644 index 0000000..a805a50 --- /dev/null +++ b/src/main/java/com/songoda/epicvouchers/utils/CachedSet.java @@ -0,0 +1,40 @@ +package com.songoda.epicvouchers.utils; + +import java.util.Map; +import java.util.WeakHashMap; + +public class CachedSet { + private final Map cache = new WeakHashMap<>(); + private final int ttl; + + private long lastClear = System.currentTimeMillis(); + + /** + * @param ttl Time-To-Live in seconds + */ + public CachedSet(int ttl) { + this.ttl = ttl * 1000; + } + + public void add(K obj) { + this.cache.put(obj, System.currentTimeMillis()); + } + + public boolean contains(K obj) { + if (shouldClear()) { + clearStale(); + } + + return this.cache.computeIfPresent(obj, (k, aLong) -> System.currentTimeMillis()) != null; + } + + public void clearStale() { + this.cache.entrySet().removeIf(entry -> System.currentTimeMillis() - entry.getValue() >= ttl); + + this.lastClear = System.currentTimeMillis(); + } + + private boolean shouldClear() { + return !this.cache.isEmpty() && System.currentTimeMillis() - lastClear > ttl; + } +}