Try improving performance on legacy InteractEvent checks [SD-8155]

This commit is contained in:
Christian Koop 2021-07-11 01:57:21 +02:00
parent a38f3b738a
commit 8aa5173a60
No known key found for this signature in database
GPG Key ID: 89A8181384E010A3
3 changed files with 98 additions and 31 deletions

View File

@ -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<Voucher> 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();
}

View File

@ -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<ItemStack> 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);
}
}
}

View File

@ -0,0 +1,40 @@
package com.songoda.epicvouchers.utils;
import java.util.Map;
import java.util.WeakHashMap;
public class CachedSet<K> {
private final Map<K, Long> 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;
}
}