From 67f12872a9d83245a2af8e10907afb410a8b7a88 Mon Sep 17 00:00:00 2001 From: MineTheCube Date: Tue, 25 Jul 2017 02:18:05 +0200 Subject: [PATCH] Performance improvements & shop updater refactor --- .../java/de/epiceric/shopchest/ShopChest.java | 9 +-- .../shopchest/listeners/ShopItemListener.java | 8 +- .../listeners/ShopUpdateListener.java | 71 ----------------- .../de/epiceric/shopchest/nms/Hologram.java | 63 ++++++++------- .../de/epiceric/shopchest/shop/ShopItem.java | 19 +++-- .../epiceric/shopchest/utils/ShopUpdater.java | 77 +++++++++++-------- .../epiceric/shopchest/utils/ShopUtils.java | 42 +++++----- src/main/resources/plugin.yml | 2 +- 8 files changed, 122 insertions(+), 169 deletions(-) diff --git a/src/main/java/de/epiceric/shopchest/ShopChest.java b/src/main/java/de/epiceric/shopchest/ShopChest.java index bce5fa7..210c4db 100644 --- a/src/main/java/de/epiceric/shopchest/ShopChest.java +++ b/src/main/java/de/epiceric/shopchest/ShopChest.java @@ -185,7 +185,7 @@ public class ShopChest extends JavaPlugin { if (updater != null) { debug("Stopping updater"); - updater.cancel(); + updater.stop(); } if (database != null) { @@ -433,13 +433,6 @@ public class ShopChest extends JavaPlugin { return updater; } - /** - * Set the {@link ShopUpdater} that schedules hologram and item updates - */ - public void setUpdater(ShopUpdater updater) { - this.updater = updater; - } - /** * @return Whether the plugin 'AreaShop' is enabled */ diff --git a/src/main/java/de/epiceric/shopchest/listeners/ShopItemListener.java b/src/main/java/de/epiceric/shopchest/listeners/ShopItemListener.java index 46b0ee9..016bc1f 100644 --- a/src/main/java/de/epiceric/shopchest/listeners/ShopItemListener.java +++ b/src/main/java/de/epiceric/shopchest/listeners/ShopItemListener.java @@ -4,9 +4,7 @@ import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.shop.Shop; import de.epiceric.shopchest.utils.ShopUtils; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -15,7 +13,8 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.*; -import org.bukkit.event.player.*; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.world.StructureGrowEvent; public class ShopItemListener implements Listener { @@ -34,6 +33,9 @@ public class ShopItemListener implements Listener { if (shop.getItem() != null) { shop.getItem().setVisible(e.getPlayer(), false); } + if (shop.getHologram() != null) { + shop.getHologram().hidePlayer(e.getPlayer()); + } } } diff --git a/src/main/java/de/epiceric/shopchest/listeners/ShopUpdateListener.java b/src/main/java/de/epiceric/shopchest/listeners/ShopUpdateListener.java index 224269b..ec03010 100644 --- a/src/main/java/de/epiceric/shopchest/listeners/ShopUpdateListener.java +++ b/src/main/java/de/epiceric/shopchest/listeners/ShopUpdateListener.java @@ -1,19 +1,10 @@ package de.epiceric.shopchest.listeners; import de.epiceric.shopchest.ShopChest; -import de.epiceric.shopchest.shop.Shop; import de.epiceric.shopchest.utils.Callback; -import de.epiceric.shopchest.utils.ShopUpdater; -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.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerRespawnEvent; -import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.world.WorldLoadEvent; -import org.bukkit.scheduler.BukkitRunnable; public class ShopUpdateListener implements Listener { @@ -23,48 +14,6 @@ public class ShopUpdateListener implements Listener { this.plugin = plugin; } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerTeleport(final PlayerTeleportEvent e) { - // Wait till the chunk should have loaded on the client - new BukkitRunnable() { - @Override - public void run() { - hideShops(e.getPlayer(), true); - plugin.getShopUtils().updateShops(e.getPlayer(), true); - } - }.runTaskLater(plugin, 15L); - } - - @EventHandler(priority = EventPriority.MONITOR) - public void onPlayerJoin(PlayerJoinEvent e) { - restartShopUpdater(e.getPlayer()); - } - - // The Bukkit::getOnlinePlayers() list does not include players that - // are currently respawning or chaning worlds, so when only one player is - // online and is currently respawning, the updater will think that no player - // is online, so it will stop. To prevent that, a delay of 1 tick is needed. - - @EventHandler - public void onPlayerChangedWorld(final PlayerChangedWorldEvent e) { - new BukkitRunnable() { - @Override - public void run() { - restartShopUpdater(e.getPlayer()); - } - }.runTaskLater(plugin, 1L); - } - - @EventHandler - public void onPlayerRespawn(final PlayerRespawnEvent e) { - new BukkitRunnable() { - @Override - public void run() { - restartShopUpdater(e.getPlayer()); - } - }.runTaskLater(plugin, 1L); - } - @EventHandler public void onWorldLoad(WorldLoadEvent e) { final String worldName = e.getWorld().getName(); @@ -81,24 +30,4 @@ public class ShopUpdateListener implements Listener { } }); } - - private void restartShopUpdater(Player p) { - if (!plugin.getUpdater().isRunning()) { - plugin.setUpdater(new ShopUpdater(plugin)); - plugin.getUpdater().start(); - } - - hideShops(p, false); - } - - private void hideShops(Player p, boolean onlyItem) { - for (Shop shop : plugin.getShopUtils().getShops()) { - if (!onlyItem) { - if (shop.getHologram() != null) shop.getHologram().hidePlayer(p); - } - - if (shop.getItem() != null) shop.getItem().setVisible(p, false); - } - } - } diff --git a/src/main/java/de/epiceric/shopchest/nms/Hologram.java b/src/main/java/de/epiceric/shopchest/nms/Hologram.java index 5458bb9..233a401 100644 --- a/src/main/java/de/epiceric/shopchest/nms/Hologram.java +++ b/src/main/java/de/epiceric/shopchest/nms/Hologram.java @@ -2,14 +2,14 @@ package de.epiceric.shopchest.nms; import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.config.Config; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class Hologram { @@ -19,7 +19,7 @@ public class Hologram { private List wrappers = new ArrayList<>(); private ArmorStandWrapper interactArmorStandWrapper; private Location location; - private List visible = new ArrayList<>(); + private Set visibility = new HashSet<>(); private ShopChest plugin; private Config config; @@ -66,8 +66,11 @@ public class Hologram { wrappers.add(line, wrapper); if (forceUpdateLine) { - for (Player player : visible) { - wrapper.setVisible(player, true); + for (UUID uuid : visibility) { + Player player = Bukkit.getPlayer(uuid); + if (player != null) { + wrapper.setVisible(player, true); + } } } } @@ -148,40 +151,44 @@ public class Hologram { * @param p Player to which the hologram should be shown */ public void showPlayer(final Player p) { - new BukkitRunnable() { - @Override - public void run() { - for (ArmorStandWrapper wrapper : wrappers) { - wrapper.setVisible(p, true); - } + if (!isVisible(p)) { + new BukkitRunnable() { + @Override + public void run() { + for (ArmorStandWrapper wrapper : wrappers) { + wrapper.setVisible(p, true); + } - if (interactArmorStandWrapper != null) { - interactArmorStandWrapper.setVisible(p, true); + if (interactArmorStandWrapper != null) { + interactArmorStandWrapper.setVisible(p, true); + } } - } - }.runTaskAsynchronously(plugin); + }.runTaskAsynchronously(plugin); - visible.add(p); + visibility.add(p.getUniqueId()); + } } /** * @param p Player from which the hologram should be hidden */ public void hidePlayer(final Player p) { - new BukkitRunnable() { - @Override - public void run() { - for (ArmorStandWrapper wrapper : wrappers) { - wrapper.setVisible(p, false); - } + if (isVisible(p)) { + new BukkitRunnable() { + @Override + public void run() { + for (ArmorStandWrapper wrapper : wrappers) { + wrapper.setVisible(p, false); + } - if (interactArmorStandWrapper != null) { - interactArmorStandWrapper.setVisible(p, false); + if (interactArmorStandWrapper != null) { + interactArmorStandWrapper.setVisible(p, false); + } } - } - }.runTaskAsynchronously(plugin); + }.runTaskAsynchronously(plugin); - visible.remove(p); + visibility.remove(p.getUniqueId()); + } } /** @@ -189,7 +196,7 @@ public class Hologram { * @return Whether the hologram is visible to the player */ public boolean isVisible(Player p) { - return visible.contains(p); + return visibility.contains(p.getUniqueId()); } /** diff --git a/src/main/java/de/epiceric/shopchest/shop/ShopItem.java b/src/main/java/de/epiceric/shopchest/shop/ShopItem.java index 7599eb8..a972b31 100644 --- a/src/main/java/de/epiceric/shopchest/shop/ShopItem.java +++ b/src/main/java/de/epiceric/shopchest/shop/ShopItem.java @@ -2,6 +2,7 @@ package de.epiceric.shopchest.shop; import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.utils.Utils; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -9,13 +10,14 @@ import org.bukkit.inventory.ItemStack; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; public class ShopItem { private ShopChest plugin; - private Map visible = new HashMap<>(); + private Set visibility = new HashSet<>(); private ItemStack itemStack; private Location location; @@ -88,8 +90,9 @@ public class ShopItem { } public void remove() { - for (Player p : visible.keySet()) { - if (isVisible(p)) setVisible(p, false); + for (UUID uuid : visibility) { + Player p = Bukkit.getPlayer(uuid); + if (p != null) setVisible(p, false); } } @@ -103,7 +106,7 @@ public class ShopItem { } public boolean isVisible(Player p) { - return visible.get(p) == null ? false : visible.get(p); + return visibility.contains(p.getUniqueId()); } public void setVisible(final Player p, boolean visible) { @@ -114,6 +117,7 @@ public class ShopItem { for (Object packet : this.creationPackets) { Utils.sendPacket(plugin, packet, p); } + visibility.add(p.getUniqueId()); } else { try { if (p.isOnline()) { @@ -125,9 +129,8 @@ public class ShopItem { plugin.debug("Failed to destroy shop item with reflection"); plugin.debug(e); } + visibility.remove(p.getUniqueId()); } - - this.visible.put(p, visible); } diff --git a/src/main/java/de/epiceric/shopchest/utils/ShopUpdater.java b/src/main/java/de/epiceric/shopchest/utils/ShopUpdater.java index 52ea673..9461867 100644 --- a/src/main/java/de/epiceric/shopchest/utils/ShopUpdater.java +++ b/src/main/java/de/epiceric/shopchest/utils/ShopUpdater.java @@ -3,11 +3,9 @@ package de.epiceric.shopchest.utils; import de.epiceric.shopchest.ShopChest; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; -import java.util.Collection; - -public class ShopUpdater extends BukkitRunnable { +public class ShopUpdater { public enum UpdateQuality { SLOWEST(31L), @@ -18,7 +16,7 @@ public class ShopUpdater extends BukkitRunnable { FASTER(4L), FASTEST(1L); - private long interval; + private final long interval; UpdateQuality(long interval) { this.interval = interval; @@ -29,47 +27,64 @@ public class ShopUpdater extends BukkitRunnable { } } - private ShopChest plugin; + private final ShopChest plugin; - private boolean running; - private long interval; + private long interval = UpdateQuality.NORMAL.getInterval(); + + private volatile BukkitTask running; public ShopUpdater(ShopChest plugin) { this.plugin = plugin; - setInterval(plugin.getShopChestConfig().update_quality.getInterval()); } - public synchronized void setInterval(long interval) { - this.interval = interval; - } - - public synchronized void start() { - super.runTaskTimerAsynchronously(plugin, interval, interval); - running = true; - } - - @Override - public synchronized void cancel() { - if (running) { - running = false; - super.cancel(); + /** + * Start task, except if it is already + */ + public void start() { + if (!isRunning()) { + interval = plugin.getShopChestConfig().update_quality.getInterval(); + running = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, new ShopUpdaterTask(plugin), interval, interval); } } + /** + * Stop any running task then start it again + */ + public void restart() { + stop(); + start(); + } + + /** + * Stop task properly + */ + public void stop() { + if (running != null) { + running.cancel(); + running = null; + } + } + + /** + * @return whether task is running or not + */ public boolean isRunning() { - return running; + return running != null; } - @Override - public void run() { - Collection players = Bukkit.getOnlinePlayers(); + private static class ShopUpdaterTask implements Runnable { - if (players.isEmpty()) { - cancel(); + private final ShopChest plugin; + + private ShopUpdaterTask(ShopChest plugin) { + this.plugin = plugin; } - for (Player p : players) { - plugin.getShopUtils().updateShops(p); + @Override + public void run() { + for (Player p : Bukkit.getOnlinePlayers()) { + plugin.getShopUtils().updateShops(p); + } } } } diff --git a/src/main/java/de/epiceric/shopchest/utils/ShopUtils.java b/src/main/java/de/epiceric/shopchest/utils/ShopUtils.java index 4fb4e8a..4e97196 100644 --- a/src/main/java/de/epiceric/shopchest/utils/ShopUtils.java +++ b/src/main/java/de/epiceric/shopchest/utils/ShopUtils.java @@ -218,10 +218,7 @@ public class ShopUtils { if (reloadConfig) { plugin.getShopChestConfig().reload(false, true, showConsoleMessages); plugin.getHologramFormat().reload(); - plugin.getUpdater().cancel(); - - plugin.setUpdater(new ShopUpdater(plugin)); - plugin.getUpdater().start(); + plugin.getUpdater().restart(); } plugin.getShopDatabase().connect(new Callback(plugin) { @@ -314,9 +311,7 @@ public class ShopUtils { } } } else { - for (Shop shop : getShops()) { - updateShop(shop, player); - } + updateNearestShops(player); } playerLocation.put(player, player.getLocation()); @@ -370,27 +365,36 @@ public class ShopUtils { double holoDistSqr = Math.pow(plugin.getShopChestConfig().maximal_distance, 2); double itemDistSqr = Math.pow(plugin.getShopChestConfig().maximal_item_distance, 2); + updateShop(shop, player, holoDistSqr, itemDistSqr); + } + + private void updateNearestShops(Player p) { + double holoDistSqr = Math.pow(plugin.getShopChestConfig().maximal_distance, 2); + double itemDistSqr = Math.pow(plugin.getShopChestConfig().maximal_item_distance, 2); + + for (Shop shop : getShops()) { + updateShop(shop, p, holoDistSqr, itemDistSqr); + } + } + + private void updateShop(Shop shop, Player player, double holoDistSqr, double itemDistSqr) { if (player.getLocation().getWorld().getName().equals(shop.getLocation().getWorld().getName())) { double distSqr = shop.getLocation().distanceSquared(player.getLocation()); - if (distSqr <= holoDistSqr) { - if (shop.getHologram() != null) { - if (!shop.getHologram().isVisible(player)) { - shop.getHologram().showPlayer(player); - } - } - } else { - if (shop.getHologram() != null) { + if (shop.getHologram() != null) { + if (distSqr <= holoDistSqr) { + shop.getHologram().showPlayer(player); + } else { shop.getHologram().hidePlayer(player); } } - if (distSqr <= itemDistSqr) { - if (shop.getItem() != null) { + if (shop.getItem() != null) { + if (distSqr <= itemDistSqr) { shop.getItem().setVisible(player, true); + } else { + shop.getItem().setVisible(player, false); } - } else { - if (shop.getItem() != null) shop.getItem().setVisible(player, false); } } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 626e294..2f9bac0 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -6,7 +6,7 @@ version: ${project.version} author: EpicEric website: ${project.url} description: Create your own nice-looking chest shops and sell your stuff to other players! -softdepend: [WorldGuard, Towny, AuthMe, PlotSquared, uSkyBlock, ASkyBlock, IslandWorld, GriefPrevention, AreaShop] +softdepend: [WorldGuard, Towny, AuthMe, PlotSquared, uSkyBlock, ASkyBlock, IslandWorld, GriefPrevention, AreaShop, Multiverse-Core, MultiWorld] depend: [Vault] permissions: