diff --git a/pom.xml b/pom.xml
index 3cc849e..12ea26c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,6 +97,11 @@
72
provided
-
+
+ com.songoda
+ epicfarming
+ 2.2.1
+ provided
+
diff --git a/src/main/java/com/songoda/epichoppers/EpicHoppers.java b/src/main/java/com/songoda/epichoppers/EpicHoppers.java
index 390c028..8b6ff34 100644
--- a/src/main/java/com/songoda/epichoppers/EpicHoppers.java
+++ b/src/main/java/com/songoda/epichoppers/EpicHoppers.java
@@ -38,6 +38,7 @@ import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
+import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
@@ -74,6 +75,7 @@ public class EpicHoppers extends JavaPlugin {
private Storage storage;
private boolean liquidtanks = false;
+ private boolean epicfarming = false;
public static EpicHoppers getInstance() {
return INSTANCE;
@@ -135,6 +137,9 @@ public class EpicHoppers extends JavaPlugin {
// Check for liquid tanks
if (pluginManager.isPluginEnabled("LiquidTanks")) liquidtanks = true;
+ // Check for epicfarming
+ if (pluginManager.isPluginEnabled("EpicFarming")) epicfarming = true;
+
// Start auto save
int saveInterval = Setting.AUTOSAVE.getInt() * 60 * 20;
Bukkit.getScheduler().runTaskTimerAsynchronously(this, this::saveToFile, saveInterval, saveInterval);
@@ -303,7 +308,8 @@ public class EpicHoppers extends JavaPlugin {
}
private void loadLevelManager() {
- saveResource("levels.yml", false);
+ if (!new File(this.getDataFolder(), "levels.yml").exists())
+ this.saveResource("levels.yml", false);
// Load an instance of LevelManager
levelManager = new LevelManager();
@@ -404,4 +410,8 @@ public class EpicHoppers extends JavaPlugin {
return liquidtanks;
}
+ public boolean isEpicFarming() {
+ return epicfarming;
+ }
+
}
diff --git a/src/main/java/com/songoda/epichoppers/gui/GUICrafting.java b/src/main/java/com/songoda/epichoppers/gui/GUICrafting.java
index ee6a94d..97401c1 100644
--- a/src/main/java/com/songoda/epichoppers/gui/GUICrafting.java
+++ b/src/main/java/com/songoda/epichoppers/gui/GUICrafting.java
@@ -60,7 +60,7 @@ public class GUICrafting extends AbstractGUI {
@Override
protected void registerOnCloses() {
registerOnClose(((player, inventory) ->
- hopper.setAutoCrafting(inventory.getItem(13))));
+ hopper.setAutoCrafting(player, inventory.getItem(13))));
}
}
diff --git a/src/main/java/com/songoda/epichoppers/gui/GUIFilter.java b/src/main/java/com/songoda/epichoppers/gui/GUIFilter.java
index ec72c3c..9ffb596 100644
--- a/src/main/java/com/songoda/epichoppers/gui/GUIFilter.java
+++ b/src/main/java/com/songoda/epichoppers/gui/GUIFilter.java
@@ -156,59 +156,59 @@ public class GUIFilter extends AbstractGUI {
private void compile(Player p) {
- ItemStack[] items = p.getOpenInventory().getTopInventory().getContents();
+ ItemStack[] items = p.getOpenInventory().getTopInventory().getContents();
- Filter filter = hopper.getFilter();
+ Filter filter = hopper.getFilter();
- List owhite = new ArrayList<>();
- List oblack = new ArrayList<>();
- List ovoid = new ArrayList<>();
+ List owhite = new ArrayList<>();
+ List oblack = new ArrayList<>();
+ List ovoid = new ArrayList<>();
- int[] awhite = {9, 10, 18, 19, 27, 28, 36, 37};
- int[] ablack = {11, 12, 20, 21, 29, 30, 38, 39};
- int[] avoid = {13, 14, 22, 23, 31, 32, 40, 41};
+ int[] awhite = {9, 10, 18, 19, 27, 28, 36, 37};
+ int[] ablack = {11, 12, 20, 21, 29, 30, 38, 39};
+ int[] avoid = {13, 14, 22, 23, 31, 32, 40, 41};
- for (int i = 0; i < items.length; i++) {
- for (int aa : awhite) {
- if (aa != i) continue;
- if (items[i] != null && items[i].getType() != Material.AIR) {
- ItemStack item = items[i];
- if (item.getAmount() != 1) {
- item.setAmount(item.getAmount() - 1);
- Bukkit.getPlayer(hopper.getLastPlayer()).getInventory().addItem(item);
- item.setAmount(1);
- }
- owhite.add(item);
- }
- }
- for (int aa : ablack) {
- if (aa != i) continue;
- if (items[i] != null && items[i].getType() != Material.AIR) {
- ItemStack item = items[i];
- if (item.getAmount() != 1) {
- item.setAmount(item.getAmount() - 1);
- Bukkit.getPlayer(hopper.getLastPlayer()).getInventory().addItem(item);
- item.setAmount(1);
- }
- oblack.add(item);
- }
- }
- for (int aa : avoid) {
- if (aa != i) continue;
- if (items[i] != null && items[i].getType() != Material.AIR) {
- ItemStack item = items[i];
- if (item.getAmount() != 1) {
- item.setAmount(item.getAmount() - 1);
- Bukkit.getPlayer(hopper.getLastPlayer()).getInventory().addItem(item);
- item.setAmount(1);
- }
- ovoid.add(item);
+ for (int i = 0; i < items.length; i++) {
+ for (int aa : awhite) {
+ if (aa != i) continue;
+ if (items[i] != null && items[i].getType() != Material.AIR) {
+ ItemStack item = items[i];
+ if (item.getAmount() != 1) {
+ item.setAmount(item.getAmount() - 1);
+ Bukkit.getPlayer(hopper.getLastPlayer()).getInventory().addItem(item);
+ item.setAmount(1);
}
+ owhite.add(item);
}
}
- filter.setWhiteList(owhite);
- filter.setBlackList(oblack);
- filter.setVoidList(ovoid);
+ for (int aa : ablack) {
+ if (aa != i) continue;
+ if (items[i] != null && items[i].getType() != Material.AIR) {
+ ItemStack item = items[i];
+ if (item.getAmount() != 1) {
+ item.setAmount(item.getAmount() - 1);
+ Bukkit.getPlayer(hopper.getLastPlayer()).getInventory().addItem(item);
+ item.setAmount(1);
+ }
+ oblack.add(item);
+ }
+ }
+ for (int aa : avoid) {
+ if (aa != i) continue;
+ if (items[i] != null && items[i].getType() != Material.AIR) {
+ ItemStack item = items[i];
+ if (item.getAmount() != 1) {
+ item.setAmount(item.getAmount() - 1);
+ Bukkit.getPlayer(hopper.getLastPlayer()).getInventory().addItem(item);
+ item.setAmount(1);
+ }
+ ovoid.add(item);
+ }
+ }
+ }
+ filter.setWhiteList(owhite);
+ filter.setBlackList(oblack);
+ filter.setVoidList(ovoid);
}
@Override
diff --git a/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java b/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java
index e3b1ad8..d69ecbe 100644
--- a/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java
+++ b/src/main/java/com/songoda/epichoppers/gui/GUIOverview.java
@@ -104,35 +104,13 @@ 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));
}
hookmeta.setLore(lorehook);
hook.setItemMeta(hookmeta);
- ItemStack itemXP = new ItemStack(Material.valueOf(plugin.getConfig().getString("Interfaces.XP Icon")), 1);
- ItemMeta itemmetaXP = itemXP.getItemMeta();
- itemmetaXP.setDisplayName(plugin.getLocale().getMessage("interface.hopper.upgradewithxp"));
- ArrayList loreXP = new ArrayList<>();
- if (nextLevel != null)
- loreXP.add(plugin.getLocale().getMessage("interface.hopper.upgradewithxplore", nextLevel.getCostExperience()));
- else
- loreXP.add(plugin.getLocale().getMessage("interface.hopper.alreadymaxed"));
- itemmetaXP.setLore(loreXP);
- itemXP.setItemMeta(itemmetaXP);
-
- ItemStack itemECO = new ItemStack(Material.valueOf(plugin.getConfig().getString("Interfaces.Economy Icon")), 1);
- ItemMeta itemmetaECO = itemECO.getItemMeta();
- itemmetaECO.setDisplayName(plugin.getLocale().getMessage("interface.hopper.upgradewitheconomy"));
- ArrayList loreECO = new ArrayList<>();
- if (nextLevel != null)
- loreECO.add(plugin.getLocale().getMessage("interface.hopper.upgradewitheconomylore", Methods.formatEconomy(nextLevel.getCostEconomy())));
- else
- loreECO.add(plugin.getLocale().getMessage("interface.hopper.alreadymaxed"));
- itemmetaECO.setLore(loreECO);
- itemECO.setItemMeta(itemmetaECO);
-
int nu = 0;
while (nu != 27) {
inventory.setItem(nu, Methods.getGlass());
@@ -182,30 +160,54 @@ public class GUIOverview extends AbstractGUI {
}
}
- if (plugin.getConfig().getBoolean("Main.Upgrade With XP")
- && player.hasPermission("EpicHoppers.Upgrade.XP")
- && level.getCostExperience() != -1) {
- inventory.setItem(11, itemXP);
+ if (plugin.getConfig().getBoolean("Main.Allow hopper Upgrading")) {
+ ItemStack itemXP = new ItemStack(Material.valueOf(plugin.getConfig().getString("Interfaces.XP Icon")), 1);
+ ItemMeta itemmetaXP = itemXP.getItemMeta();
+ itemmetaXP.setDisplayName(plugin.getLocale().getMessage("interface.hopper.upgradewithxp"));
+ ArrayList loreXP = new ArrayList<>();
+ if (nextLevel != null)
+ loreXP.add(plugin.getLocale().getMessage("interface.hopper.upgradewithxplore", nextLevel.getCostExperience()));
+ else
+ loreXP.add(plugin.getLocale().getMessage("interface.hopper.alreadymaxed"));
+ itemmetaXP.setLore(loreXP);
+ itemXP.setItemMeta(itemmetaXP);
- registerClickable(11, ((player, inventory, cursor, slot, type) -> {
- hopper.upgrade(player, CostType.EXPERIENCE);
- this.hopper.overview(player);
- }));
+ ItemStack itemECO = new ItemStack(Material.valueOf(plugin.getConfig().getString("Interfaces.Economy Icon")), 1);
+ ItemMeta itemmetaECO = itemECO.getItemMeta();
+ itemmetaECO.setDisplayName(plugin.getLocale().getMessage("interface.hopper.upgradewitheconomy"));
+ ArrayList loreECO = new ArrayList<>();
+ if (nextLevel != null)
+ loreECO.add(plugin.getLocale().getMessage("interface.hopper.upgradewitheconomylore", Methods.formatEconomy(nextLevel.getCostEconomy())));
+ else
+ loreECO.add(plugin.getLocale().getMessage("interface.hopper.alreadymaxed"));
+ itemmetaECO.setLore(loreECO);
+ itemECO.setItemMeta(itemmetaECO);
+
+ if (plugin.getConfig().getBoolean("Main.Upgrade With XP")
+ && player.hasPermission("EpicHoppers.Upgrade.XP")
+ && level.getCostExperience() != -1) {
+ inventory.setItem(11, itemXP);
+
+ registerClickable(11, ((player, inventory, cursor, slot, type) -> {
+ hopper.upgrade(player, CostType.EXPERIENCE);
+ this.hopper.overview(player);
+ }));
+ }
+
+ if (plugin.getConfig().getBoolean("Main.Upgrade With Economy")
+ && player.hasPermission("EpicHoppers.Upgrade.ECO")
+ && level.getCostEconomy() != -1) {
+ inventory.setItem(15, itemECO);
+
+ registerClickable(15, ((player, inventory, cursor, slot, type) -> {
+ hopper.upgrade(player, CostType.ECONOMY);
+ this.hopper.overview(player);
+ }));
+ }
}
inventory.setItem(13, item);
- if (plugin.getConfig().getBoolean("Main.Upgrade With Economy")
- && player.hasPermission("EpicHoppers.Upgrade.ECO")
- && level.getCostEconomy() != -1) {
- inventory.setItem(15, itemECO);
-
- registerClickable(15, ((player, inventory, cursor, slot, type) -> {
- hopper.upgrade(player, CostType.ECONOMY);
- this.hopper.overview(player);
- }));
- }
-
inventory.setItem(0, Methods.getBackgroundGlass(true));
inventory.setItem(1, Methods.getBackgroundGlass(true));
inventory.setItem(2, Methods.getBackgroundGlass(false));
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/Hopper.java b/src/main/java/com/songoda/epichoppers/hopper/Hopper.java
index 1b68eef..77694fa 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/Hopper.java
+++ b/src/main/java/com/songoda/epichoppers/hopper/Hopper.java
@@ -8,7 +8,11 @@ import com.songoda.epichoppers.utils.CostType;
import com.songoda.epichoppers.utils.Methods;
import com.songoda.epichoppers.utils.ServerVersion;
import com.songoda.epichoppers.utils.TeleportTrigger;
-import org.bukkit.*;
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Sound;
+import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@@ -53,16 +57,16 @@ public class Hopper {
}
public void overview(Player player) {
- if (lastPlayer != null
- && lastPlayer != player.getUniqueId()
- && Bukkit.getPlayer(lastPlayer) != null) {
- Bukkit.getPlayer(lastPlayer).closeInventory();
- }
- if (placedBy == null) placedBy = player.getUniqueId();
+ if (lastPlayer != null
+ && lastPlayer != player.getUniqueId()
+ && Bukkit.getPlayer(lastPlayer) != null) {
+ Bukkit.getPlayer(lastPlayer).closeInventory();
+ }
+ if (placedBy == null) placedBy = player.getUniqueId();
EpicHoppers instance = EpicHoppers.getInstance();
- if (!player.hasPermission("epichoppers.overview")) return;
- new GUIOverview(instance, this, player);
+ if (!player.hasPermission("epichoppers.overview")) return;
+ new GUIOverview(instance, this, player);
}
public void upgrade(Player player, CostType type) {
@@ -70,118 +74,119 @@ public class Hopper {
if (plugin.getLevelManager().getLevels().containsKey(this.level.getLevel() + 1)) {
Level level = plugin.getLevelManager().getLevel(this.level.getLevel() + 1);
- int cost = type == CostType.ECONOMY ? level.getCostEconomy() : level.getCostExperience();
+ int cost = type == CostType.ECONOMY ? level.getCostEconomy() : level.getCostExperience();
- if (type == CostType.ECONOMY) {
- if (plugin.getEconomy() == null) {
- player.sendMessage("Economy not enabled.");
- return;
+ if (type == CostType.ECONOMY) {
+ if (plugin.getEconomy() == null) {
+ player.sendMessage("Economy not enabled.");
+ return;
+ }
+ if (!plugin.getEconomy().hasBalance(player, cost)) {
+ player.sendMessage(plugin.references.getPrefix() + plugin.getInstance().getLocale().getMessage("event.upgrade.cannotafford"));
+ return;
+ }
+ plugin.getEconomy().withdrawBalance(player, cost);
+ upgradeFinal(level, player);
+ } else if (type == CostType.EXPERIENCE) {
+ if (player.getLevel() >= cost || player.getGameMode() == GameMode.CREATIVE) {
+ if (player.getGameMode() != GameMode.CREATIVE) {
+ player.setLevel(player.getLevel() - cost);
}
- if (!plugin.getEconomy().hasBalance(player, cost)) {
- player.sendMessage(plugin.references.getPrefix() + plugin.getInstance().getLocale().getMessage("event.upgrade.cannotafford"));
- return;
- }
- plugin.getEconomy().withdrawBalance(player, cost);
upgradeFinal(level, player);
- } else if (type == CostType.EXPERIENCE) {
- if (player.getLevel() >= cost || player.getGameMode() == GameMode.CREATIVE) {
- if (player.getGameMode() != GameMode.CREATIVE) {
- player.setLevel(player.getLevel() - cost);
- }
- upgradeFinal(level, player);
- } else {
- player.sendMessage(plugin.references.getPrefix() + plugin.getLocale().getMessage("event.upgrade.cannotafford"));
- }
+ } else {
+ player.sendMessage(plugin.references.getPrefix() + plugin.getLocale().getMessage("event.upgrade.cannotafford"));
}
}
+ }
}
private void upgradeFinal(Level level, Player player) {
EpicHoppers instance = EpicHoppers.getInstance();
- this.level = level;
- syncName();
- if (instance.getLevelManager().getHighestLevel() != level) {
- player.sendMessage(instance.getLocale().getMessage("event.upgrade.success", level.getLevel()));
- } else {
- player.sendMessage(instance.getLocale().getMessage("event.upgrade.maxed", level.getLevel()));
- }
- Location loc = location.clone().add(.5, .5, .5);
+ this.level = level;
+ syncName();
+ if (instance.getLevelManager().getHighestLevel() != level) {
+ player.sendMessage(instance.getLocale().getMessage("event.upgrade.success", level.getLevel()));
+ } else {
+ player.sendMessage(instance.getLocale().getMessage("event.upgrade.maxed", level.getLevel()));
+ }
+ Location loc = location.clone().add(.5, .5, .5);
- if (!instance.isServerVersionAtLeast(ServerVersion.V1_12)) return;
+ if (!instance.isServerVersionAtLeast(ServerVersion.V1_12)) return;
- player.getWorld().spawnParticle(org.bukkit.Particle.valueOf(instance.getConfig().getString("Main.Upgrade Particle Type")), loc, 200, .5, .5, .5);
+ player.getWorld().spawnParticle(org.bukkit.Particle.valueOf(instance.getConfig().getString("Main.Upgrade Particle Type")), loc, 200, .5, .5, .5);
- if (instance.getLevelManager().getHighestLevel() != level) {
- player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 0.6F, 15.0F);
- } else {
- player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 2F, 25.0F);
+ if (instance.getLevelManager().getHighestLevel() != level) {
+ player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 0.6F, 15.0F);
+ } else {
+ player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 2F, 25.0F);
- if (!instance.isServerVersionAtLeast(ServerVersion.V1_13)) return;
+ if (!instance.isServerVersionAtLeast(ServerVersion.V1_13)) return;
- player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 2F, 25.0F);
- Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1.2F, 35.0F), 5L);
- Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1.8F, 35.0F), 10L);
- }
+ player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 2F, 25.0F);
+ Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1.2F, 35.0F), 5L);
+ Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_CHIME, 1.8F, 35.0F), 10L);
+ }
}
private void syncName() {
- org.bukkit.block.Hopper hopper = (org.bukkit.block.Hopper)location.getBlock().getState();
+ org.bukkit.block.Hopper hopper = (org.bukkit.block.Hopper) location.getBlock().getState();
if (EpicHoppers.getInstance().isServerVersionAtLeast(ServerVersion.V1_10))
hopper.setCustomName(Methods.formatName(level.getLevel(), false));
- hopper.update(true);
+ hopper.update(true);
}
public void timeout(Player player) {
EpicHoppers instance = EpicHoppers.getInstance();
- Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> {
- PlayerData playerData = instance.getPlayerDataManager().getPlayerData(player);
- if (playerData.getSyncType() != null) {
- player.sendMessage(instance.getLocale().getMessage("event.hopper.synctimeout"));
- playerData.setSyncType(null);
- }
- }, instance.getConfig().getLong("Main.Timeout When Syncing Hoppers"));
+ Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> {
+ PlayerData playerData = instance.getPlayerDataManager().getPlayerData(player);
+ if (playerData.getSyncType() != null) {
+ player.sendMessage(instance.getLocale().getMessage("event.hopper.synctimeout"));
+ playerData.setSyncType(null);
+ }
+ }, instance.getConfig().getLong("Main.Timeout When Syncing Hoppers"));
}
public void link(Block toLink, boolean filtered, Player player) {
EpicHoppers instance = EpicHoppers.getInstance();
- if (location.getWorld().equals(toLink.getLocation().getWorld())
- && !player.hasPermission("EpicHoppers.Override")
- && !player.hasPermission("EpicHoppers.Admin")
- && location.distance(toLink.getLocation()) > level.getRange()) {
- player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncoutofrange"));
- return;
- }
+ if (location.getWorld().equals(toLink.getLocation().getWorld())
+ && !player.hasPermission("EpicHoppers.Override")
+ && !player.hasPermission("EpicHoppers.Admin")
+ && location.distance(toLink.getLocation()) > level.getRange()) {
+ player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncoutofrange"));
+ return;
+ }
- if (linkedBlocks.contains(toLink)) {
- player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.already"));
- return;
- }
+ if (linkedBlocks.contains(toLink)) {
+ player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.already"));
+ return;
+ }
- if (!filtered)
- this.linkedBlocks.add(toLink.getLocation());
- else {
- this.filter.setEndPoint(toLink.getLocation());
- player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncsuccess"));
- instance.getPlayerDataManager().getPlayerData(player).setSyncType(null);
- return;
- }
- this.lastPlayer = player.getUniqueId();
-
- if (level.getLinkAmount() > 1) {
- if (getLinkedBlocks().size() == level.getLinkAmount()) {
- player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncdone"));
- return;
- }
- player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncsuccessmore", level.getLinkAmount() - getLinkedBlocks().size()));
- return;
- }
+ if (!filtered)
+ this.linkedBlocks.add(toLink.getLocation());
+ else {
+ this.filter.setEndPoint(toLink.getLocation());
player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncsuccess"));
instance.getPlayerDataManager().getPlayerData(player).setSyncType(null);
+ return;
+ }
+ this.lastPlayer = player.getUniqueId();
+
+ if (level.getLinkAmount() > 1) {
+ if (getLinkedBlocks().size() == level.getLinkAmount()) {
+ player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncdone"));
+ return;
+ }
+ player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncsuccessmore", level.getLinkAmount() - getLinkedBlocks().size()));
+ return;
+ }
+ player.sendMessage(instance.references.getPrefix() + instance.getLocale().getMessage("event.hopper.syncsuccess"));
+ instance.getPlayerDataManager().getPlayerData(player).setSyncType(null);
}
/**
* Ticks a hopper to determine when it can transfer items next
+ *
* @param maxTick The maximum amount the hopper can be ticked before next transferring items
* @param allowLooping If true, the hopper is allowed to transfer items if the tick is also valid
* @return true if the hopper should transfer an item, otherwise false
@@ -239,10 +244,17 @@ public class Hopper {
return autoCrafting;
}
- public void setAutoCrafting(ItemStack autoCrafting) {
+ public void setAutoCrafting(Player player, ItemStack autoCrafting) {
this.autoCrafting = autoCrafting;
- if (autoCrafting != null)
+ if (autoCrafting != null) {
+ int excess = autoCrafting.getAmount() - 1;
autoCrafting.setAmount(1);
+ if (excess > 0 && player != null) {
+ ItemStack item = autoCrafting.clone();
+ item.setAmount(excess);
+ player.getInventory().addItem(item);
+ }
+ }
}
public TeleportTrigger getTeleportTrigger() {
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/hopper/levels/LevelManager.java b/src/main/java/com/songoda/epichoppers/hopper/levels/LevelManager.java
index 9f83438..8a04db6 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/levels/LevelManager.java
+++ b/src/main/java/com/songoda/epichoppers/hopper/levels/LevelManager.java
@@ -21,7 +21,7 @@ public class LevelManager {
}
public Level getLevel(ItemStack item) {
- if (item.getItemMeta().getDisplayName().contains(":")) {
+ if (item.hasItemMeta() && item.getItemMeta().getDisplayName().contains(":")) {
String arr[] = item.getItemMeta().getDisplayName().replace(String.valueOf(ChatColor.COLOR_CHAR), "").split(":");
return getLevel(Integer.parseInt(arr[0]));
} else {
diff --git a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java
index 24d98b2..8d0dcf9 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java
+++ b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoCrafting.java
@@ -8,7 +8,11 @@ import com.songoda.epichoppers.utils.ServerVersion;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
-import org.bukkit.inventory.*;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.Recipe;
+import org.bukkit.inventory.ShapedRecipe;
+import org.bukkit.inventory.ShapelessRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
@@ -19,22 +23,6 @@ import java.util.Map;
public class ModuleAutoCrafting implements Module {
private final Map cachedRecipes = new HashMap<>();
- private final Map lastMaterial = new HashMap<>();
-
- public static List compressItemStack(List target) {
- HashMap sortingList = new HashMap<>();
- for (ItemStack item : target) {
- if (sortingList.containsKey(item.getType())) {
- ItemStack existing = sortingList.get(item.getType());
- existing.setAmount(existing.getAmount() + item.getAmount());
- sortingList.put(existing.getType(), existing);
- } else {
- sortingList.put(item.getType(), item);
- }
- }
- List list = new ArrayList<>(sortingList.values());
- return list;
- }
@Override
public String getName() {
@@ -42,61 +30,69 @@ public class ModuleAutoCrafting implements Module {
}
public void run(Hopper hopper, Inventory hopperInventory) {
- if (hopper.getAutoCrafting() == null || hopperInventory == null) return;
+ if (hopper.getAutoCrafting() == null
+ || hopperInventory == null
+ || hopperInventory.getSize() == 0
+ || !canMove(hopperInventory, new ItemStack(hopper.getAutoCrafting()))
+ || cachedRecipes.get(hopper.getAutoCrafting()) == null)
+ return;
- if (hopper.getAutoCrafting() != null && canMove(hopperInventory, new ItemStack(hopper.getAutoCrafting()))) {
-
- if (cachedRecipes.get(hopper.getAutoCrafting()) == null) return;
-
- top:
- for (Recipe recipe : cachedRecipes.get(hopper.getAutoCrafting()).getRecipes()) {
- if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe)) continue;
- List ingredientMap = null;
- if (recipe instanceof ShapelessRecipe) ingredientMap = ((ShapelessRecipe) recipe).getIngredientList();
- if (recipe instanceof ShapedRecipe)
- ingredientMap = new ArrayList<>(((ShapedRecipe) recipe).getIngredientMap().values());
- if (hopperInventory.getSize() == 0) return;
-
- Map items = new HashMap<>();
- for (ItemStack item : ingredientMap) {
- if (item == null) continue;
- if (!items.containsKey(item.getType())) {
- items.put(item.getType(), item.clone());
- } else {
- items.get(item.getType()).setAmount(items.get(item.getType()).getAmount() + 1);
- }
- }
-
- for (ItemStack item : items.values()) {
- int amt = 0;
- for (ItemStack i : hopperInventory.getContents()) {
- if (i == null) continue;
- if (!i.isSimilar(item)) continue;
- amt += i.getAmount();
- }
-
- if (amt < item.getAmount()) {
- continue top;
- }
- }
- main2:
- for (ItemStack toRemove : items.values()) {
- int amtRemoved = 0;
- for (ItemStack i : hopperInventory.getContents()) {
- if (i == null || !i.isSimilar(toRemove)) continue;
- if (toRemove.getAmount() - amtRemoved <= i.getAmount()) {
- toRemove.setAmount(toRemove.getAmount() - amtRemoved);
- hopperInventory.removeItem(toRemove);
- continue main2;
- } else {
- amtRemoved += i.getAmount();
- hopperInventory.removeItem(i);
- }
- }
- }
- hopperInventory.addItem(recipe.getResult());
+ top:
+ for (Recipe recipe : cachedRecipes.get(hopper.getAutoCrafting()).getRecipes()) {
+ if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe))
+ continue;
+ List ingredientMap;
+ if (recipe instanceof ShapelessRecipe) {
+ ingredientMap = ((ShapelessRecipe) recipe).getIngredientList();
+ } else {
+ ingredientMap = new ArrayList<>(((ShapedRecipe) recipe).getIngredientMap().values());
}
+
+ Map items = new HashMap<>();
+ for (ItemStack item : ingredientMap) {
+ if (item == null)
+ continue;
+
+ if (!items.containsKey(item.getType())) {
+ items.put(item.getType(), item.clone());
+ } else {
+ items.get(item.getType()).setAmount(items.get(item.getType()).getAmount() + 1);
+ }
+ }
+
+ for (ItemStack item : items.values()) {
+ int amt = 0;
+ for (ItemStack i : hopperInventory.getContents()) {
+ if (i == null || !isSimilar(i, item))
+ continue;
+ amt += i.getAmount();
+ }
+
+ if (amt < item.getAmount()) {
+ continue top;
+ }
+ }
+
+ main2:
+ for (ItemStack toRemove : items.values()) {
+ int amtRemoved = 0;
+ for (ItemStack i : hopperInventory.getContents()) {
+ if (i == null || !isSimilar(i, toRemove))
+ continue;
+
+ amtRemoved += Math.min(toRemove.getAmount() - amtRemoved, i.getAmount());
+ if (amtRemoved == i.getAmount())
+ hopperInventory.removeItem(i);
+ else
+ i.setAmount(i.getAmount() - amtRemoved);
+
+ if (amtRemoved == toRemove.getAmount())
+ continue main2;
+ }
+ }
+
+ hopperInventory.addItem(recipe.getResult());
}
}
@@ -126,30 +122,30 @@ public class ModuleAutoCrafting implements Module {
ItemStack itemStack = hopper.getAutoCrafting();
- if (itemStack.getType() == Material.AIR) return materials;
+ if (itemStack.getType() == Material.AIR)
+ return materials;
- if (lastMaterial.get(hopper) != null && !lastMaterial.get(hopper).isSimilar(itemStack)) {
- lastMaterial.put(hopper, itemStack);
- cachedRecipes.remove(hopper);
- }
-
- if (cachedRecipes.keySet().stream().noneMatch(itemStack1 -> itemStack1.isSimilar(itemStack))) {
+ if (cachedRecipes.get(itemStack) == null) {
Recipes recipes = new Recipes();
for (Recipe recipe : Bukkit.getServer().getRecipesFor(itemStack)) {
recipes.addRecipe(recipe);
}
cachedRecipes.put(itemStack, recipes);
- } else {
+ }
+
+ if (cachedRecipes.get(itemStack) != null) {
Recipes recipes = cachedRecipes.get(itemStack);
for (Recipe recipe : recipes.getRecipes()) {
if (recipe instanceof ShapedRecipe) {
for (ItemStack itemStack1 : ((ShapedRecipe) recipe).getIngredientMap().values()) {
- if (itemStack1 == null) continue;
+ if (itemStack1 == null)
+ continue;
materials.add(itemStack1.getType());
}
} else if (recipe instanceof ShapelessRecipe) {
for (ItemStack itemStack1 : ((ShapelessRecipe) recipe).getIngredientList()) {
- if (itemStack1 == null) continue;
+ if (itemStack1 == null)
+ continue;
materials.add(itemStack1.getType());
}
}
@@ -165,16 +161,24 @@ public class ModuleAutoCrafting implements Module {
}
private boolean canMove(Inventory inventory, ItemStack item) {
- if (inventory.firstEmpty() != -1) return true;
+ if (inventory.firstEmpty() != -1) return true;
- for (ItemStack stack : inventory.getContents()) {
- if (stack.isSimilar(item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()) {
- return true;
- }
+ for (ItemStack stack : inventory.getContents()) {
+ if (stack.isSimilar(item) && (stack.getAmount() + item.getAmount()) < stack.getMaxStackSize()) {
+ return true;
}
+ }
return false;
}
+ private boolean isSimilar(ItemStack is1, ItemStack is2) {
+ if (EpicHoppers.getInstance().isServerVersionAtLeast(ServerVersion.V1_13)) {
+ return is1.getType() == is2.getType();
+ } else {
+ return is1.getType() == is2.getType() && is1.getDurability() == is2.getDurability();
+ }
+ }
+
class Recipes {
private List recipes = new ArrayList<>();
diff --git a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoSell.java b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoSell.java
index c3b7f90..1540b41 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoSell.java
+++ b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleAutoSell.java
@@ -2,6 +2,7 @@ package com.songoda.epichoppers.hopper.levels.modules;
import com.songoda.epichoppers.EpicHoppers;
import com.songoda.epichoppers.hopper.Hopper;
+import com.songoda.epichoppers.tasks.HopTask;
import com.songoda.epichoppers.utils.Methods;
import com.songoda.epichoppers.utils.ServerVersion;
import org.bukkit.Bukkit;
@@ -41,6 +42,8 @@ public class ModuleAutoSell implements Module {
if (instance.getEconomy() == null) return;
+ boolean updateComparators = false;
+
List list = instance.getConfig().getStringList("Main.AutoSell Prices");
for (String line : list) {
@@ -55,11 +58,16 @@ public class ModuleAutoSell implements Module {
instance.getEconomy().deposit(Bukkit.getOfflinePlayer(hopper.getPlacedBy()), price * itemStack.getAmount());
hopperInventory.removeItem(itemStack);
+
+ updateComparators = true;
}
} catch (Exception ignored) {
}
}
hopper.setAutoSellTimer(timeOut);
+
+ if (updateComparators)
+ HopTask.updateAdjacentComparators(hopper.getLocation());
}
hopper.setAutoSellTimer(hopper.getAutoSellTimer() - hopperTickRate);
}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleBlockBreak.java b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleBlockBreak.java
index 22f9656..ecfe22f 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleBlockBreak.java
+++ b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleBlockBreak.java
@@ -11,6 +11,7 @@ import org.bukkit.Sound;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
@@ -37,7 +38,8 @@ public class ModuleBlockBreak implements Module {
public void run(Hopper hopper, Inventory hopperInventory) {
Block block = hopper.getLocation().getBlock();
- if (!hopper.isAutoBreaking()) return;
+ if (!hopper.isAutoBreaking())
+ return;
if (!blockTick.containsKey(block)) {
blockTick.put(block, 1);
@@ -46,11 +48,21 @@ public class ModuleBlockBreak implements Module {
int tick = blockTick.get(block);
int put = tick + 1;
blockTick.put(block, put);
- if (tick < amount) return;
- Block above = block.getRelative(0, 1, 0);
- if (above.getType() == Material.WATER || above.getType() == Material.LAVA) return;
+ if (tick < amount)
+ return;
- if (above.getType() != Material.AIR && above.getType() != Material.HOPPER && !EpicHoppers.getInstance().getConfig().getStringList("Main.BlockBreak Blacklisted Blocks").contains(above.getType().name())) {
+ Block above = block.getRelative(0, 1, 0);
+ if (above.getType() == Material.WATER
+ || above.getType() == Material.LAVA
+ || above.getType() == Material.AIR
+ || above.getState() instanceof InventoryHolder)
+ return;
+
+ // Don't break farm items from EpicFarming
+ if (EpicHoppers.getInstance().isEpicFarming() && com.songoda.epicfarming.EpicFarmingPlugin.getInstance().getFarmManager().getFarm(above) != null)
+ return;
+
+ if (!EpicHoppers.getInstance().getConfig().getStringList("Main.BlockBreak Blacklisted Blocks").contains(above.getType().name())) {
if (EpicHoppers.getInstance().isServerVersionAtLeast(ServerVersion.V1_9))
above.getWorld().playSound(above.getLocation(), Sound.BLOCK_STONE_BREAK, 1F, 1F);
Location locationAbove = above.getLocation();
@@ -62,7 +74,17 @@ public class ModuleBlockBreak implements Module {
if (EpicHoppers.getInstance().isServerVersionAtLeast(ServerVersion.V1_9))
above.getWorld().spawnParticle(Particle.valueOf(EpicHoppers.getInstance().getConfig().getString("Main.BlockBreak Particle Type")), locationAbove, 15, xx, yy, zz);
+ boolean waterlogged = false;
+ if (EpicHoppers.getInstance().isServerVersionAtLeast(ServerVersion.V1_13)
+ && above.getBlockData() instanceof org.bukkit.block.data.Waterlogged
+ && ((org.bukkit.block.data.Waterlogged)above.getBlockData()).isWaterlogged()) {
+ waterlogged = true;
+ }
+
above.breakNaturally();
+
+ if (waterlogged)
+ above.setType(Material.WATER);
}
blockTick.remove(block);
}
diff --git a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleSuction.java b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleSuction.java
index fd0035a..fc44dca 100644
--- a/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleSuction.java
+++ b/src/main/java/com/songoda/epichoppers/hopper/levels/modules/ModuleSuction.java
@@ -14,7 +14,6 @@ import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.metadata.FixedMetadataValue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -29,6 +28,7 @@ public class ModuleSuction implements Module {
public static List blacklist = new ArrayList<>();
private boolean wildStacker = Bukkit.getPluginManager().isPluginEnabled("WildStacker");
+ private boolean ultimateStacker = Bukkit.getPluginManager().isPluginEnabled("UltimateStacker");
private Class> clazzItemStack, clazzItem, clazzCraftItemStack;
private Method methodGetItem, methodAsNMSCopy;
@@ -63,7 +63,7 @@ public class ModuleSuction implements Module {
hopper.getLocation().getWorld().getNearbyEntities(hopper.getLocation().add(0.5, 0.5, 0.5), radius, radius, radius).stream()
.filter(entity -> entity.getType() == EntityType.DROPPED_ITEM
- && entity.getTicksLived() > 10
+ && entity.getTicksLived() >= ((Item)entity).getPickupDelay()
&& entity.getLocation().getBlock().getType() != Material.HOPPER).forEach(entity -> {
Item item = (Item) entity;
@@ -80,6 +80,9 @@ public class ModuleSuction implements Module {
if (wildStacker)
itemStack.setAmount(WildStackerAPI.getItemAmount((Item) entity));
+ if (ultimateStacker && item.hasMetadata("US_AMT"))
+ itemStack.setAmount(item.getMetadata("US_AMT").get(0).asInt());
+
if (!canMove(hopperInventory, itemStack) || blacklist.contains(item.getUniqueId()))
return;
@@ -90,7 +93,7 @@ public class ModuleSuction implements Module {
float zz = (float) (0 + (Math.random() * .1));
if (EpicHoppers.getInstance().isServerVersionAtLeast(ServerVersion.V1_9))
- entity.getLocation().getWorld().spawnParticle(Particle.FLAME, entity.getLocation(), 5, xx, yy, zz, 0);
+ entity.getLocation().getWorld().spawnParticle(Particle.FLAME, entity.getLocation(), 5, xx, yy, zz, 0);
for (ItemStack is : hopperInventory.addItem(itemStack).values()) {
entity.getWorld().dropItemNaturally(entity.getLocation(), is);
diff --git a/src/main/java/com/songoda/epichoppers/listeners/BlockListeners.java b/src/main/java/com/songoda/epichoppers/listeners/BlockListeners.java
index ee39928..2b40d89 100644
--- a/src/main/java/com/songoda/epichoppers/listeners/BlockListeners.java
+++ b/src/main/java/com/songoda/epichoppers/listeners/BlockListeners.java
@@ -39,28 +39,27 @@ public class BlockListeners implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockPlace(BlockPlaceEvent e) {
- Player player = e.getPlayer();
+ Player player = e.getPlayer();
- if (e.getBlock().getType() != Material.HOPPER) return;
+ if (e.getBlock().getType() != Material.HOPPER)
+ return;
- if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(e.getBlock().getLocation()))
- return;
+ if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(e.getBlock().getLocation()))
+ return;
- int amt = count(e.getBlock().getChunk());
+ int amt = count(e.getBlock().getChunk());
- int max = maxHoppers(player);
+ int max = maxHoppers(player);
- if (max != -1 && amt > max) {
- player.sendMessage(instance.getLocale().getMessage("event.hopper.toomany", max));
- e.setCancelled(true);
- return;
- }
+ if (max != -1 && amt > max) {
+ player.sendMessage(instance.getLocale().getMessage("event.hopper.toomany", max));
+ e.setCancelled(true);
+ return;
+ }
- if (!e.getItemInHand().getItemMeta().hasDisplayName()) return;
+ ItemStack item = e.getItemInHand().clone();
- ItemStack item = e.getItemInHand().clone();
-
- instance.getHopperManager().addHopper(e.getBlock().getLocation(), new Hopper(e.getBlock(), instance.getLevelManager().getLevel(item), player.getUniqueId(), player.getUniqueId(), new ArrayList<>(), new Filter(), TeleportTrigger.DISABLED, null));
+ instance.getHopperManager().addHopper(e.getBlock().getLocation(), new Hopper(e.getBlock(), instance.getLevelManager().getLevel(item), player.getUniqueId(), player.getUniqueId(), new ArrayList<>(), new Filter(), TeleportTrigger.DISABLED, null));
}
private int maxHoppers(Player player) {
@@ -74,57 +73,57 @@ public class BlockListeners implements Listener {
}
private int count(Chunk c) {
- int count = 0;
- for (int x = 0; x < 16; x++) {
- for (int z = 0; z < 16; z++) {
- for (int y = 0; y < c.getWorld().getMaxHeight(); y++) {
- if (c.getBlock(x, y, z).getType() == Material.HOPPER) count++;
- }
+ int count = 0;
+ for (int x = 0; x < 16; x++) {
+ for (int z = 0; z < 16; z++) {
+ for (int y = 0; y < c.getWorld().getMaxHeight(); y++) {
+ if (c.getBlock(x, y, z).getType() == Material.HOPPER) count++;
}
}
- return count;
+ }
+ return count;
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent event) {
- Block block = event.getBlock();
- Player player = event.getPlayer();
+ Block block = event.getBlock();
+ Player player = event.getPlayer();
- handleSyncTouch(event);
+ handleSyncTouch(event);
- if (event.getBlock().getType() != Material.HOPPER) return;
+ if (event.getBlock().getType() != Material.HOPPER) return;
- if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(block.getLocation()))
- return;
+ if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(block.getLocation()))
+ return;
- Hopper hopper = instance.getHopperManager().getHopper(block);
+ Hopper hopper = instance.getHopperManager().getHopper(block);
- Level level = hopper.getLevel();
+ Level level = hopper.getLevel();
- if (level.getLevel() > 1) {
- event.setCancelled(true);
- ItemStack item = instance.newHopperItem(level);
+ if (level.getLevel() > 1) {
+ event.setCancelled(true);
+ ItemStack item = instance.newHopperItem(level);
- event.getBlock().setType(Material.AIR);
- event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), item);
- }
+ event.getBlock().setType(Material.AIR);
+ event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), item);
+ }
- for (ItemStack m : hopper.getFilter().getWhiteList()) {
- if (m != null)
- event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), m);
- }
+ for (ItemStack m : hopper.getFilter().getWhiteList()) {
+ if (m != null)
+ event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), m);
+ }
- for (ItemStack m : hopper.getFilter().getBlackList()) {
- if (m != null)
- event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), m);
- }
- for (ItemStack m : hopper.getFilter().getVoidList()) {
- if (m != null)
- event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), m);
- }
- instance.getHopperManager().removeHopper(block.getLocation());
+ for (ItemStack m : hopper.getFilter().getBlackList()) {
+ if (m != null)
+ event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), m);
+ }
+ for (ItemStack m : hopper.getFilter().getVoidList()) {
+ if (m != null)
+ event.getBlock().getLocation().getWorld().dropItemNaturally(event.getBlock().getLocation(), m);
+ }
+ instance.getHopperManager().removeHopper(block.getLocation());
- instance.getPlayerDataManager().getPlayerData(player).setSyncType(null);
+ instance.getPlayerDataManager().getPlayerData(player).setSyncType(null);
}
private void handleSyncTouch(BlockBreakEvent event) {
diff --git a/src/main/java/com/songoda/epichoppers/listeners/HopperListeners.java b/src/main/java/com/songoda/epichoppers/listeners/HopperListeners.java
index d991f25..c4d192b 100644
--- a/src/main/java/com/songoda/epichoppers/listeners/HopperListeners.java
+++ b/src/main/java/com/songoda/epichoppers/listeners/HopperListeners.java
@@ -2,11 +2,15 @@ package com.songoda.epichoppers.listeners;
import com.songoda.epichoppers.EpicHoppers;
import com.songoda.epichoppers.hopper.Hopper;
+import com.songoda.epichoppers.utils.HopperDirection;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
+import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Minecart;
+import org.bukkit.entity.minecart.HopperMinecart;
+import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryMoveItemEvent;
@@ -29,7 +33,17 @@ public class HopperListeners implements Listener {
Inventory source = event.getSource();
Inventory destination = event.getDestination();
- if (!(source.getHolder() instanceof org.bukkit.block.Hopper)) return;
+ // Hopper minecarts should be able to take care of themselves
+ // Let EpicHoppers take over if the hopper is pointing down though
+ if (destination.getHolder() instanceof HopperMinecart && (!(source.getHolder() instanceof org.bukkit.block.Hopper)
+ || HopperDirection.getDirection(((org.bukkit.block.Hopper)destination.getHolder()).getRawData()) != HopperDirection.DOWN))
+ return;
+
+ // Shulker boxes have a mind of their own and relentlessly steal items from hoppers
+ if (destination.getHolder() instanceof ShulkerBox || !(source.getHolder() instanceof org.bukkit.block.Hopper)) {
+ event.setCancelled(true);
+ return;
+ }
if (instance.isLiquidtanks() && net.arcaniax.liquidtanks.object.LiquidTankAPI.isLiquidTank(event.getDestination().getLocation()))
return;
@@ -47,7 +61,8 @@ public class HopperListeners implements Listener {
return;
}
- if (!(destinationLocation.getBlock().getState() instanceof InventoryHolder)) return;
+ if (!(destinationLocation.getBlock().getState() instanceof InventoryHolder))
+ return;
Hopper hopper = instance.getHopperManager().getHopper(sourceHopper.getLocation());
@@ -55,6 +70,5 @@ public class HopperListeners implements Listener {
hopper.addLinkedBlock(destinationLocation);
event.setCancelled(true);
-
}
}
diff --git a/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java b/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java
index 2750618..aaf1b56 100644
--- a/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java
+++ b/src/main/java/com/songoda/epichoppers/listeners/InteractListeners.java
@@ -50,58 +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 (instance.getConfig().getBoolean("Main.Allow hopper Upgrading")
- && !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/listeners/InventoryListeners.java b/src/main/java/com/songoda/epichoppers/listeners/InventoryListeners.java
index fadf178..9f21c8c 100644
--- a/src/main/java/com/songoda/epichoppers/listeners/InventoryListeners.java
+++ b/src/main/java/com/songoda/epichoppers/listeners/InventoryListeners.java
@@ -55,4 +55,4 @@ public class InventoryListeners implements Listener {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/songoda/epichoppers/storage/StorageItem.java b/src/main/java/com/songoda/epichoppers/storage/StorageItem.java
index 19201cb..c8bde0f 100644
--- a/src/main/java/com/songoda/epichoppers/storage/StorageItem.java
+++ b/src/main/java/com/songoda/epichoppers/storage/StorageItem.java
@@ -54,6 +54,7 @@ public class StorageItem {
public boolean asBoolean() {
if (object == null) return false;
+ if (object instanceof Integer) return (Integer) object == 1;
return (boolean) object;
}
@@ -63,6 +64,8 @@ public class StorageItem {
}
public Object asObject() {
+ if (object == null) return null;
+ if (object instanceof Boolean) return (Boolean) object ? 1 : 0;
return object;
}
diff --git a/src/main/java/com/songoda/epichoppers/storage/types/StorageMysql.java b/src/main/java/com/songoda/epichoppers/storage/types/StorageMysql.java
index 495fc7c..b7cd52e 100644
--- a/src/main/java/com/songoda/epichoppers/storage/types/StorageMysql.java
+++ b/src/main/java/com/songoda/epichoppers/storage/types/StorageMysql.java
@@ -105,8 +105,10 @@ public class StorageMysql extends Storage {
continue;
toSave.remove(to.getKey());
for (int i = 0; i < to.getValue().length; i ++) {
- if (!to.getValue()[i].asObject().toString()
- .equals(last.getValue()[i].asObject().toString())) {
+ if ((to.getValue()[i].asObject() != null && last.getValue()[i].asObject() == null)
+ || (last.getValue()[i].asObject() == null && to.getValue()[i].asObject() != null)
+ || (last.getValue()[i].asObject() != null && to.getValue()[i].asObject() != null
+ && !to.getValue()[i].asObject().toString().equals(last.getValue()[i].asObject().toString()))) {
//Update
StorageItem[] items = to.getValue();
StringBuilder sql = new StringBuilder(String.format("UPDATE `" + instance.getConfig().getString("Database.Prefix") + "%s`", toKey));
diff --git a/src/main/java/com/songoda/epichoppers/tasks/HopTask.java b/src/main/java/com/songoda/epichoppers/tasks/HopTask.java
index 38fca9d..49c3fea 100644
--- a/src/main/java/com/songoda/epichoppers/tasks/HopTask.java
+++ b/src/main/java/com/songoda/epichoppers/tasks/HopTask.java
@@ -2,6 +2,7 @@ package com.songoda.epichoppers.tasks;
import com.songoda.epichoppers.EpicHoppers;
import com.songoda.epichoppers.boost.BoostData;
+import com.songoda.epichoppers.hopper.HopperManager;
import com.songoda.epichoppers.hopper.levels.modules.Module;
import com.songoda.epichoppers.utils.HopperDirection;
import com.songoda.epichoppers.utils.Methods;
@@ -12,9 +13,14 @@ import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Hopper;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.inventory.BrewerInventory;
+import org.bukkit.inventory.DoubleChestInventory;
import org.bukkit.inventory.FurnaceInventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
@@ -25,9 +31,14 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
/**
* Created by songoda on 3/14/2017.
@@ -43,7 +54,7 @@ public class HopTask extends BukkitRunnable {
public HopTask(EpicHoppers plug) {
plugin = plug;
- this.hopTicks = Setting.HOP_TICKS.getInt() / 2; // Purposeful integer division
+ this.hopTicks = Math.max(1, Setting.HOP_TICKS.getInt() / 2); // Purposeful integer division. Don't go below 1.
this.runTaskTimer(plugin, 0, 2);
}
@@ -52,6 +63,8 @@ public class HopTask extends BukkitRunnable {
Collection hoppers = plugin.getHopperManager().getHoppers().values();
Iterator itr = hoppers.iterator();
+ Set toRemove = new HashSet<>();
+
main:
while (itr.hasNext()) {
com.songoda.epichoppers.hopper.Hopper hopper = itr.next();
@@ -69,7 +82,7 @@ public class HopTask extends BukkitRunnable {
// If block is not a hopper remove and continue.
if (block.getType() != Material.HOPPER) {
- plugin.getHopperManager().removeHopper(location);
+ toRemove.add(location);
continue;
}
@@ -112,47 +125,46 @@ public class HopTask extends BukkitRunnable {
BoostData boostData = plugin.getBoostManager().getBoost(hopper.getPlacedBy());
int amount = hopper.getLevel().getAmount() * (boostData == null ? 1 : boostData.getMultiplier());
- // Fetch all hopper contents.
- ItemStack[] hopperContents = hopperState.getInventory().getContents();
+ // Grab items from the container above (includes storage/hopper minecarts and EpicFarming farm items)
+ // If the container above is a hopper, ignore it if it's pointing down
+ Block above = block.getRelative(BlockFace.UP);
+ boolean isFarmItem = false;
+ Collection nearbyEntities = null;
+ outer:
+ if ((above.getState() instanceof InventoryHolder
+ && (above.getType() != Material.HOPPER || HopperDirection.getDirection(above.getState().getRawData()) != HopperDirection.DOWN))
+ || !(nearbyEntities = above.getWorld().getNearbyEntities(above.getLocation().clone().add(0.5, 0.5, 0.5), 0.5, 0.5, 0.5)).isEmpty()
+ || (isFarmItem = this.isFarmItem(above))) {
- // Get filter endpoint
- InventoryHolder filterEndpoint = this.getFilterEndpoint(hopper);
-
- // Loop through our container list.
- for (Location destinationLocation : linkedContainers) {
-
- // Make sure the destination chunk is loaded.
- if (!destinationLocation.getWorld().isChunkLoaded(destinationLocation.getBlockX() >> 4,
- destinationLocation.getBlockZ() >> 4))
- continue;
-
- // Get the destination block.
- Block destinationBlock = destinationLocation.getBlock();
-
- // Get the destination state.
- BlockState blockState = destinationBlock.getState();
-
- // Remove if destination is not a inventory holder.
- if (!(blockState instanceof InventoryHolder)) {
- hopper.removeLinkedBlock(destinationLocation);
- continue;
+ // Get the inventory holder. Special check for EpicFarming.
+ // Get the slots that we can pull items from.
+ InventoryHolder aboveInvHolder;
+ int[] pullableSlots;
+ if (isFarmItem) {
+ aboveInvHolder = this.getEpicFarmingItemWrapped(above);
+ pullableSlots = IntStream.rangeClosed(27, 53).toArray();
+ } else if (nearbyEntities != null) {
+ if ((aboveInvHolder = this.getRandomInventoryHolderFromEntities(nearbyEntities)) == null)
+ break outer;
+ if (aboveInvHolder instanceof StorageMinecart) {
+ pullableSlots = IntStream.rangeClosed(0, 26).toArray();
+ } else {
+ pullableSlots = IntStream.rangeClosed(0, 4).toArray();
+ }
+ } else {
+ aboveInvHolder = (InventoryHolder) above.getState();
+ pullableSlots = this.getPullableSlots(aboveInvHolder, above.getType());
}
- // Cast blockState to container
- InventoryHolder destinationContainer = ((InventoryHolder) blockState);
+ ItemStack[] contents = aboveInvHolder.getInventory().getContents();
- // Loop through all of our hoppers item slots.
- for (int i = 0; i < 5; i++) {
+ // Loop over the pullable slots and try to pull something.
+ for (int i : pullableSlots) {
+ // Get the item
+ ItemStack item = contents[i];
- // Skip if slot empty.
- if (hopperContents[i] == null)
- continue;
-
- // Get potential item to move.
- ItemStack item = hopperContents[i];
-
- // Skip if item blacklisted.
- if ((this.blacklist.containsKey(hopperState) && this.blacklist.get(hopperState).isSimilar(item)) || blockedMaterials.contains(item.getType()))
+ // If item is invalid, try the next slot.
+ if (item == null)
continue;
// Get amount to move.
@@ -162,14 +174,92 @@ public class HopTask extends BukkitRunnable {
ItemStack itemToMove = item.clone();
itemToMove.setAmount(amountToMove);
- // Process void.
- if (hopper.getFilter().getVoidList().stream().anyMatch(itemStack -> itemStack.isSimilar(item))) {
- item.setAmount(item.getAmount() - amountToMove);
- continue;
- }
+ // Add item to container and break on success.
+ if (this.addItem(hopper, aboveInvHolder, hopperState, block.getType(), item, itemToMove, amountToMove))
+ break;
+ }
+ }
- // Set current destination.
- InventoryHolder currentDestination = destinationContainer;
+ // Fetch all hopper contents.
+ ItemStack[] hopperContents = hopperState.getInventory().getContents();
+
+ // Loop over hopper inventory to process void filtering.
+ if (!hopper.getFilter().getVoidList().isEmpty()) {
+ for (ItemStack item : hopperContents) {
+ // Skip if slot empty.
+ if (item == null)
+ continue;
+
+ // Try to void it out
+ int amountToVoid = item.getAmount() < amount ? item.getAmount() : amount;
+ if (hopper.getFilter().getVoidList().stream().anyMatch(itemStack -> itemStack.isSimilar(item))) {
+ item.setAmount(item.getAmount() - amountToVoid);
+ break;
+ }
+ }
+ }
+
+ // Get filter endpoint
+ InventoryHolder filterEndpoint = this.getFilterEndpoint(hopper);
+
+ // Keep track of any destination containers
+ List destinationContainers = new ArrayList<>();
+
+ // Add linked containers to the destinations
+ for (Location linkedContainerLocation : linkedContainers) {
+ // Make sure the destination chunk is loaded.
+ if (!linkedContainerLocation.getWorld().isChunkLoaded(linkedContainerLocation.getBlockX() >> 4,
+ linkedContainerLocation.getBlockZ() >> 4))
+ continue;
+
+ // Get the destination block.
+ Block destinationBlock = linkedContainerLocation.getBlock();
+
+ // Get the destination state.
+ BlockState blockState = destinationBlock.getState();
+
+ // Remove if destination is not a inventory holder.
+ if (!(blockState instanceof InventoryHolder)) {
+ hopper.removeLinkedBlock(linkedContainerLocation);
+ continue;
+ }
+
+ // Add to the destination containers list
+ destinationContainers.add((InventoryHolder) blockState);
+ }
+
+ // Add storage/hopper minecarts the hopper is pointing into to the list if there aren't any destinations
+ if (destinationContainers.size() < 2) {
+ destinationContainers.addAll(block.getWorld().getNearbyEntities(hopperDirection.getLocation(location).clone().add(0.5, 0.5, 0.5), 0.5, 0.5, 0.5)
+ .stream().filter(e -> e.getType() == EntityType.MINECART_CHEST || e.getType() == EntityType.MINECART_HOPPER)
+ .map(e -> (InventoryHolder) e).collect(Collectors.toSet()));
+ }
+
+ // Loop through our destination list.
+ for (InventoryHolder currentDestination : destinationContainers) {
+
+ // Loop through all of our hoppers item slots.
+ for (int i = 0; i < 5; i++) {
+
+ // Get potential item to move.
+ ItemStack item = hopperContents[i];
+
+ // Skip if slot empty.
+ if (item == null)
+ continue;
+
+ // Skip if item blacklisted or void.
+ if ((this.blacklist.containsKey(hopperState) && this.blacklist.get(hopperState).isSimilar(item))
+ || blockedMaterials.contains(item.getType())
+ || hopper.getFilter().getVoidList().stream().anyMatch(itemStack -> itemStack.isSimilar(item)))
+ continue;
+
+ // Get amount to move.
+ int amountToMove = item.getAmount() < amount ? item.getAmount() : amount;
+
+ // Create item that will be moved.
+ ItemStack itemToMove = item.clone();
+ itemToMove.setAmount(amountToMove);
// Process whitelist and blacklist.
boolean blocked = (!hopper.getFilter().getWhiteList().isEmpty() && hopper.getFilter().getWhiteList().stream().noneMatch(itemStack -> itemStack.isSimilar(item))
@@ -179,12 +269,15 @@ public class HopTask extends BukkitRunnable {
// otherwise set the current destination to the endpoint.
if (blocked) {
if (filterEndpoint == null || !this.canMove(filterEndpoint.getInventory(), itemToMove))
- break;
+ continue;
currentDestination = filterEndpoint;
}
+ // Get the material of the destination
+ Material destinationMaterial = currentDestination instanceof BlockState ? ((BlockState) currentDestination).getType() : Material.AIR;
+
// Add item to container and continue on success.
- if (this.addItem(hopper, hopperState, currentDestination, destinationBlock.getType(), item, itemToMove, amountToMove))
+ if (this.addItem(hopper, hopperState, currentDestination, destinationMaterial, item, itemToMove, amountToMove))
continue main;
}
}
@@ -193,6 +286,10 @@ public class HopTask extends BukkitRunnable {
}
}
+ // Clear out invalid hoppers
+ HopperManager hopperManager = plugin.getHopperManager();
+ toRemove.forEach(hopperManager::removeHopper);
+
// Empty blacklist in preparation for next cycle.
this.blacklist.clear();
}
@@ -202,6 +299,10 @@ public class HopTask extends BukkitRunnable {
Inventory destinationInventory = currentDestination.getInventory();
+ // Don't transfer shulker boxes into other shulker boxes, that's a bad idea.
+ if (destinationType.name().contains("SHULKER_BOX") && item.getType().name().contains("SHULKER_BOX"))
+ return false;
+
switch (destinationType.name()) {
case "ENDER_CHEST":
OfflinePlayer op = Bukkit.getOfflinePlayer(hopper.getPlacedBy());
@@ -209,24 +310,6 @@ public class HopTask extends BukkitRunnable {
if (op.isOnline())
destinationInventory = op.getPlayer().getEnderChest();
break;
- case "BLACK_SHULKER_BOX":
- case "BLUE_SHULKER_BOX":
- case "BROWN_SHULKER_BOX":
- case "CYAN_SHULKER_BOX":
- case "GRAY_SHULKER_BOX":
- case "GREEN_SHULKER_BOX":
- case "LIGHT_BLUE_SHULKER_BOX":
- case "LIGHT_GRAY_SHULKER_BOX":
- case "LIME_SHULKER_BOX":
- case "MAGENTA_SHULKER_BOX":
- case "ORANGE_SHULKER_BOX":
- case "PINK_SHULKER_BOX":
- case "PURPLE_SHULKER_BOX":
- case "RED_SHULKER_BOX":
- case "SHULKER_BOX":
- case "WHITE_SHULKER_BOX":
- case "YELLOW_SHULKER_BOX":
- return false;
case "BREWING_STAND": {
BrewerInventory brewerInventory = (BrewerInventory) destinationInventory;
@@ -264,6 +347,7 @@ public class HopTask extends BukkitRunnable {
this.debt(item, amountToMove, currentHolder);
return true;
}
+ case "SMOKER":
case "BLAST_FURNACE":
case "BURNING_FURNACE":
case "FURNACE": {
@@ -298,7 +382,8 @@ public class HopTask extends BukkitRunnable {
// Prevent item from being moved again during this cycle.
// Only block if the hopper being transfered into doesn't already contain the same item.
- if (!destinationInventory.contains(itemToMove))
+ // Don't blacklist if the block is transfering items into itself
+ if (!destinationInventory.contains(itemToMove) && currentDestination != currentHolder && currentHolder instanceof Hopper)
this.blacklist.put(currentDestination, itemToMove);
// Move item to destination.
@@ -307,8 +392,9 @@ public class HopTask extends BukkitRunnable {
// Debt hopper
this.debt(item, amountToMove, currentHolder);
- // Update comparators for destination hopper.
- updateAdjacentComparators(((BlockState) currentDestination).getLocation());
+ // Update comparators for destination block.
+ if (currentDestination instanceof BlockState)
+ updateAdjacentComparators(((BlockState) currentDestination).getLocation());
// Update comparators for current hopper.
updateAdjacentComparators(hopper.getLocation());
@@ -394,4 +480,74 @@ public class HopTask extends BukkitRunnable {
return false;
}
+ /**
+ * Gets a set of slots that can be pulled from based on the given material
+ * @param material The material to get pullable slots for
+ * @return A set of valid pullable slots
+ */
+ private int[] getPullableSlots(InventoryHolder inventoryHolder, Material material) {
+ if (material.name().contains("SHULKER_BOX"))
+ return IntStream.rangeClosed(0, 26).toArray();
+
+ switch (material.name()) {
+ case "BARREL":
+ case "CHEST":
+ case "TRAPPED_CHEST":
+ if (inventoryHolder.getInventory() instanceof DoubleChestInventory)
+ return IntStream.rangeClosed(0, 53).toArray();
+ return IntStream.rangeClosed(0, 26).toArray();
+ case "BREWING_STAND":
+ return IntStream.rangeClosed(0, 2).toArray();
+ case "HOPPER":
+ return IntStream.rangeClosed(0, 4).toArray();
+ case "DISPENSER":
+ case "DROPPER":
+ return IntStream.rangeClosed(0, 8).toArray();
+ case "SMOKER":
+ case "BLAST_FURNACE":
+ case "BURNING_FURNACE":
+ case "FURNACE":
+ return IntStream.of(2).toArray();
+ default:
+ return IntStream.empty().toArray();
+ }
+ }
+
+ /**
+ * Gets a random InventoryHolder from a collection of entities
+ * Only grabs InventoryHolders from StorageMinecarts and HopperMinecarts
+ * @param entities The collection of entities
+ * @return A random InventoryHolder if one exists, otherwise null
+ */
+ private InventoryHolder getRandomInventoryHolderFromEntities(Collection entities) {
+ List inventoryHolders = new ArrayList<>();
+ entities.stream().filter(e -> e.getType() == EntityType.MINECART_CHEST || e.getType() == EntityType.MINECART_HOPPER)
+ .forEach(e -> inventoryHolders.add((InventoryHolder) e));
+ if (inventoryHolders.isEmpty())
+ return null;
+ if (inventoryHolders.size() == 1)
+ return inventoryHolders.get(0);
+ return inventoryHolders.get(ThreadLocalRandom.current().nextInt(inventoryHolders.size()));
+ }
+
+ /**
+ * Checks if a given block is an EpicFarming farm item
+ * @param block The block to check
+ * @return true if the block is a farm item, otherwise false
+ */
+ private boolean isFarmItem(Block block) {
+ return EpicHoppers.getInstance().isEpicFarming() && com.songoda.epicfarming.EpicFarmingPlugin.getInstance().getFarmManager().getFarm(block) != null;
+ }
+
+ /**
+ * Gets an EpicFarming block as an InventoryHolder
+ * Needed because EpicFarming doesn't natively support having an InventoryHolder for the farm item
+ *
+ * @param block The block to effectively attach an InventoryHolder to
+ * @return An InventoryHolder wrapping the EpicFarming inventory
+ */
+ private InventoryHolder getEpicFarmingItemWrapped(Block block) {
+ return () -> com.songoda.epicfarming.EpicFarmingPlugin.getInstance().getFarmManager().getFarm(block).getInventory();
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/songoda/epichoppers/utils/HopperDirection.java b/src/main/java/com/songoda/epichoppers/utils/HopperDirection.java
index 374015c..61849e8 100644
--- a/src/main/java/com/songoda/epichoppers/utils/HopperDirection.java
+++ b/src/main/java/com/songoda/epichoppers/utils/HopperDirection.java
@@ -35,7 +35,7 @@ public enum HopperDirection {
}
public Location getLocation(Location location) {
- return location.add(getX(), getY(), getZ());
+ return location.clone().add(getX(), getY(), getZ());
}
public int getX() {
diff --git a/src/main/java/com/songoda/epichoppers/utils/MySQLDatabase.java b/src/main/java/com/songoda/epichoppers/utils/MySQLDatabase.java
index fa70851..e8bf34f 100644
--- a/src/main/java/com/songoda/epichoppers/utils/MySQLDatabase.java
+++ b/src/main/java/com/songoda/epichoppers/utils/MySQLDatabase.java
@@ -1,6 +1,7 @@
package com.songoda.epichoppers.utils;
import com.songoda.epichoppers.EpicHoppers;
+import org.bukkit.Bukkit;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -33,8 +34,8 @@ public class MySQLDatabase {
"\t`whitelist` TEXT NULL,\n" +
"\t`blacklist` TEXT NULL,\n" +
"\t`void` TEXT NULL,\n" +
- "\t`black` TEXT NULL\n" +
- "\t`autobreak` TEXT NULL\n" +
+ "\t`black` TEXT NULL,\n" +
+ "\t`autobreak` TINYINT(1) NULL\n" +
")");
connection.createStatement().execute("CREATE TABLE IF NOT EXISTS `" + instance.getConfig().getString("Database.Prefix") + "boosts` (\n" +
@@ -44,7 +45,8 @@ public class MySQLDatabase {
")");
} catch (ClassNotFoundException | SQLException e) {
- System.out.println("Database connection failed.");
+ Bukkit.getLogger().severe("Database connection failed.");
+ Bukkit.getLogger().severe(e.getMessage());
}
}
diff --git a/src/main/java/com/songoda/epichoppers/utils/Serializers.java b/src/main/java/com/songoda/epichoppers/utils/Serializers.java
index 97bf6fe..7f3aca4 100644
--- a/src/main/java/com/songoda/epichoppers/utils/Serializers.java
+++ b/src/main/java/com/songoda/epichoppers/utils/Serializers.java
@@ -36,7 +36,7 @@ public class Serializers {
public static ItemStack deserialize(String serializedItem) {
String[] strings = serializedItem.split(" ");
- Map enchants = new HashMap();
+ Map enchants = new HashMap<>();
String[] args;
ItemStack item = new ItemStack(Material.AIR);
for (String str : strings) {
@@ -53,21 +53,22 @@ public class Serializers {
}
for (String str : strings) {
args = str.split(":", 2);
+ Bukkit.broadcastMessage(Arrays.toString(args));
if (isNumber(args[0])) item.setAmount(Integer.parseInt(args[0]));
if (args.length == 1) continue;
- if (args[0].equalsIgnoreCase("name:")) {
+ if (args[0].equalsIgnoreCase("name")) {
setName(item, ChatColor.translateAlternateColorCodes('&', args[1]));
continue;
}
- if (args[0].equalsIgnoreCase("lore:")) {
+ if (args[0].equalsIgnoreCase("lore")) {
setLore(item, ChatColor.translateAlternateColorCodes('&', args[1]));
continue;
}
- if (args[0].equalsIgnoreCase("rgb:")) {
+ if (args[0].equalsIgnoreCase("rgb")) {
setArmorColor(item, args[1]);
continue;
}
- if (args[0].equalsIgnoreCase("owner:")) {
+ if (args[0].equalsIgnoreCase("owner")) {
setOwner(item, args[1]);
continue;
}
@@ -102,7 +103,7 @@ public class Serializers {
}
private static void setName(ItemStack item, String name) {
- name = name.replace("_", " ");
+ name = name.replace("_", " ").replace('&', ChatColor.COLOR_CHAR);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(name);
item.setItemMeta(meta);
@@ -120,7 +121,7 @@ public class Serializers {
}
private static void setLore(ItemStack item, String lore) {
- lore = lore.replace("_", " ");
+ lore = lore.replace("_", " ").replace('&', ChatColor.COLOR_CHAR);
ItemMeta meta = item.getItemMeta();
meta.setLore(Arrays.asList(lore.split("\\|")));
item.setItemMeta(meta);
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 cf4eb76..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"), "" +
+ 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"
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 848d6ff..5afb935 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,7 +1,7 @@
name: EpicHoppers
description: EpicHoppers
main: com.songoda.epichoppers.EpicHoppers
-softdepend: [LiquidTanks, WildStacker, Towny, RedProtect, Kingdoms, PlotsSquared, GriefPrevention, USkyBlock, ASkyBlock, WorldGuard, Factions, Vault]
+softdepend: [LiquidTanks, WildStacker, Towny, RedProtect, Kingdoms, PlotsSquared, GriefPrevention, USkyBlock, ASkyBlock, WorldGuard, Factions, Vault, EpicFarming]
version: maven-version-number
author: Songoda
api-version: 1.13