diff --git a/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java b/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java index 6baa783..d69ecbe 100644 --- a/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java +++ b/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java @@ -104,7 +104,7 @@ public class GUIOverview extends AbstractGUI { ItemMeta hookmeta = hook.getItemMeta(); hookmeta.setDisplayName(plugin.getLocale().getMessage("interface.hopper.synchopper")); ArrayList lorehook = new ArrayList<>(); - parts = plugin.getLocale().getMessage("interface.hopper.synclore", hopper.getLinkedBlocks().size()).split("\\|"); + parts = plugin.getLocale().getMessage("interface.hopper.synclore", hopper.getLinkedBlocks().stream().distinct().count()).split("\\|"); for (String line : parts) { lorehook.add(Methods.formatText(line)); } diff --git a/src/main/java/com/songoda/epichoppers/handlers/TeleportHandler.java b/src/main/java/com/songoda/epichoppers/handlers/TeleportHandler.java index 353786d..b1b8ed6 100644 --- a/src/main/java/com/songoda/epichoppers/handlers/TeleportHandler.java +++ b/src/main/java/com/songoda/epichoppers/handlers/TeleportHandler.java @@ -14,7 +14,6 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; import java.util.Date; import java.util.HashMap; @@ -23,71 +22,75 @@ import java.util.UUID; public class TeleportHandler { - //Teleport from - teleport 2 - private final Map teleportFrom = new HashMap<>(); private final Map lastTeleports = new HashMap<>(); private EpicHoppers instance; public TeleportHandler(EpicHoppers instance) { - this.instance = instance; - Bukkit.getScheduler().scheduleSyncRepeatingTask(instance, this::teleportRunner, 0, instance.getConfig().getLong("Main.Amount of Ticks Between Teleport")); + this.instance = instance; + Bukkit.getScheduler().scheduleSyncRepeatingTask(instance, this::teleportRunner, 0, instance.getConfig().getLong("Main.Amount of Ticks Between Teleport")); } private void teleportRunner() { for (World world : Bukkit.getWorlds()) { for (Entity entity : world.getEntities()) { - if (!(entity instanceof LivingEntity) ||entity.getType() == EntityType.ARMOR_STAND) continue; - - if (!instance.getConfig().getBoolean("Main.Allow Players To Teleport Through Hoppers") - || entity instanceof Player && !((Player)entity).hasPermission("EpicHoppers.Teleport")) { + if (!(entity instanceof LivingEntity) || entity.getType() == EntityType.ARMOR_STAND) + continue; + + if (!this.instance.getConfig().getBoolean("Main.Allow Players To Teleport Through Hoppers") + || (entity instanceof Player && !entity.hasPermission("EpicHoppers.Teleport"))) continue; - } Location location = entity.getLocation().getBlock().getRelative(BlockFace.DOWN).getLocation(); - if (!instance.getHopperManager().isHopper(location)) { + if (!this.instance.getHopperManager().isHopper(location)) continue; - } - Hopper hopper = instance.getHopperManager().getHopper(location); + Hopper hopper = this.instance.getHopperManager().getHopper(location); - if (hopper.getTeleportTrigger() != TeleportTrigger.WALK_ON) continue; + if (hopper.getTeleportTrigger() != TeleportTrigger.WALK_ON) + continue; - if (lastTeleports.containsKey(entity.getUniqueId())) { - long duration = (new Date()).getTime() - new Date(lastTeleports.get(entity.getUniqueId())).getTime(); - if (duration <= 5 * 1000) { + if (this.lastTeleports.containsKey(entity.getUniqueId())) { + long duration = (new Date()).getTime() - new Date(this.lastTeleports.get(entity.getUniqueId())).getTime(); + if (duration <= 5 * 1000) continue; - } } - tpEntity(entity, hopper); - lastTeleports.put(entity.getUniqueId(), System.currentTimeMillis()); + this.tpEntity(entity, hopper); + this.lastTeleports.put(entity.getUniqueId(), System.currentTimeMillis()); } } } public void tpEntity(Entity entity, Hopper hopper) { - if (hopper == null || !instance.getHopperManager().isHopper(hopper.getLocation())) return; + if (hopper == null || !this.instance.getHopperManager().isHopper(hopper.getLocation())) + return; - EpicHoppers instance = EpicHoppers.getInstance(); - Hopper lastHopper = hopper; - for (int i = 0; i < 15; i++) { - boolean empty = lastHopper.getLinkedBlocks().isEmpty(); - if (empty && i == 0) { - if (teleportFrom.containsKey(hopper.getLocation())) - doTeleport(entity, teleportFrom.get(hopper.getLocation()).clone()); - return; - } + Hopper lastHopper = this.getChain(hopper, 1); + if (hopper != lastHopper) + this.doTeleport(entity, lastHopper.getLocation()); + } - if (empty) break; - Location nextHopper = lastHopper.getLinkedBlocks().get(0); - if (!(nextHopper.getBlock().getState() instanceof InventoryHolder)) break; - lastHopper = instance.getHopperManager().getHopper(nextHopper); + /** + * Recursively gets the next hopper in the linked hopper chain + * @param lastHopper The previous hopper found in the chain + * @param currentChainLength The current length of the chain, used to cap the search length + * @return The hopper at the end of the chain (or up to 15 in depth) + */ + private Hopper getChain(Hopper lastHopper, int currentChainLength) { + if (currentChainLength > 15) + return lastHopper; + + for (Location nextHopperLocation : lastHopper.getLinkedBlocks()) { + if (nextHopperLocation.getBlock().getState() instanceof org.bukkit.block.Hopper) { + Hopper hopper = this.instance.getHopperManager().getHopper(nextHopperLocation); + if (hopper != null) + return this.getChain(hopper, currentChainLength + 1); } + } - teleportFrom.put(lastHopper.getLocation(), hopper.getLocation()); - doTeleport(entity, lastHopper.getLocation()); + return lastHopper; } private void doTeleport(Entity entity, Location location) { @@ -95,14 +98,14 @@ public class TeleportHandler { location.setPitch(entity.getLocation().getPitch()); location.setDirection(entity.getLocation().getDirection()); - if (instance.isServerVersionAtLeast(ServerVersion.V1_12)) { + if (this.instance.isServerVersionAtLeast(ServerVersion.V1_12)) { Methods.doParticles(entity, location); Methods.doParticles(entity, entity.getLocation().getBlock().getRelative(BlockFace.DOWN).getLocation()); } - + entity.teleport(location); - if (instance.isServerVersionAtLeast(ServerVersion.V1_12)) + if (this.instance.isServerVersionAtLeast(ServerVersion.V1_12)) entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 10, 10); } } diff --git a/src/main/java/com/songoda/epichoppers/hopper/HopperManager.java b/src/main/java/com/songoda/epichoppers/hopper/HopperManager.java index 303cf87..fe440c4 100644 --- a/src/main/java/com/songoda/epichoppers/hopper/HopperManager.java +++ b/src/main/java/com/songoda/epichoppers/hopper/HopperManager.java @@ -20,9 +20,18 @@ public class HopperManager { registeredHoppers.put(roundLocation(location), hopper); } - + /** + * Removes a hopper and unlinks it from any other hoppers + * @param location The location of the hopper to remove + * @return The removed hopper, or null if none was removed + */ public Hopper removeHopper(Location location) { - return registeredHoppers.remove(location); + Hopper removed = this.registeredHoppers.remove(location); + + for (Hopper hopper : this.registeredHoppers.values()) + hopper.removeLinkedBlock(location); + + return removed; } diff --git a/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java b/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java index 1aa56fe..aaf1b56 100644 --- a/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java +++ b/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java @@ -50,57 +50,57 @@ public class InteractListeners implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockInteract(PlayerInteractEvent e) { - Player player = e.getPlayer(); - if (e.getAction() != Action.LEFT_CLICK_BLOCK - || e.getClickedBlock() == null - || player.isSneaking() - || !player.hasPermission("EpicHoppers.overview") - || !(e.getClickedBlock().getState() instanceof InventoryHolder || e.getClickedBlock().getType().equals(Material.ENDER_CHEST))) { - return; + Player player = e.getPlayer(); + if (e.getAction() != Action.LEFT_CLICK_BLOCK + || e.getClickedBlock() == null + || player.isSneaking() + || !player.hasPermission("EpicHoppers.overview") + || !(e.getClickedBlock().getState() instanceof InventoryHolder || e.getClickedBlock().getType().equals(Material.ENDER_CHEST))) { + return; + } + + if (e.getClickedBlock().getType() == Material.CHEST && Methods.isSync(player)) { + ItemStack item = e.getPlayer().getInventory().getItemInHand(); + if (item.getItemMeta().getLore().size() == 2) { + player.sendMessage(instance.getLocale().getMessage("event.hopper.desyncchest", item.getType().toString())); + instance.enchantmentHandler.createSyncTouch(item, null); + } else { + player.sendMessage(instance.getLocale().getMessage("event.hopper.syncchest", item.getType().toString())); + instance.enchantmentHandler.createSyncTouch(item, e.getClickedBlock()); } + e.setCancelled(true); + return; + } - if (e.getClickedBlock().getType() == Material.CHEST && Methods.isSync(player)) { - ItemStack item = e.getPlayer().getInventory().getItemInHand(); - if (item.getItemMeta().getLore().size() == 2) { - player.sendMessage(instance.getLocale().getMessage("event.hopper.desyncchest", item.getType().toString())); - instance.enchantmentHandler.createSyncTouch(item, null); - } else { - player.sendMessage(instance.getLocale().getMessage("event.hopper.syncchest", item.getType().toString())); - instance.enchantmentHandler.createSyncTouch(item, e.getClickedBlock()); - } - e.setCancelled(true); - return; - } + PlayerData playerData = instance.getPlayerDataManager().getPlayerData(player); - PlayerData playerData = instance.getPlayerDataManager().getPlayerData(player); - - if (playerData.getSyncType() == null) { - if (e.getClickedBlock().getType() == Material.HOPPER) { - if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(e.getClickedBlock().getLocation())) - return; - Hopper hopper = instance.getHopperManager().getHopper(e.getClickedBlock()); - playerData.setLastHopper(hopper); - if (!player.getInventory().getItemInHand().getType().name().contains("PICKAXE")) { - hopper.overview(player); - e.setCancelled(true); - return; - } - } - return; - } - - if (e.getClickedBlock().getState() instanceof InventoryHolder || e.getClickedBlock().getType().equals(Material.ENDER_CHEST) && instance.getConfig().getBoolean("Main.Support Enderchests")) { - Hopper hopper = playerData.getLastHopper(); - if (playerData.getSyncType() != null && e.getClickedBlock().getLocation().equals(playerData.getLastHopper().getLocation())) { - player.sendMessage(instance.getLocale().getMessage("event.hopper.syncself")); - } else if (playerData.getSyncType() != null) { - hopper.link(e.getClickedBlock(), playerData.getSyncType() == SyncType.FILTERED, player); - } - e.setCancelled(true); - int amountLinked = hopper.getLevel().getLinkAmount(); - if (hopper.getLinkedBlocks().size() >= amountLinked) { - playerData.setSyncType(null); + if (playerData.getSyncType() == null) { + if (e.getClickedBlock().getType() == Material.HOPPER) { + if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(e.getClickedBlock().getLocation())) + return; + Hopper hopper = instance.getHopperManager().getHopper(e.getClickedBlock()); + playerData.setLastHopper(hopper); + if (!player.getInventory().getItemInHand().getType().name().contains("PICKAXE")) { + hopper.overview(player); + e.setCancelled(true); + return; } } + return; + } + + if (e.getClickedBlock().getState() instanceof InventoryHolder || (e.getClickedBlock().getType().equals(Material.ENDER_CHEST) && instance.getConfig().getBoolean("Main.Support Enderchests"))) { + Hopper hopper = playerData.getLastHopper(); + if (playerData.getSyncType() != null && e.getClickedBlock().getLocation().equals(playerData.getLastHopper().getLocation())) { + player.sendMessage(instance.getLocale().getMessage("event.hopper.syncself")); + } else if (playerData.getSyncType() != null) { + hopper.link(e.getClickedBlock(), playerData.getSyncType() == SyncType.FILTERED, player); + } + e.setCancelled(true); + int amountLinked = hopper.getLevel().getLinkAmount(); + if (hopper.getLinkedBlocks().size() >= amountLinked) { + playerData.setSyncType(null); + } + } } } diff --git a/src/main/java/com/songoda/epichoppers/utils/settings/Setting.java b/src/main/java/com/songoda/epichoppers/utils/settings/Setting.java index dcb4048..62e4bba 100644 --- a/src/main/java/com/songoda/epichoppers/utils/settings/Setting.java +++ b/src/main/java/com/songoda/epichoppers/utils/settings/Setting.java @@ -50,7 +50,8 @@ public enum Setting { BLOCKBREAK_PARTICLE("Main.BlockBreak Particle Type", "LAVA", "The particle shown when the block break module performs a block break."), - BLACKLIST("Main.BlockBreak Blacklisted Blocks", Arrays.asList("BEDROCK", "END_PORTAL", "ENDER_PORTAL", "END_PORTAL_FRAME", "ENDER_PORTAL_FRAME", "PISTON_HEAD", "PISTON_EXTENSION"), + BLACKLIST("Main.BlockBreak Blacklisted Blocks", + Arrays.asList("BEDROCK", "END_PORTAL", "ENDER_PORTAL", "END_PORTAL_FRAME", "ENDER_PORTAL_FRAME", "PISTON_HEAD", "PISTON_EXTENSION", "RAIL", "RAILS", "ACTIVATOR_RAIL", "DETECTOR_RAIL", "POWERED_RAIL"), "Anything listed here will not be broken by the block break module."), AUTOSELL_PRICES("Main.AutoSell Prices", diff --git a/src/main/resources/en_US.lang b/src/main/resources/en_US.lang index 7fca323..30dd7f1 100644 --- a/src/main/resources/en_US.lang +++ b/src/main/resources/en_US.lang @@ -27,7 +27,7 @@ interface.hopper.autosell = "&7AutoSell: Every &6%seconds%s" interface.hopper.linkamount = "&7Link Overflow: &6%amount%" interface.hopper.blockbreak = "&7Block Break: &6Every %ticks% ticks" interface.hopper.alreadymaxed = "&7This hopper is already maxed out!" -interface.hopper.synclore = "|&7Left-Click then click a another|&7hopper or chest to link!||&7Right-Click to unlink.|&7Currently linked to &6%amount% hopper(s)&7." +interface.hopper.synclore = "|&7Left-Click then click a another|&7hopper or chest to link!||&7Right-Click to unlink.|&7Currently linked to &6%amount% container(s)&7." interface.hopper.perltitle = "&6Click to Teleport" interface.hopper.perllore2 = "|&7Left-Click to teleport to|&7the end of the chain.||&7Right-Click to switch the|&7teleport trigger mode.|&7Currently set to: &a%type%&7." interface.hopper.filtertitle = "&cClick to Filter"