diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_github_cryptomorin_XSeries_7_2_1.xml b/.idea/libraries/Maven__com_github_cryptomorin_XSeries_7_2_1.xml new file mode 100644 index 0000000..4ad4b7b --- /dev/null +++ b/.idea/libraries/Maven__com_github_cryptomorin_XSeries_7_2_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_google_code_gson_gson_2_8_6.xml b/.idea/libraries/Maven__com_google_code_gson_gson_2_8_6.xml new file mode 100644 index 0000000..82a9f20 --- /dev/null +++ b/.idea/libraries/Maven__com_google_code_gson_gson_2_8_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_google_guava_guava_17_0.xml b/.idea/libraries/Maven__com_google_guava_guava_17_0.xml new file mode 100644 index 0000000..2a9069c --- /dev/null +++ b/.idea/libraries/Maven__com_google_guava_guava_17_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__javax_persistence_persistence_api_1_0.xml b/.idea/libraries/Maven__javax_persistence_persistence_api_1_0.xml new file mode 100644 index 0000000..e60370e --- /dev/null +++ b/.idea/libraries/Maven__javax_persistence_persistence_api_1_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__net_md_5_bungeecord_chat_1_8_SNAPSHOT.xml b/.idea/libraries/Maven__net_md_5_bungeecord_chat_1_8_SNAPSHOT.xml new file mode 100644 index 0000000..2e39f35 --- /dev/null +++ b/.idea/libraries/Maven__net_md_5_bungeecord_chat_1_8_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_avaje_ebean_2_8_1.xml b/.idea/libraries/Maven__org_avaje_ebean_2_8_1.xml new file mode 100644 index 0000000..91f161a --- /dev/null +++ b/.idea/libraries/Maven__org_avaje_ebean_2_8_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_jetbrains_annotations_20_1_0.xml b/.idea/libraries/Maven__org_jetbrains_annotations_20_1_0.xml new file mode 100644 index 0000000..de125e3 --- /dev/null +++ b/.idea/libraries/Maven__org_jetbrains_annotations_20_1_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_spigotmc_spigot_api_1_8_8_R0_1_SNAPSHOT.xml b/.idea/libraries/Maven__org_spigotmc_spigot_api_1_8_8_R0_1_SNAPSHOT.xml new file mode 100644 index 0000000..15cce87 --- /dev/null +++ b/.idea/libraries/Maven__org_spigotmc_spigot_api_1_8_8_R0_1_SNAPSHOT.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_15.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_15.xml new file mode 100644 index 0000000..02d9152 --- /dev/null +++ b/.idea/libraries/Maven__org_yaml_snakeyaml_1_15.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 432bc90..5d5076f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.epconsortium CryptoMarket - 1.1.0 + 2.0.0 CryptoMarket A plugin that brings the cryptocoins market experience to your server! https://www.spigotmc.org/resources/cryptomarket.69031/ @@ -106,11 +106,4 @@ - - - bintray-roinujnosde-bukkit-plugins - roinujnosde-bukkit-plugins - https://api.bintray.com/maven/roinujnosde/bukkit-plugins/CryptoMarket/;publish=1 - - diff --git a/src/main/java/net/epconsortium/cryptomarket/CryptoMarket.java b/src/main/java/net/epconsortium/cryptomarket/CryptoMarket.java index b023286..81dda94 100644 --- a/src/main/java/net/epconsortium/cryptomarket/CryptoMarket.java +++ b/src/main/java/net/epconsortium/cryptomarket/CryptoMarket.java @@ -1,22 +1,18 @@ package net.epconsortium.cryptomarket; import net.epconsortium.cryptomarket.commands.CryptoMarketCommand; +import net.epconsortium.cryptomarket.database.dao.InvestorDao; +import net.epconsortium.cryptomarket.finances.Economy; import net.epconsortium.cryptomarket.finances.ExchangeRates; +import net.epconsortium.cryptomarket.listeners.PlayerListeners; +import net.epconsortium.cryptomarket.task.SaveInvestorsTask; import net.epconsortium.cryptomarket.task.UpdateExchangeRatesTask; -import net.epconsortium.cryptomarket.ui.MenuListener; -import net.milkbowl.vault.economy.Economy; -import org.bukkit.Bukkit; +import net.epconsortium.cryptomarket.task.UpdateRichersListTask; +import net.epconsortium.cryptomarket.ui.InventoryController; import org.bukkit.command.PluginCommand; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.logging.Level; -import net.epconsortium.cryptomarket.database.dao.InvestorDao; -import net.epconsortium.cryptomarket.task.SaveInvestorsTask; -import net.epconsortium.cryptomarket.ui.CalendarListener; -import net.epconsortium.cryptomarket.ui.RankingListener; /** * Main class of the plugin @@ -26,12 +22,8 @@ public class CryptoMarket extends JavaPlugin { private static CryptoMarket cm; - - private Economy econ = null; - private SaveInvestorsTask saveInvestors; - private UpdateExchangeRatesTask updateRates; - private static boolean debug; + private net.milkbowl.vault.economy.Economy econ = null; @Override public void onEnable() { @@ -41,9 +33,8 @@ public void onEnable() { // Eventos PluginManager pluginManager = getServer().getPluginManager(); - pluginManager.registerEvents(new MenuListener(this), this); - pluginManager.registerEvents(new CalendarListener(this), this); - pluginManager.registerEvents(new RankingListener(this), this); + pluginManager.registerEvents(InventoryController.getInstance(), this); + pluginManager.registerEvents(new PlayerListeners(this), this); //Comandos PluginCommand command = getCommand("cryptomarket"); @@ -60,39 +51,28 @@ public void onEnable() { debug = getConfig().getBoolean("debug", false); - InvestorDao.configureDatabase(this, (success) -> { - new BukkitRunnable() { - - @Override - public void run() { - if (!success) { - getServer().getPluginManager().disablePlugin(CryptoMarket.this); - } else { - getServer().getConsoleSender().sendMessage( - "[CryptoMarket] Database configured successfuly!"); - - ExchangeRates rates = new ExchangeRates(CryptoMarket.this); - rates.updateAll(); - - updateRates = new UpdateExchangeRatesTask(rates); - updateRates.start(CryptoMarket.this); - - saveInvestors = new SaveInvestorsTask(CryptoMarket.this); - saveInvestors.start(); - } - } - }.runTask(this); + getInvestorDao().configureDatabase(this, (success) -> { + if (!success) { + getServer().getPluginManager().disablePlugin(this); + } else { + getLogger().info("Database configured successfuly!"); + getExchangeRates().updateAll(); + startTasks(); + } }); } + private void startTasks() { + new UpdateExchangeRatesTask(this).start(); + new SaveInvestorsTask(this).start(); + new UpdateRichersListTask(this).start(); + } + @Override public void onDisable() { - if (saveInvestors == null || updateRates == null) return; - - new InvestorDao(this).saveAll(); - saveInvestors.cancel(); - updateRates.cancel(); + getServer().getScheduler().cancelTasks(this); + getInvestorDao().saveAll(); } /** @@ -102,7 +82,7 @@ public void onDisable() { */ public static void debug(String message) { if (debug) { - Bukkit.getServer().getLogger().log(Level.INFO, "[CryptoMarket] {0}", message); + getInstance().getLogger().info(message); } } @@ -112,7 +92,7 @@ public static void debug(String message) { * @param message message */ public static void warn(String message) { - Bukkit.getServer().getLogger().log(Level.WARNING, "[CryptoMarket] {0}", message); + getInstance().getLogger().warning(message); } /** @@ -124,8 +104,8 @@ private boolean setupEconomy() { if (getServer().getPluginManager().getPlugin("Vault") == null) { return false; } - RegisteredServiceProvider rsp = getServer() - .getServicesManager().getRegistration(Economy.class); + RegisteredServiceProvider rsp = getServer() + .getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class); if (rsp == null) { return false; } @@ -133,21 +113,33 @@ private boolean setupEconomy() { return econ != null; } + public InvestorDao getInvestorDao() { + return InvestorDao.getInstance(this); + } + + public ExchangeRates getExchangeRates() { + return ExchangeRates.getInstance(this); + } + /** * Returns Vault's Economy * * @return economy */ - public Economy getEconomy() { + public net.milkbowl.vault.economy.Economy getVaultEconomy() { return econ; } + public Economy getEconomy() { + return Economy.getInstance(this); + } + /** * Returns the instance of CryptoMarket * * @return the instance */ - public static CryptoMarket getCryptoMarket() { + public static CryptoMarket getInstance() { return cm; } } diff --git a/src/main/java/net/epconsortium/cryptomarket/commands/CryptoMarketCommand.java b/src/main/java/net/epconsortium/cryptomarket/commands/CryptoMarketCommand.java index d5b9caf..bfb9c66 100644 --- a/src/main/java/net/epconsortium/cryptomarket/commands/CryptoMarketCommand.java +++ b/src/main/java/net/epconsortium/cryptomarket/commands/CryptoMarketCommand.java @@ -2,10 +2,11 @@ import java.math.BigDecimal; import net.epconsortium.cryptomarket.CryptoMarket; -import net.epconsortium.cryptomarket.database.dao.InvestorDao; +import net.epconsortium.cryptomarket.database.dao.Investor; import net.epconsortium.cryptomarket.finances.ExchangeRate; import net.epconsortium.cryptomarket.finances.ExchangeRates; -import net.epconsortium.cryptomarket.ui.Menu; +import net.epconsortium.cryptomarket.ui.InventoryDrawer; +import net.epconsortium.cryptomarket.ui.frames.MenuFrame; import net.epconsortium.cryptomarket.util.Configuration; import net.epconsortium.cryptomarket.util.Formatter; import org.bukkit.command.Command; @@ -67,7 +68,11 @@ public boolean onCommand(CommandSender commandSender, Command command, } } else { if (player.hasPermission("cryptomarket.menu")) { - new Menu(plugin, player).open(); + if (plugin.getInvestorDao().getInvestor(player) == null) { + player.sendMessage(config.getMessageErrorConnectingToDatabase()); + return true; + } + InventoryDrawer.getInstance().open(new MenuFrame(null, player)); } else { player.sendMessage(config.getMessageErrorNoPermission()); } @@ -87,16 +92,14 @@ public boolean onCommand(CommandSender commandSender, Command command, */ private boolean processUpdateCommand(Player player) { if (player.hasPermission("cryptomarket.update")) { - if (ExchangeRates.errorOcurred()) { - ExchangeRates rates = new ExchangeRates(plugin); + if (ExchangeRates.errorOccurred()) { + ExchangeRates rates = plugin.getExchangeRates(); rates.updateAll(); String mensagem = config.getMessageUpdatingContent(); - mensagem = MessageFormat.format(mensagem, - rates.getMinutesToUpdate()); + mensagem = MessageFormat.format(mensagem, rates.getMinutesToUpdate()); player.sendMessage(mensagem); } else { - player.sendMessage( - config.getMessageContentAlreadyUptodate()); + player.sendMessage(config.getMessageContentAlreadyUptodate()); } } else { player.sendMessage(config.getMessageErrorNoPermission()); @@ -112,16 +115,14 @@ private boolean processUpdateCommand(Player player) { */ private boolean processTodayCommand(Player player) { if (player.hasPermission("cryptomarket.today")) { - ExchangeRate er = new ExchangeRates(plugin).getExchangeRate( - LocalDate.now()); + ExchangeRate er = plugin.getExchangeRates().getExchangeRate(LocalDate.now()); if (er == null) { player.sendMessage(config.getMessageCommandOutdatedData()); return true; } player.sendMessage(config.getMessageCurrentExchangeRate()); for (String coin : config.getCoins()) { - player.sendMessage(MessageFormat.format( - config.getMessageCurrentExchangeRatePerCoin(), coin, + player.sendMessage(MessageFormat.format(config.getMessageCurrentExchangeRatePerCoin(), coin, Formatter.formatCryptocoin(er.getCoinValue(coin)))); } } else { @@ -161,29 +162,21 @@ public List onTabComplete(CommandSender commandSender, */ private boolean processBalanceCommand(Player player) { if (player.hasPermission("cryptomarket.balance")) { - new InvestorDao(plugin).getInvestor(player, (investor) -> { - new BukkitRunnable() { - @Override - public void run() { - if (!player.isOnline()) { - return; - } - if (investor == null) { - player.sendMessage(config - .getMessageErrorConnectingToDatabase()); - return; - } - player.sendMessage(config.getMessageBalance()); - config.getCoins().forEach((coin) -> { - player.sendMessage(MessageFormat.format( - config.getMessageBalancePerCoin(), coin, - Formatter.formatCryptocoin(investor - .getBalance(coin).getValue()))); - }); - } - }.runTask(plugin); + Investor investor = plugin.getInvestorDao().getInvestor(player); + if (!player.isOnline()) { + return true; + } + if (investor == null) { + player.sendMessage(config.getMessageErrorConnectingToDatabase()); + return true; + } + player.sendMessage(config.getMessageBalance()); + config.getCoins().forEach((coin) -> { + player.sendMessage(MessageFormat.format(config.getMessageBalancePerCoin(), coin, + Formatter.formatCryptocoin(investor.getBalance(coin).getValue()))); }); + } else { player.sendMessage(config.getMessageErrorNoPermission()); } @@ -202,7 +195,7 @@ private boolean processSaveCommand(Player player) { new BukkitRunnable() { @Override public void run() { - new InvestorDao(plugin).saveAll(); + plugin.getInvestorDao().saveAll(); } }.runTaskAsynchronously(plugin); } else { @@ -244,23 +237,15 @@ private boolean processGiveCommand(Player player, String[] args) { player.sendMessage(config.getMessageErrorInvalidCoin()); return false; } - new InvestorDao(plugin).getInvestor(target, (investor) -> { - new BukkitRunnable() { - @Override - public void run() { - if (investor == null) { - player.sendMessage(config - .getMessageErrorConnectingToDatabase()); - return; - } - Economy economy = new Economy(plugin, coin); - economy.deposit(investor, amount); - player.sendMessage(MessageFormat.format( - config.getMessagePlayerBalanceUpdated(), - target.getName())); - } - }.runTask(plugin); - }); + Investor investor = plugin.getInvestorDao().getInvestor(target); + if (investor == null) { + player.sendMessage(config.getMessageErrorConnectingToDatabase()); + return true; + } + plugin.getEconomy().deposit(coin, investor, amount); + player.sendMessage(MessageFormat.format(config.getMessagePlayerBalanceUpdated(), target.getName())); + + } else { player.sendMessage(config.getMessageErrorNoPermission()); } @@ -272,7 +257,7 @@ public void run() { * Process the take command * * @param player player - * @param args args + * @param args args * @return true if the syntax is ok */ private boolean processTakeCommand(Player player, String[] args) { @@ -301,28 +286,19 @@ private boolean processTakeCommand(Player player, String[] args) { player.sendMessage(config.getMessageErrorInvalidCoin()); return false; } - new InvestorDao(plugin).getInvestor(target, (investor) -> { - new BukkitRunnable() { - @Override - public void run() { - if (investor == null) { - player.sendMessage(config - .getMessageErrorConnectingToDatabase()); - return; - } - Economy economy = new Economy(plugin, coin); - if (economy.has(investor, amount)) { - economy.withdraw(investor, amount); - player.sendMessage(MessageFormat.format( - config.getMessagePlayerBalanceUpdated(), - target.getName())); - } else { - player.sendMessage(config - .getMessageErrorInsufficientBalance()); - } - } - }.runTask(plugin); - }); + Investor investor = plugin.getInvestorDao().getInvestor(target); + + if (investor == null) { + player.sendMessage(config.getMessageErrorConnectingToDatabase()); + return true; + } + Economy economy = plugin.getEconomy(); + if (economy.has(coin, investor, amount)) { + economy.withdraw(coin, investor, amount); + player.sendMessage(MessageFormat.format(config.getMessagePlayerBalanceUpdated(), target.getName())); + } else { + player.sendMessage(config.getMessageErrorInsufficientBalance()); + } } else { player.sendMessage(config.getMessageErrorNoPermission()); } @@ -363,23 +339,13 @@ private boolean processSetCommand(Player player, String[] args) { player.sendMessage(config.getMessageErrorInvalidCoin()); return false; } - new InvestorDao(plugin).getInvestor(target, (investor) -> { - new BukkitRunnable() { - @Override - public void run() { - if (investor == null) { - player.sendMessage(config - .getMessageErrorConnectingToDatabase()); - return; - } - Economy economy = new Economy(plugin, coin); - economy.set(investor, amount); - player.sendMessage(MessageFormat.format( - config.getMessagePlayerBalanceUpdated(), - target.getName())); - } - }.runTask(plugin); - }); + Investor investor = plugin.getInvestorDao().getInvestor(target); + if (investor == null) { + player.sendMessage(config.getMessageErrorConnectingToDatabase()); + return true; + } + plugin.getEconomy().set(coin, investor, amount); + player.sendMessage(MessageFormat.format(config.getMessagePlayerBalanceUpdated(), target.getName())); } else { player.sendMessage(config.getMessageErrorNoPermission()); } diff --git a/src/main/java/net/epconsortium/cryptomarket/conversation/NegotiationConversation.java b/src/main/java/net/epconsortium/cryptomarket/conversation/NegotiationConversation.java index b940b27..409afbb 100644 --- a/src/main/java/net/epconsortium/cryptomarket/conversation/NegotiationConversation.java +++ b/src/main/java/net/epconsortium/cryptomarket/conversation/NegotiationConversation.java @@ -41,22 +41,15 @@ public NegotiationConversation(CryptoMarket plugin, Negotiation negotiation, Pla * Starts the Negotiation Conversation with the Player */ public void start() { - new InvestorDao(plugin).getInvestor(player, (investor) -> { - new BukkitRunnable() { - @Override - public void run() { - if (!player.isOnline()) { - return; - } - if (investor == null) { - player.sendMessage(config. - getMessageErrorConnectingToDatabase()); - return; - } - createConversation(investor).begin(); - } - }.runTask(plugin); - }); + if (!player.isOnline()) { + return; + } + Investor investor = plugin.getInvestorDao().getInvestor(player); + if (investor == null) { + player.sendMessage(config.getMessageErrorConnectingToDatabase()); + return; + } + createConversation(investor).begin(); } /** diff --git a/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/AmountPrompt.java b/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/AmountPrompt.java index 8a8f236..1474514 100644 --- a/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/AmountPrompt.java +++ b/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/AmountPrompt.java @@ -20,10 +20,9 @@ protected Prompt acceptValidatedInput(ConversationContext context, Number number CryptoMarket plugin = (CryptoMarket) context.getPlugin(); Configuration config = new Configuration(plugin); String coin = ((String) context.getSessionData("coin")); - Economy economia = new Economy(plugin, coin); BigDecimal amount = new BigDecimal(number.toString()); - if (economia.convert(amount).doubleValue() < 0) { + if (plugin.getEconomy().convert(coin, amount).doubleValue() < 0) { return new OutdatedDataPrompt(); } context.setSessionData("amount", amount); diff --git a/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/ConfirmationPrompt.java b/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/ConfirmationPrompt.java index 3917172..175af57 100644 --- a/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/ConfirmationPrompt.java +++ b/src/main/java/net/epconsortium/cryptomarket/conversation/prompt/ConfirmationPrompt.java @@ -27,16 +27,14 @@ public ConfirmationPrompt(String yes, String cancel) { } @Override - protected Prompt acceptValidatedInput(ConversationContext context, - String s) { + protected Prompt acceptValidatedInput(ConversationContext context, String s) { if (s.equals(cancel)) { return END_OF_CONVERSATION; } CryptoMarket plugin = (CryptoMarket) context.getPlugin(); String coin = (String) context.getSessionData("coin"); - Economy economy = new Economy(plugin, coin); - + Economy economy = plugin.getEconomy(); Investor investor = (Investor) context.getSessionData("investor"); BigDecimal value = (BigDecimal) context.getSessionData("amount"); @@ -44,12 +42,12 @@ protected Prompt acceptValidatedInput(ConversationContext context, Negotiation negotiation = getNegotiation(context); switch (negotiation) { case PURCHASE: - if (!economy.buy(investor, value)) { + if (!economy.buy(coin, investor, value)) { return new ErrorPrompt(); } break; case SELL: - if (!economy.sell(investor, value)) { + if (!economy.sell(coin, investor, value)) { return new ErrorPrompt(); } break; @@ -62,7 +60,6 @@ protected Prompt acceptValidatedInput(ConversationContext context, public String getPromptText(ConversationContext context) { CryptoMarket plugin = (CryptoMarket) context.getPlugin(); String coin = (String) context.getSessionData("coin"); - Economy economy = new Economy(plugin, coin); Configuration config = new Configuration(plugin); String message = config.getMessageNegotiationConfirmation(); String action = null; @@ -78,10 +75,9 @@ public String getPromptText(ConversationContext context) { } BigDecimal amount = ((BigDecimal) context.getSessionData("amount")); - BigDecimal value = economy.convert(amount); + BigDecimal value = plugin.getEconomy().convert(coin, amount); - return MessageFormat.format(message, action, amount, coin, value) + - " " + formatFixedSet(); + return MessageFormat.format(message, action, amount, coin, value) + " " + formatFixedSet(); } private Negotiation getNegotiation(ConversationContext context) { diff --git a/src/main/java/net/epconsortium/cryptomarket/database/dao/Investor.java b/src/main/java/net/epconsortium/cryptomarket/database/dao/Investor.java index a114d9b..c5242fa 100644 --- a/src/main/java/net/epconsortium/cryptomarket/database/dao/Investor.java +++ b/src/main/java/net/epconsortium/cryptomarket/database/dao/Investor.java @@ -1,12 +1,12 @@ package net.epconsortium.cryptomarket.database.dao; +import net.epconsortium.cryptomarket.finances.ExchangeRate; import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; +import java.util.*; /** * Class representing an Investor @@ -26,7 +26,7 @@ public class Investor { /** * Returns the OfflinePlayer linked to the Investor * - * @return offlineplayer + * @return the {@link OfflinePlayer} */ public OfflinePlayer getPlayer() { return player; @@ -48,6 +48,32 @@ public Balance getBalance(String coin) { return balance; } + /** + * Converts this Investor's balance in cryptocoins to the server's currency + * + * @param rate the {@link ExchangeRate} used to calculate the patrimony + * @return the converted patrimony or -1 if the rate is null + */ + public BigDecimal getConvertedPatrimony(@Nullable ExchangeRate rate) { + if (rate == null) { + return new BigDecimal(-1); + } + BigDecimal patrimony = BigDecimal.ZERO; + for (Map.Entry entry : getBalances().entrySet()) { + patrimony = patrimony.add(rate.getCoinValue(entry.getKey()).multiply(entry.getValue().getValue())); + } + + return patrimony; + } + + public static Comparator comparator(@NotNull ExchangeRate exchangeRate) { + return (o1, o2) -> o1.compareTo(o2, exchangeRate); + } + + public int compareTo(@NotNull Investor other, @NotNull ExchangeRate rate) { + return getConvertedPatrimony(rate).compareTo(other.getConvertedPatrimony(rate)); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -55,12 +81,12 @@ public boolean equals(Object o) { Investor that = (Investor) o; - return player.equals(that.player); + return player.getUniqueId().equals(that.player.getUniqueId()); } @Override public int hashCode() { - return player.hashCode(); + return player.getUniqueId().hashCode(); } /** diff --git a/src/main/java/net/epconsortium/cryptomarket/database/dao/InvestorDao.java b/src/main/java/net/epconsortium/cryptomarket/database/dao/InvestorDao.java index 070b1e4..49f0416 100644 --- a/src/main/java/net/epconsortium/cryptomarket/database/dao/InvestorDao.java +++ b/src/main/java/net/epconsortium/cryptomarket/database/dao/InvestorDao.java @@ -2,17 +2,20 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.database.ConnectionFactory; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.lang.reflect.Type; import java.sql.*; import java.util.*; -import net.epconsortium.cryptomarket.CryptoMarket; +import java.util.concurrent.CopyOnWriteArrayList; + import static net.epconsortium.cryptomarket.CryptoMarket.debug; -import net.epconsortium.cryptomarket.database.ConnectionFactory; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; /** * Class used to manage the Investors @@ -21,190 +24,143 @@ */ public class InvestorDao { - private static final Map INVESTORS_ONLINE = new HashMap<>(); + private static InvestorDao instance; + private static final List ONLINE_INVESTORS = new CopyOnWriteArrayList<>(); + private static ConnectionFactory connectionFactory; private final Gson gson = new Gson(); - private static final Type BALANCES_TYPE = TypeToken.getParameterized( - Map.class, String.class, Balance.class).getType(); + private static final Type BALANCES_TYPE = TypeToken.getParameterized(Map.class, String.class, Balance.class) + .getType(); private final CryptoMarket plugin; - - public InvestorDao(CryptoMarket plugin) { + + private InvestorDao(CryptoMarket plugin) { this.plugin = Objects.requireNonNull(plugin); + connectionFactory = new ConnectionFactory(plugin); + } + + public static InvestorDao getInstance(@NotNull CryptoMarket plugin) { + if (instance == null) { + instance = new InvestorDao(plugin); + } + return instance; } /** * Creates the table if it does not exist - * - * @param plugin - * @param callback */ - public static void configureDatabase(CryptoMarket plugin, - DatabaseConfigurationCallback callback) { + public void configureDatabase(CryptoMarket plugin, DatabaseConfigurationCallback callback) { Objects.requireNonNull(plugin); Objects.requireNonNull(callback); new BukkitRunnable() { @Override public void run() { boolean success; - try (Connection connection = new ConnectionFactory( - plugin).getConnection()) { - connection.createStatement().execute("CREATE TABLE IF NOT" - + " EXISTS investors (uuid VARCHAR(255), " - + "balances TEXT);"); + try (Connection connection = connectionFactory.getConnection()) { + connection.createStatement().execute("CREATE TABLE IF NOT EXISTS investors (uuid VARCHAR(255), balances TEXT);"); success = true; } catch (SQLException ex) { CryptoMarket.warn("Error configuring the database:"); ex.printStackTrace(); success = false; } - callback.onDatabaseConfigured(success); + boolean finalSuccess = success; + Bukkit.getScheduler().runTask(plugin, () -> callback.onDatabaseConfigured(finalSuccess)); } }.runTaskAsynchronously(plugin); } /** - * Saves the Investor data on the database + * Inserts the Investor data into the database * - * @param investor investor to save + * @param investor investor to insert */ - private void save(Investor investor) { - Objects.requireNonNull(investor); - + private void insert(@NotNull Investor investor) { try (Connection connection = new ConnectionFactory(plugin).getConnection()) { PreparedStatement s = connection.prepareStatement("INSERT INTO investors (uuid, balances) VALUES (?,?);"); s.setString(1, investor.getPlayer().getUniqueId().toString()); s.setString(2, gson.toJson(investor.getBalances(), BALANCES_TYPE)); s.execute(); - INVESTORS_ONLINE.put(investor.getUniqueId(), investor); + ONLINE_INVESTORS.add(investor); } catch (SQLException ex) { CryptoMarket.warn("Error saving the Investor to the database: " + investor); ex.printStackTrace(); } } - /** - * Retrieves an Investor from a Player - * - * @param player player - * @param callback callback - */ - public void getInvestor(Player player, InvestorDataCallback callback) { - Objects.requireNonNull(player); - Objects.requireNonNull(callback); - - Investor i = INVESTORS_ONLINE.get(player.getUniqueId()); - if (i != null) { - callback.onInvestorDataReady(i); - return; + public @Nullable Investor getInvestor(@NotNull final OfflinePlayer player) { + for (Investor investor : ONLINE_INVESTORS) { + if (investor.getUniqueId().equals(player.getUniqueId())) { + return investor; + } } - new BukkitRunnable() { - @Override - public void run() { - try (Connection connection = new ConnectionFactory(plugin) - .getConnection()) { - PreparedStatement statement = connection. - prepareStatement("SELECT * FROM investors" - + " WHERE uuid = ?;"); - statement.setString(1, player.getUniqueId().toString()); - ResultSet set = statement.executeQuery(); - Investor investor; - if (set.next()) { - Map balances = gson.fromJson( - set.getString("balances"), BALANCES_TYPE); - - investor = new Investor(player, balances); - debug("Successfully retrieved data from " - + player.getName()); - } else { - debug(player.getName() + " was not an Investor. " - + "Creating data..."); - investor = new Investor(player, new HashMap<>()); - save(investor); - } - INVESTORS_ONLINE.put(investor.getUniqueId(), investor); - callback.onInvestorDataReady(investor); - } catch (SQLException ex) { - CryptoMarket.warn("An error ocurred while retrieving " - + "data from " + player.getName()); - ex.printStackTrace(); - callback.onInvestorDataReady(null); - } + return null; + } + + public void unloadInvestor(@NotNull final OfflinePlayer player) { + ONLINE_INVESTORS.removeIf(i -> i.getUniqueId().equals(player.getUniqueId())); + } + + public void loadInvestor(@NotNull final OfflinePlayer player) { + try (Connection connection = new ConnectionFactory(plugin).getConnection()) { + PreparedStatement statement = connection.prepareStatement("SELECT * FROM investors WHERE uuid = ?;"); + statement.setString(1, player.getUniqueId().toString()); + ResultSet set = statement.executeQuery(); + Investor investor; + if (set.next()) { + Map balances = gson.fromJson(set.getString("balances"), BALANCES_TYPE); + + investor = new Investor(player, balances); + debug("Successfully retrieved data for " + player.getName()); + ONLINE_INVESTORS.add(investor); + } else { + debug(player.getName() + " was not an Investor. Creating data..."); + investor = new Investor(player, new HashMap<>()); + insert(investor); } - }.runTaskAsynchronously(plugin); + } catch (SQLException ex) { + CryptoMarket.warn("An error occurred while retrieving data for " + player.getName()); + ex.printStackTrace(); + } } - /** - * Returns all Investors saved in the database - * - * @param callback callback - */ - public void getInvestors(InvestorsDataCallback callback) { - Objects.requireNonNull(callback); - - new BukkitRunnable() { - @Override - public void run() { - debug("Retrieving investors from the database..."); - try (Connection connection = new ConnectionFactory(plugin) - .getConnection()) { - Statement statement = connection.createStatement(); - ResultSet set = statement.executeQuery("SELECT * FROM " - + "investors;"); - - Set investors = new HashSet<>(); - while (set.next()) { - Map balances = gson.fromJson( - set.getString("balances"), BALANCES_TYPE); - UUID uuid = UUID.fromString(set.getString("uuid")); - OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); - Investor investor = new Investor(player, balances); - if (INVESTORS_ONLINE.containsKey(uuid)) { - investor = INVESTORS_ONLINE.get(uuid); - } - investors.add(investor); - } - callback.onInvestorsDataReady(investors); - } catch (SQLException ex) { - CryptoMarket.warn("Error retrieving all investors " - + "from the database:"); - ex.printStackTrace(); - callback.onInvestorsDataReady(null); + public @Nullable List getInvestors() { + List investors = new ArrayList<>(); + try (Connection connection = new ConnectionFactory(plugin).getConnection()) { + Statement statement = connection.createStatement(); + ResultSet set = statement.executeQuery("SELECT * FROM investors;"); + while (set.next()) { + Map balances = gson.fromJson(set.getString("balances"), BALANCES_TYPE); + UUID uuid = UUID.fromString(set.getString("uuid")); + OfflinePlayer player = Bukkit.getOfflinePlayer(uuid); + Investor investor = getInvestor(player); + if (investor == null) { + investor = new Investor(player, balances); } + investors.add(investor); } - }.runTaskAsynchronously(plugin); + } catch (SQLException ex) { + CryptoMarket.warn("Error retrieving all investors from the database:"); + ex.printStackTrace(); + return null; + } + + return investors; } /** * Saves the last modifications to the database - * */ public void saveAll() { debug("Saving online investors..."); - try (Connection connection = - new ConnectionFactory(plugin).getConnection()) { - try (PreparedStatement ps = connection.prepareStatement( - "UPDATE investors SET balances=? WHERE uuid=?;")) { - Set offline = new HashSet<>(); - for (Map.Entry entry : - INVESTORS_ONLINE.entrySet()) { - Investor investor = entry.getValue(); - ps.setString(1, gson.toJson(investor.getBalances(), - BALANCES_TYPE)); - ps.setString(2, investor.getPlayer().getUniqueId() - .toString()); + try (Connection connection = new ConnectionFactory(plugin).getConnection()) { + try (PreparedStatement ps = connection.prepareStatement("UPDATE investors SET balances=? WHERE uuid=?;")) { + for (Investor investor : ONLINE_INVESTORS) { + ps.setString(1, gson.toJson(investor.getBalances(), BALANCES_TYPE)); + ps.setString(2, investor.getPlayer().getUniqueId().toString()); ps.addBatch(); - - if (!investor.getPlayer().isOnline()) { - debug(investor + " is not online. " - + "Removing from the map..."); - offline.add(entry.getKey()); - } } ps.executeBatch(); - - //Removing the offline investors - INVESTORS_ONLINE.keySet().removeAll(offline); } } catch (SQLException ex) { CryptoMarket.warn("Error saving online investors!"); @@ -212,33 +168,13 @@ public void saveAll() { } } - public static interface DatabaseConfigurationCallback { + public interface DatabaseConfigurationCallback { /** * Called when the database configuration is finished * * @param success true if success */ - public void onDatabaseConfigured(boolean success); - } - - public static interface InvestorsDataCallback { - - /** - * Notifies when the Investors set is ready - * - * @param investors set of all investors, null if an error ocurred - */ - void onInvestorsDataReady(Set investors); - } - - public static interface InvestorDataCallback { - - /** - * Notifies when the Investor object is ready - * - * @param investor the investor, null if an error ocurred - */ - void onInvestorDataReady(Investor investor); + void onDatabaseConfigured(boolean success); } } diff --git a/src/main/java/net/epconsortium/cryptomarket/finances/Economy.java b/src/main/java/net/epconsortium/cryptomarket/finances/Economy.java index 8a23399..7cd86d8 100644 --- a/src/main/java/net/epconsortium/cryptomarket/finances/Economy.java +++ b/src/main/java/net/epconsortium/cryptomarket/finances/Economy.java @@ -1,10 +1,13 @@ package net.epconsortium.cryptomarket.finances; import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.database.dao.Investor; import net.epconsortium.cryptomarket.util.Configuration; import net.epconsortium.cryptomarket.util.Formatter; +import net.epconsortium.cryptomarket.util.Logger; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.math.BigDecimal; import java.text.MessageFormat; @@ -13,15 +16,12 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import static net.epconsortium.cryptomarket.CryptoMarket.debug; -import net.epconsortium.cryptomarket.database.dao.InvestorDao; -import net.epconsortium.cryptomarket.database.dao.Investor; -import net.epconsortium.cryptomarket.util.Logger; /** * Class used to perform operations like purchase, sell, etc. @@ -31,27 +31,28 @@ */ public class Economy { + private static Economy instance; private final CryptoMarket plugin; - private final net.milkbowl.vault.economy.Economy economy; + private final net.milkbowl.vault.economy.Economy vaultEconomy; private final Configuration config; - private final String coin; private final Logger logger; - private static List richers = new ArrayList<>(); - private static long richersUpdate = -1; - private static double totalInvestments = 0; - private static long totalInvestmentsUpdate = -1; + private List investors = new ArrayList<>(); + private long richersUpdate = -1; + private double totalInvestments = 0; - public Economy(CryptoMarket plugin, String coin) { - this.plugin = Objects.requireNonNull(plugin); + private Economy(@NotNull CryptoMarket plugin) { + this.plugin = plugin; config = new Configuration(plugin); - economy = plugin.getEconomy(); + vaultEconomy = plugin.getVaultEconomy(); logger = new Logger(plugin); + } - if (coin == null) { - coin = "BTC"; + public static Economy getInstance(@NotNull CryptoMarket plugin) { + if (instance == null) { + instance = new Economy(plugin); } - this.coin = coin; + return instance; } /** @@ -63,8 +64,7 @@ public Economy(CryptoMarket plugin, String coin) { * @throws IllegalArgumentException if amount is equal or less than 0 or * investor does not have the amount */ - public void withdraw(Investor investor, BigDecimal amount) - throws IllegalArgumentException { + public void withdraw(String coin, Investor investor, BigDecimal amount) throws IllegalArgumentException { Objects.requireNonNull(investor); Objects.requireNonNull(amount); @@ -73,13 +73,13 @@ public void withdraw(Investor investor, BigDecimal amount) + "than 0"); } BigDecimal value = investor.getBalance(coin).getValue(); - if (!(has(investor, amount))) { + if (!(has(coin, investor, amount))) { throw new IllegalArgumentException("investor does not have enough " + "balance"); } value = value.subtract(amount); investor.getBalance(coin).setValue(value); - sendNewBalance(investor, value); + sendNewBalance(coin, investor, value); } /** @@ -87,7 +87,7 @@ public void withdraw(Investor investor, BigDecimal amount) * * @param investor investor */ - private void sendNewBalance(Investor investor, BigDecimal newBalance) { + private void sendNewBalance(String coin, Investor investor, BigDecimal newBalance) { Objects.requireNonNull(investor); Objects.requireNonNull(newBalance); @@ -95,8 +95,7 @@ private void sendNewBalance(Investor investor, BigDecimal newBalance) { debug("New balance: " + newBalance); Player player = Bukkit.getPlayer(investor.getPlayer().getUniqueId()); String newBalanceMsg = config.getMessageNewBalance(); - newBalanceMsg = MessageFormat.format(newBalanceMsg, coin, Formatter - .formatCryptocoin(newBalance)); + newBalanceMsg = MessageFormat.format(newBalanceMsg, coin, Formatter.formatCryptocoin(newBalance)); if (player != null) { player.sendMessage(newBalanceMsg); } else { @@ -112,7 +111,7 @@ private void sendNewBalance(Investor investor, BigDecimal newBalance) { * @param amount new balance * @throws IllegalArgumentException if amount is negative or equal to 0 */ - public void set(Investor investor, BigDecimal amount) { + public void set(String coin, Investor investor, BigDecimal amount) { Objects.requireNonNull(investor); Objects.requireNonNull(amount); @@ -121,7 +120,7 @@ public void set(Investor investor, BigDecimal amount) { } investor.getBalance(coin).setValue(amount); - sendNewBalance(investor, amount); + sendNewBalance(coin, investor, amount); } /** @@ -132,7 +131,7 @@ public void set(Investor investor, BigDecimal amount) { * @param amount amount to deposit * @throws IllegalArgumentException if amount is negative or equal to 0 */ - public void deposit(Investor investor, BigDecimal amount) + public void deposit(String coin, Investor investor, BigDecimal amount) throws IllegalArgumentException { Objects.requireNonNull(investor); Objects.requireNonNull(amount); @@ -144,9 +143,8 @@ public void deposit(Investor investor, BigDecimal amount) BigDecimal value = investor.getBalance(coin).getValue(); value = value.add(amount); investor.getBalance(coin).setValue(value); - debug("Processing deposit of " + amount + " " + coin + ". New balance:" - + " " + value); - sendNewBalance(investor, value); + debug("Processing deposit of " + amount + " " + coin + ". New balance: " + value); + sendNewBalance(coin, investor, value); } /** @@ -157,22 +155,20 @@ public void deposit(Investor investor, BigDecimal amount) * @param amount amount to buy * @return true if success */ - public boolean buy(Investor investor, BigDecimal amount) { + public boolean buy(String coin, Investor investor, BigDecimal amount) { Objects.requireNonNull(investor); Objects.requireNonNull(amount); debug("Processing the purchase of crypto for " + investor); debug("Amount: " + amount); - double toPay = convert(amount).doubleValue(); + double toPay = convert(coin, amount).doubleValue(); debug("To pay: " + toPay); - if (economy.has(investor.getPlayer(), toPay)) { + if (vaultEconomy.has(investor.getPlayer(), toPay)) { if (amount.doubleValue() > 0) { - economy.withdrawPlayer(investor.getPlayer(), toPay); + vaultEconomy.withdrawPlayer(investor.getPlayer(), toPay); //deposit(investor, amount); - investor.getBalance(coin).increase(amount, - new BigDecimal(toPay)); - logger.log(investor, Negotiation.PURCHASE, amount, coin, - toPay); + investor.getBalance(coin).increase(amount, new BigDecimal(toPay)); + logger.log(investor, Negotiation.PURCHASE, amount, coin, toPay); return true; } else { debug("amount is less than 0"); @@ -189,23 +185,22 @@ public boolean buy(Investor investor, BigDecimal amount) { * * @param investor investor * @param amount amount to sell - * @return true if sucess + * @return true if success */ - public boolean sell(Investor investor, BigDecimal amount) { + public boolean sell(String coin, Investor investor, BigDecimal amount) { Objects.requireNonNull(investor); Objects.requireNonNull(amount); debug("Processing the sell of crypto for " + investor); debug("Amount: " + amount); - double toReceive = convert(amount).doubleValue(); + double toReceive = convert(coin, amount).doubleValue(); debug("To receive: " + toReceive); if (amount.doubleValue() > 0) { - if (has(investor, amount)) { - economy.depositPlayer(investor.getPlayer(), toReceive); + if (has(coin, investor, amount)) { + vaultEconomy.depositPlayer(investor.getPlayer(), toReceive); //withdraw(investor, amount); - investor.getBalance(coin).decrease(amount, - new BigDecimal(toReceive)); + investor.getBalance(coin).decrease(amount, new BigDecimal(toReceive)); logger.log(investor, Negotiation.SELL, amount, coin, toReceive); return true; } @@ -220,11 +215,10 @@ public boolean sell(Investor investor, BigDecimal amount) { * @param amount amount to convert * @return value in the server currency */ - public BigDecimal convert(BigDecimal amount) { + public BigDecimal convert(String coin, BigDecimal amount) { Objects.requireNonNull(amount); - ExchangeRate er = new ExchangeRates(plugin).getExchangeRate( - LocalDate.now()); + ExchangeRate er = plugin.getExchangeRates().getExchangeRate(LocalDate.now()); if (er == null) { er = new ExchangeRate(); } @@ -240,12 +234,11 @@ public BigDecimal convert(BigDecimal amount) { * @param amount amount * @return true if success */ - public boolean transfer(Investor debited, Investor favored, - BigDecimal amount) { + public boolean transfer(String coin, Investor debited, Investor favored, BigDecimal amount) { if (!(amount.doubleValue() <= 0)) { - if (has(debited, amount)) { - withdraw(debited, amount); - deposit(favored, amount); + if (has(coin, debited, amount)) { + withdraw(coin, debited, amount); + deposit(coin, favored, amount); return true; } } @@ -259,71 +252,20 @@ public boolean transfer(Investor debited, Investor favored, * @param amount amount * @return true if he does */ - public boolean has(Investor investor, BigDecimal amount) { + public boolean has(String coin, Investor investor, BigDecimal amount) { Objects.requireNonNull(investor); Objects.requireNonNull(amount); - return investor.getBalance(coin).getValue().doubleValue() - >= amount.doubleValue(); - } - - /** - * Returns the total investments of the Investor converted to the server - * currency - * - * @param investor investor - * @return patrimony - */ - @SuppressWarnings("LocalVariableHidesMemberVariable") - public BigDecimal getConvertedPatrimony(Investor investor) { - Objects.requireNonNull(investor); - - BigDecimal patrimony = new BigDecimal(0); - for (String coin : investor.getBalances().keySet()) { - patrimony = patrimony.add(new Economy(plugin, coin) - .convert(investor.getBalance(coin).getValue())); - } - - return patrimony; + return investor.getBalance(coin).getValue().doubleValue() >= amount.doubleValue(); } /** * Returns the total balance of cryptocoins on the server converted to the * server coin * - * @param callback callback */ - public void getTotalInvestments(InvestmentsCallback callback) { - Objects.requireNonNull(callback); - - if (totalInvestmentsUpdate == -1 || System.currentTimeMillis() - > (totalInvestmentsUpdate + config - .getIntervalRichersUpdateInMillis())) { - new InvestorDao(plugin).getInvestors((investors) -> { - updateTotalInvestments(investors); - callback.onTotalInvestmentsReady(totalInvestments); - }); - } else { - callback.onTotalInvestmentsReady(totalInvestments); - } - } - - /** - * Updates the total balance of cryptocoins and its last update time - * - * @param investors investors to calculate, can be null - */ - private void updateTotalInvestments(Set investors) { - if (investors != null) { - totalInvestments = investors - .stream() - .map(this::getConvertedPatrimony) - .mapToDouble(BigDecimal::doubleValue) - .sum(); - } else { - totalInvestments = -1; - } - totalInvestmentsUpdate = System.currentTimeMillis(); + public double getTotalInvestments() { + return totalInvestments; } /** @@ -332,80 +274,52 @@ private void updateTotalInvestments(Set investors) { * list in case the update interval has not passed yet... * * @param max max number of investors - * @param callback callback - * @throws IllegalArgumentException if max is equal or less than 0 + * @throws IllegalArgumentException if max is negative + * @return the list of richest investors or empty if an error occurred */ - public void getRichestInvestors(final int max, - RichestInvestorsCallback callback) throws IllegalArgumentException { - Objects.requireNonNull(callback); - - if (max < 1) { - throw new IllegalArgumentException("max cannot be equal or less " - + "than 0"); + public @NotNull List getTopInvestors(int max) throws IllegalArgumentException { + if (max < 0) { + throw new IllegalArgumentException("max cannot be negative"); } - //Checking if the update interval has passed or not - if (richersUpdate == -1 - || (System.currentTimeMillis() - config - .getIntervalRichersUpdateInMillis()) - >= richersUpdate) { - - //Getting all investors - new InvestorDao(plugin).getInvestors((investors) -> { - updateTotalInvestments(investors); - - if (investors == null) { - callback.onRichestInvestorsDataReady(null); - debug("Economy: investors list returned null"); - return; - } - Economy eco = new Economy(plugin, ""); - debug("Economy: investors list empty? " + investors.isEmpty()); - richers = investors - .stream() - .sorted((i1, i2) -> (eco.getConvertedPatrimony(i1) - .compareTo(eco.getConvertedPatrimony(i2)) * -1)) - .limit(max).collect(Collectors.toList()); - - richersUpdate = System.currentTimeMillis(); - - debug("Richers updated"); - callback.onRichestInvestorsDataReady(richers); - }); - } else { - debug("The interval has not passed," - + " the previous list is going to be returned."); - //todo: isto deveria levar em consideração o parâmetro max - callback.onRichestInvestorsDataReady(richers); + if (max == 0) { + max = investors.size(); + } + + ExchangeRate rate = plugin.getExchangeRates().getExchangeRate(LocalDate.now()); + if (rate == null) { + return Collections.emptyList(); } + return investors.stream().sorted(Investor.comparator(rate)).limit(max).collect(Collectors.toList()); } /** - * Returns the time of the last update of the Richers list - * - * @return the last update + * @return the top 10 richest investors */ - public static LocalDateTime getRichersLastUpdate() { - return LocalDateTime.ofInstant(Instant.ofEpochMilli(richersUpdate), - ZoneId.systemDefault()); + public List getTopInvestors() { + return getTopInvestors(10); } - public static interface InvestmentsCallback { - - /** - * Notifies when the total investments is ready - * - * @param total total investments - */ - void onTotalInvestmentsReady(double total); + public void setInvestors(@NotNull List investors) { + this.investors = investors; + ExchangeRate rate = plugin.getExchangeRates().getExchangeRate(LocalDate.now()); + if (rate == null) { + totalInvestments = 0; + } else { + totalInvestments = investors.stream().map(i -> i.getConvertedPatrimony(rate)) + .mapToDouble(BigDecimal::doubleValue).sum(); + } } - public static interface RichestInvestorsCallback { + public void setRichersLastUpdate(long timestamp) { + this.richersUpdate = timestamp; + } - /** - * Notifies when the ordered list of richest investors is ready - * - * @param investors richer investors, null if an error ocurred - */ - void onRichestInvestorsDataReady(List investors); + /** + * Returns the time of the last update of the Richers list + * + * @return the last update + */ + public LocalDateTime getRichersLastUpdate() { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(richersUpdate), ZoneId.systemDefault()); } } diff --git a/src/main/java/net/epconsortium/cryptomarket/finances/ExchangeRates.java b/src/main/java/net/epconsortium/cryptomarket/finances/ExchangeRates.java index d2dce45..9e0d253 100644 --- a/src/main/java/net/epconsortium/cryptomarket/finances/ExchangeRates.java +++ b/src/main/java/net/epconsortium/cryptomarket/finances/ExchangeRates.java @@ -6,6 +6,8 @@ import net.epconsortium.cryptomarket.CryptoMarket; import net.epconsortium.cryptomarket.util.Configuration; import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; @@ -25,6 +27,7 @@ */ public class ExchangeRates { + private static ExchangeRates instance; private final CryptoMarket plugin; private final Configuration config; @@ -36,16 +39,23 @@ public class ExchangeRates { private static boolean dailyError; private static boolean currentError; - public ExchangeRates(CryptoMarket plugin) { + private ExchangeRates(CryptoMarket plugin) { this.plugin = Objects.requireNonNull(plugin); config = new Configuration(plugin); } + public static ExchangeRates getInstance(@NotNull CryptoMarket plugin) { + if (instance == null) { + instance = new ExchangeRates(plugin); + } + return instance; + } + /** * Updates all exchange rates and allocates them on memory */ public void updateAll() { - //Reseting the errors + //Resetting the errors setCurrentError(false); setDailyError(false); //Updating @@ -65,16 +75,12 @@ public void run() { for (String coin : config.getCoins()) { awaitServerLimit(); try { - HttpURLConnection connection - = openHttpConnection(getExchangeRateUrl(coin)); - + HttpURLConnection connection = openHttpConnection(getExchangeRateUrl(coin)); int responseCode = connection.getResponseCode(); if (responseCode >= 200 && responseCode <= 299) { JsonObject json = extractJsonFrom(connection); - BigDecimal exchangeRate = json - .get("Realtime Currency Exchange Rate") - .getAsJsonObject() + BigDecimal exchangeRate = json.get("Realtime Currency Exchange Rate").getAsJsonObject() .get("5. Exchange Rate").getAsBigDecimal(); LocalDate date = LocalDate.now(); @@ -89,8 +95,8 @@ public void run() { error = true; } } catch (Exception e) { - warn("Error updating the coins values. " - + "Wait a few minutes and try again!"); + warn("Error updating the coins values. Wait a few minutes and try again!"); + e.printStackTrace(); error = true; } } @@ -118,20 +124,13 @@ public void run() { if (responseCode >= 200 && responseCode <= 299) { JsonObject json = extractJsonFrom(connection); - JsonObject jo = json.getAsJsonObject( - "Time Series (Digital Currency Daily)"); - Set> entries - = jo.entrySet(); + JsonObject jo = json.getAsJsonObject("Time Series (Digital Currency Daily)"); + Set> entries = jo.entrySet(); entries.forEach(entry -> { - LocalDate date - = LocalDate.parse(entry.getKey()); - BigDecimal value = entry.getValue() - .getAsJsonObject() - .get("4a. close (" - + config.getPhysicalCurrency() - + ")") - .getAsBigDecimal(); + LocalDate date = LocalDate.parse(entry.getKey()); + BigDecimal value = entry.getValue().getAsJsonObject().get("4a. close (" + + config.getPhysicalCurrency() + ")").getAsBigDecimal(); ExchangeRate er = getExchangeRate(date); if (er == null) { er = new ExchangeRate(); @@ -143,8 +142,8 @@ public void run() { errors.put(coin, true); } } catch (Exception ex) { - warn("Error updating the coins values. " - + "Wait a few minutes and try again!"); + warn("Error updating the coins values. Wait a few minutes and try again!"); + ex.printStackTrace(); errors.put(coin, true); } } @@ -163,14 +162,10 @@ public void run() { * * @param coin coin * @return the URL - * @throws MalformedURLException */ private URL getExchangeRateUrl(String coin) throws MalformedURLException { - URL url = new URL("https://www.alphavantage.co/query?function=" - + "CURRENCY_EXCHANGE_RATE&from_currency=" + coin - + "&to_currency=" + config.getPhysicalCurrency() - + "&apikey=" + config.getApiKey()); - return url; + return new URL("https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=" + coin + + "&to_currency=" + config.getPhysicalCurrency() + "&apikey=" + config.getApiKey()); } /** @@ -178,25 +173,20 @@ private URL getExchangeRateUrl(String coin) throws MalformedURLException { * * @param coin coin * @return the URL - * @throws MalformedURLException */ private URL getCurrencyDailyUrl(String coin) throws MalformedURLException { - URL url = new URL("https://www.alphavantage.co/query?function=" - + "DIGITAL_CURRENCY_DAILY&symbol=" + coin + "&market=" - + config.getPhysicalCurrency() + "&apikey=" - + config.getApiKey()); - return url; + return new URL("https://www.alphavantage.co/query?function=DIGITAL_CURRENCY_DAILY&symbol=" + coin + "&market=" + + config.getPhysicalCurrency() + "&apikey=" + config.getApiKey()); } /** * Returns the Exchange Rate from the date * * @param date date - * @return Exchange Rate, or null if an error ocurred + * @return Exchange Rate, or null if an error occurred * @throws IllegalArgumentException if date is after today */ - public ExchangeRate getExchangeRate(LocalDate date) throws - IllegalArgumentException { + public @Nullable ExchangeRate getExchangeRate(LocalDate date) throws IllegalArgumentException { Objects.requireNonNull(date); final LocalDate now = LocalDate.now(); if (date.isAfter(now)) { @@ -236,7 +226,7 @@ private static synchronized void awaitServerLimit() { } catch (InterruptedException ex) { ex.printStackTrace(); } - //Reseting requests count + //Resetting requests count requests = 1; } @@ -245,7 +235,7 @@ private static synchronized void awaitServerLimit() { * * @param connection connection * @return json object - * @throws IOException if an error ocurred reading the response + * @throws IOException if an error occurred reading the response */ private JsonObject extractJsonFrom(HttpURLConnection connection) throws IOException { JsonObject json; @@ -289,27 +279,27 @@ public int getMinutesToUpdate() { /** * Verifies if an error happened during an update * - * @return true if an error ocurred + * @return true if an error occurred */ - public static boolean errorOcurred() { + public static boolean errorOccurred() { return dailyError || currentError; } /** - * Sets if an error ocurred during the daily exchange rate update + * Sets if an error occurred during the daily exchange rate update * - * @param error true if ocurred + * @param error true if occurred */ private void setDailyError(boolean error) { dailyError = error; } /** - * Sets if an error ocurred during the current exchange rate update + * Sets if an error occurred during the current exchange rate update * - * @param error true if ocurred + * @param error true if occurred */ - private void setCurrentError(boolean error) { + private static void setCurrentError(boolean error) { currentError = error; } } diff --git a/src/main/java/net/epconsortium/cryptomarket/listeners/PlayerListeners.java b/src/main/java/net/epconsortium/cryptomarket/listeners/PlayerListeners.java new file mode 100644 index 0000000..29a3f16 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/listeners/PlayerListeners.java @@ -0,0 +1,32 @@ +package net.epconsortium.cryptomarket.listeners; + +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.database.dao.InvestorDao; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.jetbrains.annotations.NotNull; + +public class PlayerListeners implements Listener { + + private final CryptoMarket plugin; + private final InvestorDao investorDao; + + public PlayerListeners(@NotNull CryptoMarket plugin) { + this.plugin = plugin; + investorDao = plugin.getInvestorDao(); + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> investorDao.loadInvestor(event.getPlayer())); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + investorDao.unloadInvestor(event.getPlayer()); + } + +} diff --git a/src/main/java/net/epconsortium/cryptomarket/task/SaveInvestorsTask.java b/src/main/java/net/epconsortium/cryptomarket/task/SaveInvestorsTask.java index fd7ac66..a048f5d 100644 --- a/src/main/java/net/epconsortium/cryptomarket/task/SaveInvestorsTask.java +++ b/src/main/java/net/epconsortium/cryptomarket/task/SaveInvestorsTask.java @@ -1,40 +1,36 @@ package net.epconsortium.cryptomarket.task; -import java.util.Objects; import net.epconsortium.cryptomarket.CryptoMarket; -import net.epconsortium.cryptomarket.database.dao.InvestorDao; -import net.epconsortium.cryptomarket.util.Configuration; -import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; /** * Task that save all investors to the database * * @author roinujnosde */ -public class SaveInvestorsTask extends BukkitRunnable { - - private final CryptoMarket plugin; +public class SaveInvestorsTask extends Task { public SaveInvestorsTask(CryptoMarket plugin) { - this.plugin = Objects.requireNonNull(plugin); + super(plugin); } - /** - * Used internally! - */ @Override - public void run() { - InvestorDao dao = new InvestorDao(plugin); - dao.saveAll(); + public @NotNull Runnable getRunnable() { + return () -> plugin.getInvestorDao().saveAll(); } - /** - * Starts the repetitive task - */ - public void start() { - Configuration config = new Configuration(plugin); - long delay = config.getIntervalSavingInvestorsInTicks(); + @Override + public boolean isAsync() { + return true; + } - this.runTaskTimerAsynchronously(plugin, delay, delay); + @Override + public long getDelay() { + return configuration.getIntervalSavingInvestorsInTicks(); + } + + @Override + public long getPeriod() { + return configuration.getIntervalSavingInvestorsInTicks(); } } diff --git a/src/main/java/net/epconsortium/cryptomarket/task/Task.java b/src/main/java/net/epconsortium/cryptomarket/task/Task.java new file mode 100644 index 0000000..c84e17a --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/task/Task.java @@ -0,0 +1,43 @@ +package net.epconsortium.cryptomarket.task; + +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.util.Configuration; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; + +public abstract class Task { + + protected final CryptoMarket plugin; + protected final Configuration configuration; + protected BukkitTask bukkitTask; + + public Task(@NotNull CryptoMarket plugin) { + this.plugin = plugin; + this.configuration = new Configuration(plugin); + } + + public void start() { + BukkitScheduler scheduler = plugin.getServer().getScheduler(); + if (!isAsync()) { + bukkitTask = scheduler.runTaskTimer(plugin, getRunnable(), getDelay(), getPeriod()); + } else { + bukkitTask = scheduler.runTaskTimerAsynchronously(plugin, getRunnable(), getDelay(), getPeriod()); + } + } + + public void cancel() { + if (bukkitTask != null) { + bukkitTask.cancel(); + bukkitTask = null; + } + } + + public abstract @NotNull Runnable getRunnable(); + + public abstract boolean isAsync(); + + public abstract long getDelay(); + + public abstract long getPeriod(); +} diff --git a/src/main/java/net/epconsortium/cryptomarket/task/UpdateExchangeRatesTask.java b/src/main/java/net/epconsortium/cryptomarket/task/UpdateExchangeRatesTask.java index e01e571..27101e9 100644 --- a/src/main/java/net/epconsortium/cryptomarket/task/UpdateExchangeRatesTask.java +++ b/src/main/java/net/epconsortium/cryptomarket/task/UpdateExchangeRatesTask.java @@ -8,49 +8,48 @@ import net.epconsortium.cryptomarket.util.Configuration; import net.epconsortium.cryptomarket.finances.ExchangeRates; import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; /** * Task that updates the exchanges rates * * @author roinujnosde */ -public class UpdateExchangeRatesTask extends BukkitRunnable { +public class UpdateExchangeRatesTask extends Task { - private final ExchangeRates exchangeRates; - - public UpdateExchangeRatesTask(ExchangeRates exchangeRates) { - this.exchangeRates = Objects.requireNonNull(exchangeRates); + public UpdateExchangeRatesTask(@NotNull CryptoMarket plugin) { + super(plugin); } - /** - * Used internally! - */ @Override - public void run() { - //Se ocorreu erro, atualiza as cotações diárias e atual - if (ExchangeRates.errorOcurred()) { - exchangeRates.updateAll(); - //Se não, atualiza apenas a atual - } else { - exchangeRates.updateCurrentExchangeRate(); - } + public @NotNull Runnable getRunnable() { + ExchangeRates exchangeRates = plugin.getExchangeRates(); + return () -> { + //Se ocorreu erro, atualiza as cotações diárias e atual + if (ExchangeRates.errorOccurred()) { + exchangeRates.updateAll(); + //Se não, atualiza apenas a atual + } else { + exchangeRates.updateCurrentExchangeRate(); + } + }; } - /** - * Starts the repetitive task - * - * @param plugin plugin - */ - public void start(CryptoMarket plugin) { - Objects.requireNonNull(plugin); - - Configuration config = new Configuration(plugin); - long period = config.getIntervalExchangeRatesUpdateInTicks(); + @Override + public boolean isAsync() { + return false; + } + @Override + public long getDelay() { LocalDateTime tomorrow = LocalDate.now().plusDays(1).atTime(0, 1); long delay = LocalDateTime.now().until(tomorrow, ChronoUnit.SECONDS) * 20; - delay = delay % period; - this.runTaskTimer(plugin, delay, period); + return delay % getPeriod(); + } + + @Override + public long getPeriod() { + return configuration.getIntervalExchangeRatesUpdateInTicks(); } } diff --git a/src/main/java/net/epconsortium/cryptomarket/task/UpdateRichersListTask.java b/src/main/java/net/epconsortium/cryptomarket/task/UpdateRichersListTask.java new file mode 100644 index 0000000..a27855f --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/task/UpdateRichersListTask.java @@ -0,0 +1,43 @@ +package net.epconsortium.cryptomarket.task; + +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.database.dao.Investor; +import net.epconsortium.cryptomarket.finances.Economy; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class UpdateRichersListTask extends Task { + + public UpdateRichersListTask(@NotNull CryptoMarket plugin) { + super(plugin); + } + + @Override + public @NotNull Runnable getRunnable() { + return () -> { + List investors = plugin.getInvestorDao().getInvestors(); + if (investors == null) { + return; + } + Economy economy = plugin.getEconomy(); + economy.setInvestors(investors); + economy.setRichersLastUpdate(System.currentTimeMillis()); + }; + } + + @Override + public boolean isAsync() { + return true; + } + + @Override + public long getDelay() { + return 0; + } + + @Override + public long getPeriod() { + return configuration.getIntervalRichersUpdateInTicks(); + } +} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Calendar.java b/src/main/java/net/epconsortium/cryptomarket/ui/Calendar.java index 7e5b7cc..c331cbf 100644 --- a/src/main/java/net/epconsortium/cryptomarket/ui/Calendar.java +++ b/src/main/java/net/epconsortium/cryptomarket/ui/Calendar.java @@ -143,8 +143,7 @@ private void loadValues() { lore.add(config.getCalendarMenuNoExchangeRate()); dayMeta.setLore(lore); } else { - ExchangeRates rates = new ExchangeRates(plugin); - ExchangeRate er = rates.getExchangeRate(date); + ExchangeRate er = plugin.getExchangeRates().getExchangeRate(date); if (er == null) { er = new ExchangeRate(); diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/CalendarListener.java b/src/main/java/net/epconsortium/cryptomarket/ui/CalendarListener.java index 9e912eb..d963506 100644 --- a/src/main/java/net/epconsortium/cryptomarket/ui/CalendarListener.java +++ b/src/main/java/net/epconsortium/cryptomarket/ui/CalendarListener.java @@ -28,10 +28,6 @@ public CalendarListener(CryptoMarket plugin) { public void onInventoryClickEvent(InventoryClickEvent event) { Player player = (Player) event.getWhoClicked(); - if (!Helper.isCustomInventory(event)) { - return; - } - if (event.getView().getTitle().equals( config.getCalendarMenuName())) { event.setCancelled(true); diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Component.java b/src/main/java/net/epconsortium/cryptomarket/ui/Component.java new file mode 100644 index 0000000..4970148 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/Component.java @@ -0,0 +1,48 @@ +package net.epconsortium.cryptomarket.ui; + +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; + +public abstract class Component { + + private final HashMap listeners = new HashMap<>(); + private final HashMap permissions = new HashMap<>(); + + @NotNull + public abstract ItemStack getItem(); + + public abstract int getSlot(); + + @Nullable + public ItemMeta getItemMeta() { + return getItem().getItemMeta(); + } + + public void setItemMeta(@NotNull ItemMeta itemMeta) { + getItem().setItemMeta(itemMeta); + } + + public void setPermission(@NotNull ClickType click, @Nullable String permission) { + permissions.put(click, permission); + } + + @Nullable + public String getPermission(@NotNull ClickType click) { + return permissions.get(click); + } + + public void setListener(@NotNull ClickType click, @Nullable Runnable listener) { + listeners.put(click, listener); + } + + @Nullable + public Runnable getListener(@NotNull ClickType click) { + return listeners.get(click); + } +} + diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/ComponentImpl.java b/src/main/java/net/epconsortium/cryptomarket/ui/ComponentImpl.java new file mode 100644 index 0000000..661fef8 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/ComponentImpl.java @@ -0,0 +1,116 @@ +package net.epconsortium.cryptomarket.ui; + +import com.cryptomorin.xseries.XMaterial; +import org.bukkit.Material; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class ComponentImpl extends Component { + + @NotNull + private ItemStack item; + private int slot; + + private ComponentImpl() { + item = new ItemStack(Material.STONE); + slot = 0; + } + + public ComponentImpl(@Nullable String displayName, @Nullable List lore, @NotNull Material material, + int slot) { + this(displayName, lore, new ItemStack(material), slot); + } + + public ComponentImpl(@Nullable String displayName, @Nullable List lore, @NotNull XMaterial material, + int slot) { + this(displayName, lore, material.parseItem(true), slot); + } + + public ComponentImpl(@Nullable String displayName, @Nullable List lore, @Nullable ItemStack item, + int slot) { + if (item == null) { + item = new ItemStack(Material.STONE); + } + this.item = item; + ItemMeta itemMeta = item.getItemMeta(); + if (itemMeta != null) { + itemMeta.setDisplayName(displayName); + itemMeta.setLore(lore); + itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + item.setItemMeta(itemMeta); + } + this.slot = slot; + } + + @Override + public @NotNull ItemStack getItem() { + return item; + } + + @Override + public int getSlot() { + return slot; + } + + public static class Builder { + private final ComponentImpl component = new ComponentImpl(); + private @Nullable List lore; + + public Builder(@NotNull XMaterial material) { + this(material.parseItem(true)); + } + + public Builder(@NotNull Material material) { + component.item = new ItemStack(material); + } + + public Builder(@Nullable ItemStack item) { + if (item == null) { + item = new ItemStack(Material.STONE); + } + component.item = item; + } + + public Builder withDisplayName(@Nullable String displayName) { + ItemMeta itemMeta = component.getItemMeta(); + if (itemMeta != null) { + itemMeta.setDisplayName(displayName); + component.setItemMeta(itemMeta); + } + return this; + } + + public Builder withLore(@Nullable List lore) { + this.lore = lore; + return this; + } + + public Builder withLoreLine(@NotNull String line) { + if (lore == null) { + lore = new ArrayList<>(); + } + lore.add(line); + return this; + } + + public Builder withSlot(int slot) { + component.slot = slot; + return this; + } + + public Component build() { + ItemMeta itemMeta = component.getItemMeta(); + if (itemMeta != null) { + itemMeta.setLore(lore); + component.setItemMeta(itemMeta); + } + return component; + } + } +} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Components.java b/src/main/java/net/epconsortium/cryptomarket/ui/Components.java new file mode 100644 index 0000000..c7fa401 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/Components.java @@ -0,0 +1,19 @@ +package net.epconsortium.cryptomarket.ui; + +import com.cryptomorin.xseries.XMaterial; + +public class Components { + + private Components() { + } + + public static Component generic(XMaterial material, String displayName, int slot) { + return new ComponentImpl(displayName, null, material, slot); + } + + public static void addPanels(Frame frame, XMaterial material, int[] slots) { + for (int slot : slots) { + frame.add(generic(material, " ", slot)); + } + } +} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Frame.java b/src/main/java/net/epconsortium/cryptomarket/ui/Frame.java new file mode 100644 index 0000000..5bfc57f --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/Frame.java @@ -0,0 +1,83 @@ +package net.epconsortium.cryptomarket.ui; + +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.util.Configuration; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class Frame { + + protected final CryptoMarket plugin; + protected final Configuration configuration; + private final Frame parent; + private final Player viewer; + private final Set components = ConcurrentHashMap.newKeySet(); + + public Frame(@Nullable Frame parent, @NotNull Player viewer) { + this.parent = parent; + this.viewer = viewer; + plugin = CryptoMarket.getInstance(); + configuration = new Configuration(plugin); + } + + @NotNull + public abstract String getTitle(); + + @NotNull + public Player getViewer() { + return viewer; + } + + @Nullable + public Frame getParent() { + return parent; + } + + public abstract int getSize(); + + public abstract void createComponents(); + + @Nullable + public Component getComponent(int slot) { + for (Component c : getComponents()) { + if (c.getSlot() == slot) { + return c; + } + } + return null; + } + + public void add(@NotNull Component c) { + components.add(c); + } + + public void clear() { + components.clear(); + } + + @NotNull + public Set getComponents() { + return components; + } + + @Override + public boolean equals(Object other) { + if (other instanceof Frame) { + Frame otherFrame = (Frame) other; + return getSize() == otherFrame.getSize() && getTitle().equals(otherFrame.getTitle()) + && getComponents().equals(otherFrame.getComponents()); + } + + return false; + } + + @Override + public int hashCode() { + return getTitle().hashCode() + Integer.hashCode(getSize()) + getComponents().hashCode(); + } + +} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Helper.java b/src/main/java/net/epconsortium/cryptomarket/ui/Helper.java deleted file mode 100644 index ef9993b..0000000 --- a/src/main/java/net/epconsortium/cryptomarket/ui/Helper.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.epconsortium.cryptomarket.ui; - -import java.util.Objects; -import org.bukkit.event.inventory.InventoryClickEvent; - -class Helper { - - /** - * Checks if this is not a regular inventory (like a Chest or something) - * - * @param event event - * @return true if it is a custom inventory - */ - static boolean isCustomInventory(InventoryClickEvent event) { - Objects.requireNonNull(event); - - return event.getView().getTitle() != null - && event.getCurrentItem() != null - && event.getCurrentItem().hasItemMeta() - && event.getCurrentItem().getItemMeta().hasDisplayName(); - } -} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/InventoryController.java b/src/main/java/net/epconsortium/cryptomarket/ui/InventoryController.java new file mode 100644 index 0000000..68d0333 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/InventoryController.java @@ -0,0 +1,114 @@ +package net.epconsortium.cryptomarket.ui; + +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.util.Configuration; +import org.bukkit.Bukkit; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class InventoryController implements Listener { + private static InventoryController instance; + + private final Map frames = new HashMap<>(); + private final Configuration configuration = new Configuration(CryptoMarket.getInstance()); + + private InventoryController() {} + + public static InventoryController getInstance() { + if (instance == null) { + instance = new InventoryController(); + } + return instance; + } + + @EventHandler(ignoreCancelled = true) + public void onClose(InventoryCloseEvent event) { + HumanEntity entity = event.getPlayer(); + if (!(entity instanceof Player)) { + return; + } + + frames.remove(entity.getUniqueId()); + } + + @EventHandler(ignoreCancelled = true) + public void onInteract(InventoryClickEvent event) { + HumanEntity entity = event.getWhoClicked(); + if (!(entity instanceof Player)) { + return; + } + + Frame frame = frames.get(entity.getUniqueId()); + if (frame == null) { + return; + } + + event.setCancelled(true); + + if (event.getClickedInventory() == null || event.getClickedInventory().getType() == InventoryType.PLAYER) { + return; + } + + Component component = frame.getComponent(event.getSlot()); + if (component == null) { + return; + } + + ClickType click = event.getClick(); + Runnable listener = component.getListener(click); + if (listener == null) { + return; + } + + String permission = component.getPermission(click); + if (permission != null) { + if (!entity.hasPermission(permission)) { + entity.sendMessage(configuration.getMessageErrorNoPermission()); + return; + } + } + + Bukkit.getScheduler().runTask(CryptoMarket.getInstance(), () -> { + ItemStack currentItem = event.getCurrentItem(); + if (currentItem == null) return; + + ItemMeta itemMeta = currentItem.getItemMeta(); + Objects.requireNonNull(itemMeta).setLore(Collections.singletonList("...")); + currentItem.setItemMeta(itemMeta); + + listener.run(); + }); + } + + /** + * Registers the frame in the InventoryController + * @param frame the frame + * + * @author RoinujNosde + */ + public void register(@NotNull Frame frame) { + frames.put(frame.getViewer().getUniqueId(), frame); + } + + /** + * Checks if the Player is registered + * + * @param player the Player + * @return if they are registered + */ + public boolean isRegistered(@NotNull Player player) { + return frames.containsKey(player.getUniqueId()); + } +} + diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/InventoryDrawer.java b/src/main/java/net/epconsortium/cryptomarket/ui/InventoryDrawer.java new file mode 100644 index 0000000..3289de4 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/InventoryDrawer.java @@ -0,0 +1,79 @@ +package net.epconsortium.cryptomarket.ui; + +import net.epconsortium.cryptomarket.CryptoMarket; +import org.bukkit.Bukkit; +import org.bukkit.inventory.Inventory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class InventoryDrawer { + private static InventoryDrawer instance; + private final CryptoMarket plugin = CryptoMarket.getInstance(); + private final ConcurrentHashMap OPENING = new ConcurrentHashMap<>(); + + private InventoryDrawer() { + } + + public static InventoryDrawer getInstance() { + if (instance == null) { + instance = new InventoryDrawer(); + } + return instance; + } + + public void open(@Nullable Frame frame) { + if (frame == null) { + return; + } + UUID uuid = frame.getViewer().getUniqueId(); + if (frame.equals(OPENING.get(uuid))) { + return; + } + + OPENING.put(uuid, frame); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + + Inventory inventory = prepareInventory(frame); + + if (!frame.equals(OPENING.get(uuid))) { + return; + } + Bukkit.getScheduler().runTask(plugin, () -> { + frame.getViewer().openInventory(inventory); + InventoryController.getInstance().register(frame); + OPENING.remove(uuid); + }); + }); + } + + @NotNull + private Inventory prepareInventory(@NotNull Frame frame) { + Inventory inventory = Bukkit.createInventory(frame.getViewer(), frame.getSize(), frame.getTitle()); + setComponents(inventory, frame); + return inventory; + } + + + private void setComponents(@NotNull Inventory inventory, @NotNull Frame frame) { + frame.clear(); + frame.createComponents(); + + Set components = frame.getComponents(); + if (components.isEmpty()) { + plugin.getLogger().warning(String.format("Frame %s has no components", frame.getTitle())); + return; + } + for (Component c : frame.getComponents()) { + if (c.getSlot() >= frame.getSize()) { + continue; + } + inventory.setItem(c.getSlot(), c.getItem()); + } + } + +} + diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Menu.java b/src/main/java/net/epconsortium/cryptomarket/ui/Menu.java deleted file mode 100644 index ed3fecb..0000000 --- a/src/main/java/net/epconsortium/cryptomarket/ui/Menu.java +++ /dev/null @@ -1,350 +0,0 @@ -package net.epconsortium.cryptomarket.ui; - -import java.math.BigDecimal; - -import com.cryptomorin.xseries.XMaterial; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; - -import java.text.MessageFormat; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import net.epconsortium.cryptomarket.CryptoMarket; -import net.epconsortium.cryptomarket.database.dao.Investor; -import net.epconsortium.cryptomarket.database.dao.InvestorDao; -import net.epconsortium.cryptomarket.finances.ExchangeRate; -import net.epconsortium.cryptomarket.finances.ExchangeRates; -import net.epconsortium.cryptomarket.util.Configuration; -import net.epconsortium.cryptomarket.util.Formatter; -import org.bukkit.scheduler.BukkitRunnable; - -/** - * Represents the Main menu - * - * @author roinujnosde - */ -public class Menu { - - private final CryptoMarket plugin; - private final Configuration config; - private final ExchangeRates rates; - - private final Player player; - private final Inventory inventory; - private Investor investor; - - public Menu(CryptoMarket plugin, Player player) { - this.plugin = Objects.requireNonNull(plugin); - this.player = Objects.requireNonNull(player); - rates = new ExchangeRates(this.plugin); - config = new Configuration(plugin); - inventory = Bukkit.createInventory(null, 54, config.getMenuName()); - } - - /** - * Opens the Menu - */ - @SuppressWarnings("LocalVariableHidesMemberVariable") - public void open() { - new InvestorDao(plugin).getInvestor(player, (investor) -> { - new BukkitRunnable() { - @Override - public void run() { - if (!player.isOnline()) { - return; - } - if (investor == null) { - player.sendMessage(config.getMessageErrorConnectingToDatabase()); - return; - } - Menu.this.investor = investor; - configureInventory(); - player.openInventory(inventory); - } - }.runTask(plugin); - }); - } - - /** - * Configures the inventory - */ - private void configureInventory() { - ItemStack coins = configureItemCoins(); - ItemStack wallet = configureItemWallet(); - ItemStack ranking = configureItemRanking(); - ItemStack profit = configureProfitItem(); - ItemStack calendar = configureGenericItem(XMaterial.FILLED_MAP, - config.getButtonCalendarName()); - ItemStack update = configureGenericItem(XMaterial.STRUCTURE_VOID, - config.getButtonUpdateName()); - ItemStack blackGlass = configureGenericItem( - XMaterial.BLACK_STAINED_GLASS_PANE, " "); - ItemStack grayGlass = configureGenericItem(XMaterial.GRAY_STAINED_GLASS_PANE, " "); - - setButtonsPositions(coins, wallet, profit, calendar, update, blackGlass, - grayGlass, ranking); - } - - /** - * Configures the Profit item - * - * @return the profit item - */ - private ItemStack configureProfitItem() { - ItemStack profit = XMaterial.LIME_DYE.parseItem(true); - if (profit == null) { - profit = new ItemStack(Material.STONE); - } - ItemMeta profitMeta = profit.getItemMeta(); - profitMeta.setDisplayName(config.getButtonProfitName()); - - List lore = configureProfitItemLore(); - - profitMeta.setLore(lore); - profit.setItemMeta(profitMeta); - - return profit; - } - - /** - * Configures the lore of Profit item - * - */ - private List configureProfitItemLore() { - List coinLines = new ArrayList<>(); - String coinLine = config.getButtonProfitCoinLine(); - ExchangeRate rate = rates.getExchangeRate(LocalDate.now()); - if (rate == null) { - rate = new ExchangeRate(); - } - for (String coin : config.getCoins()) { - BigDecimal profitD = investor.getBalance(coin).getProfitPercentage( - rate.getCoinValue(coin)); - String color = config.getButtonProfitNeuterColor(); - if (profitD.compareTo(BigDecimal.ZERO) > 0) { - color = config.getButtonProfitPositiveColor(); - } else if (profitD.compareTo(BigDecimal.ZERO) < 0) { - color = config.getButtonProfitNegativeColor(); - } - - coinLines.add(MessageFormat.format(coinLine, coin, color, - Formatter.formatServerCurrency(profitD))); - } - List lore = config.getButtonProfitLore(); - int indexPlaceholder = 0; - String tempLine = "{0}"; - for (int i = 0; i < lore.size(); i++) { - String l = lore.get(i); - if (l.contains("{0}")) { - indexPlaceholder = i; - tempLine = l; - } - } - lore.addAll(indexPlaceholder, coinLines); - lore.remove(tempLine); - return lore; - } - - /** - * Configures an item with a name and material only - * - * @param material material - * @param name name - * @return item - */ - private ItemStack configureGenericItem(XMaterial material, String name) { - ItemStack stack = material.parseItem(true); - if (stack == null) { - stack = new ItemStack(Material.STONE); - } - ItemMeta meta = stack.getItemMeta(); - meta.setDisplayName(name); - stack.setItemMeta(meta); - - return stack; - } - - /** - * Configures the Wallet item - * - * @return Wallet item - */ - private ItemStack configureItemWallet() { - ItemStack wallet = XMaterial.BOOK.parseItem(true); - if (wallet == null) { - wallet = new ItemStack(Material.STONE); - } - ItemMeta meta = wallet.getItemMeta(); - meta.setDisplayName(config.getButtonWalletName()); - configureItemWalletLore(meta); - wallet.setItemMeta(meta); - return wallet; - } - - /** - * Configures the Coins item - * - * @return Coins item - */ - private ItemStack configureItemCoins() { - ItemStack coins = XMaterial.SUNFLOWER.parseItem(true); - if (coins == null) { - coins = new ItemStack(Material.STONE); - } - ItemMeta meta = coins.getItemMeta(); - meta.addEnchant(Enchantment.ARROW_DAMAGE, 1, false); - meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); - meta.setDisplayName(config.getButtonCoinsName()); - - configureItemCoinsLore(meta); - coins.setItemMeta(meta); - return coins; - } - - /** - * Configures the lore of Wallet item - * - * @param meta Wallet meta - */ - private void configureItemWalletLore(ItemMeta meta) { - List lore = config.getButtonWalletLore(); - double vaultBalance = plugin.getEconomy().getBalance(player); - - int balanceIndex = 0; - String tempBalance = "{0}"; - int coinsIndex = 1; - String coinsLineTemp = "{1}"; - for (int i = 0; i < lore.size(); i++) { - String l = lore.get(i); - if (l.contains("{0}")) { - balanceIndex = i; - tempBalance = l; - } - if (l.contains("{1}")) { - coinsIndex = i; - coinsLineTemp = l; - } - } - lore.add(balanceIndex, MessageFormat.format(tempBalance, - Formatter.formatServerCurrency(vaultBalance))); - lore.remove(tempBalance); - - List coinsTemp = new ArrayList<>(); - String coinLine = config.getButtonWalletCoinLine(); - for (String coin : config.getCoins()) { - String format = MessageFormat.format(coinLine, coin, - Formatter.formatCryptocoin(investor.getBalance(coin) - .getValue())); - coinsTemp.add(format); - } - - lore.addAll(coinsIndex, coinsTemp); - lore.remove(coinsLineTemp); - - meta.setLore(lore); - } - - /** - * Configures the lore of the Coins item - * - * @param meta Coins meta - */ - private void configureItemCoinsLore(ItemMeta meta) { - ExchangeRate er = rates.getExchangeRate(LocalDate.now()); - List lore = config.getButtonCoinsLore(); - if (er == null) { - er = new ExchangeRate(); - } - - //Configuring the line of values of the item - List coinsLine = new ArrayList<>(); - for (String coin : config.getCoins()) { - BigDecimal coinValue = er.getCoinValue(coin); - String format; - if (coinValue.equals(new BigDecimal(-1))) { - format = MessageFormat.format(config.getButtonCoinsCoinLine(), - coin, config.getButtonCoinsError()); - } else { - format = MessageFormat.format(config.getButtonCoinsCoinLine(), - coin, Formatter.formatServerCurrency(coinValue)); - } - coinsLine.add(format); - } - - //Adding the line of values to the lore - int index = 0; - String remove = null; - for (int i = 0; i < lore.size(); i++) { - String s = lore.get(i); - if (s.contains("{0}")) { - index = i; - remove = s; - } - } - lore.addAll(index, coinsLine); - if (remove != null) { - lore.remove(remove); - } - meta.setLore(lore); - } - - /** - * Configures the Ranking item - * - * @return Ranking item - */ - private ItemStack configureItemRanking() { - ItemStack ranking = XMaterial.PLAYER_HEAD.parseItem(true); - if (ranking == null) { - ranking = new ItemStack(Material.STONE); - } - ItemMeta rankingMeta = ranking.getItemMeta(); - rankingMeta.setDisplayName(config.getButtonRankingName()); - ranking.setItemMeta(rankingMeta); - return ranking; - } - - /** - * Sets the Buttons on the inventory - * - * @param coins - * @param wallet - * @param profit - * @param calendar - * @param update - * @param blackGlass - * @param greyGlass - * @param ranking - */ - private void setButtonsPositions(ItemStack coins, ItemStack wallet, - ItemStack profit, ItemStack calendar, ItemStack update, - ItemStack blackGlass, ItemStack greyGlass, ItemStack ranking) { - - int[] grey = {1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 24, 26, 22, 27, - 29, 47, 48, 51, 50, 30, 36, 38, 39, 40, 41, 42, 44, 32, 33, 35}; - for (int i : grey) { - inventory.setItem(i, greyGlass); - } - - int[] black = {28, 0, 3, 5, 8, 10, 16, 21, 23, 34, 45, 46, 49, 52, 52, - 31}; - for (int i : black) { - inventory.setItem(i, blackGlass); - } - - inventory.setItem(37, ranking); - inventory.setItem(12, coins); - inventory.setItem(14, wallet); - inventory.setItem(19, profit); - inventory.setItem(25, calendar); - inventory.setItem(43, update); - } -} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/MenuListener.java b/src/main/java/net/epconsortium/cryptomarket/ui/MenuListener.java index a2c407e..bbfb955 100644 --- a/src/main/java/net/epconsortium/cryptomarket/ui/MenuListener.java +++ b/src/main/java/net/epconsortium/cryptomarket/ui/MenuListener.java @@ -4,6 +4,7 @@ import net.epconsortium.cryptomarket.conversation.NegotiationConversation; import net.epconsortium.cryptomarket.finances.ExchangeRates; import net.epconsortium.cryptomarket.finances.Negotiation; +import net.epconsortium.cryptomarket.ui.frames.RankingFrame; import net.epconsortium.cryptomarket.util.Configuration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -12,6 +13,7 @@ import java.text.MessageFormat; import java.util.Objects; +import java.util.concurrent.ExecutionException; /** * Class used to listen to clicks on the Menu menu and process them @@ -32,10 +34,6 @@ public MenuListener(CryptoMarket plugin) { public void onInventoryClick(InventoryClickEvent event) { Player player = (Player) event.getWhoClicked(); - if (!Helper.isCustomInventory(event)) { - return; - } - if (event.getView().getTitle().equals(config.getMenuName())) { event.setCancelled(true); @@ -59,8 +57,8 @@ private boolean processUpdateButton(InventoryClickEvent event, Player player) { player.closeInventory(); return true; } - if (ExchangeRates.errorOcurred()) { - ExchangeRates er = new ExchangeRates(plugin); + if (ExchangeRates.errorOccurred()) { + ExchangeRates er = plugin.getExchangeRates(); er.updateAll(); player.closeInventory(); @@ -112,8 +110,13 @@ private boolean processRankingButton(InventoryClickEvent event, Player player) { player.closeInventory(); return true; } - Ranking ranking = new Ranking(plugin, player); - ranking.open(); + //todo trocar parent para o MenuFrame + try { + InventoryDrawer.getInstance().open(new RankingFrame(null, player)); + } catch (ExecutionException | InterruptedException e) { + player.sendMessage(config.getMessageErrorAccessingRankingData()); + e.printStackTrace(); + } return true; } return false; diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/Ranking.java b/src/main/java/net/epconsortium/cryptomarket/ui/Ranking.java deleted file mode 100644 index 6cc7f59..0000000 --- a/src/main/java/net/epconsortium/cryptomarket/ui/Ranking.java +++ /dev/null @@ -1,247 +0,0 @@ -package net.epconsortium.cryptomarket.ui; - -import com.cryptomorin.xseries.XMaterial; -import net.epconsortium.cryptomarket.CryptoMarket; -import net.epconsortium.cryptomarket.database.dao.Investor; -import net.epconsortium.cryptomarket.finances.Economy; -import net.epconsortium.cryptomarket.util.Configuration; -import net.epconsortium.cryptomarket.util.Formatter; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.SkullMeta; -import org.bukkit.scheduler.BukkitRunnable; - -import java.math.BigDecimal; -import java.text.MessageFormat; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import static net.epconsortium.cryptomarket.CryptoMarket.debug; -import static org.bukkit.Material.STONE; - -/** - * Represents the Ranking menu - * - * @author roinujnosde - */ -public class Ranking { - - private final Player player; - private final CryptoMarket plugin; - private final Inventory inventory; - private final Configuration config; - private List richersList; - private double totalInvestments; - - public Ranking(CryptoMarket plugin, Player player) { - this.player = Objects.requireNonNull(player); - this.plugin = Objects.requireNonNull(plugin); - - config = new Configuration(plugin); - inventory = Bukkit.createInventory(null, 45, - config.getRankingMenuName()); - } - - /** - * Open the Ranking menu - */ - public void open() { - Economy eco = new Economy(plugin, ""); - eco.getRichestInvestors(5, (investors) -> { - eco.getTotalInvestments(total -> { - new BukkitRunnable() { - @Override - public void run() { - if (player.isOnline()) { - if (investors == null || total == -1) { - player.sendMessage(config - .getMessageErrorAccessingRankingData()); - return; - } - debug("Ranking: investors size: " + investors.size()); - richersList = investors; - totalInvestments = total; - configureInventory(); - player.openInventory(inventory); - } - } - }.runTask(plugin); - }); - }); - } - - /** - * Configures the Richer on the index - * - * @param index index - * @return the Richer item - */ - private ItemStack getRicher(int index) { - Economy econ = new Economy(plugin, ""); - - ItemStack head = XMaterial.PLAYER_HEAD.parseItem(true); - ItemMeta meta = Objects.requireNonNull(head).getItemMeta(); - - int rank = index + 1; - - if (index >= richersList.size()) { - meta.setDisplayName(MessageFormat.format( - config.getRankingMenuNoRicherLore(), rank)); - head.setItemMeta(meta); - } else { - Investor richer = richersList.get(index); - SkullMeta skullMeta = (SkullMeta) head.getItemMeta(); - skullMeta.setOwner(richer.getPlayer().getName()); - skullMeta.setDisplayName(MessageFormat.format( - config.getRankingMenuRicherItemName(), rank, - richer.getPlayer().getName())); - - List lore1 = config.getRankingMenuRicherItemLore(); - ArrayList lore2 = new ArrayList<>(); - BigDecimal patrimony = econ.getConvertedPatrimony(richer); - double percentage = 0; - if (totalInvestments > 0) { - percentage = (patrimony.doubleValue() / totalInvestments) * 100; - } - for (String s : lore1) { - lore2.add(MessageFormat.format(s, - Formatter.formatServerCurrency(patrimony), - Formatter.formatPercentage(percentage))); - } - - skullMeta.setLore(lore2); - head.setItemMeta(skullMeta); - } - - return head; - } - - /** - * Configures the inventory - */ - private void configureInventory() { - List richers = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - richers.add(getRicher(i)); - } - - ItemStack total = configureTotalInvestmentsItem(); - ItemStack lastUpdated = configureLastUpdated(); - ItemStack back = configureBackButton(); - ItemStack black = configureGenericItem(XMaterial.BLACK_STAINED_GLASS_PANE, " "); - ItemStack grey = configureGenericItem(XMaterial.GRAY_STAINED_GLASS_PANE, " "); - - setItemsPositions(black, grey, back, richers, total, lastUpdated); - } - - private ItemStack configureLastUpdated() { - ItemStack lastUpdated = XMaterial.CLOCK.parseItem(true); - ItemMeta lastUpdatedMeta = Objects.requireNonNull(lastUpdated).getItemMeta(); - lastUpdatedMeta.setDisplayName(config.getRankingMenuLastUpdatedItemName()); - List lastUpdateLore = new ArrayList<>(); - for (String s : config.getRankingMenuLastUpdatedItemLore()) { - lastUpdateLore.add(MessageFormat.format(s, - Economy.getRichersLastUpdate().format(DateTimeFormatter - .ofLocalizedDateTime(FormatStyle.SHORT)))); - } - lastUpdatedMeta.setLore(lastUpdateLore); - lastUpdated.setItemMeta(lastUpdatedMeta); - return lastUpdated; - } - - private ItemStack configureTotalInvestmentsItem() { - ItemStack total = XMaterial.SUNFLOWER.parseItem(true); - if (total == null) { - total = new ItemStack(STONE); - } - ItemMeta totalMeta = total.getItemMeta(); - totalMeta.setDisplayName(config.getRankingMenuTotalInvestmentsItemName()); - List totalLore = new ArrayList<>(); - for (String s : config.getRankingMenuTotalInvestmentsItemLore()) { - totalLore.add(MessageFormat.format(s, - Formatter.formatServerCurrency(totalInvestments))); - } - totalMeta.setLore(totalLore); - total.setItemMeta(totalMeta); - - return total; - } - - /** - * Configures a generic item - * - * @param material - * @param name - * @return the item - */ - private ItemStack configureGenericItem(XMaterial material, String name) { - ItemStack stack = material.parseItem(true); - if (stack == null) { - stack = new ItemStack(STONE); - } - ItemMeta meta = stack.getItemMeta(); - meta.setDisplayName(name); - stack.setItemMeta(meta); - - return stack; - } - - /** - * Configures the Back button - * - * @return the back button - */ - private ItemStack configureBackButton() { - ItemStack back = XMaterial.ARROW.parseItem(true); - if (back == null) { - back = new ItemStack(STONE); - } - ItemMeta meta = back.getItemMeta(); - meta.setDisplayName(config.getRankingMenuBackButton()); - back.setItemMeta(meta); - return back; - } - - /** - * Sets the items' positions - * - * @param blackGlass - * @param grayGlass - * @param back - * @param richers - */ - private void setItemsPositions(ItemStack blackGlass, ItemStack grayGlass, - ItemStack back, List richers, ItemStack total, - ItemStack lastUpdated) { - //black glasses - int black[] = {0, 3, 5, 8, 9, 11, 12, 14, 15, 17, 18, 19, 25, 26, 27, - 29, 30, 32, 33, 35, 41, 39, 44}; - for (int b : black) { - inventory.setItem(b, blackGlass); - } - //grey glasses - int grey[] = {1, 2, 6, 7, 10, 13, 16, 28, 31, 34, 37, 40, 42, 43}; - for (int g : grey) { - inventory.setItem(g, grayGlass); - } - //back button - inventory.setItem(4, back); - //total investments - inventory.setItem(36, total); - //last updated - inventory.setItem(38, lastUpdated); - //richers - int index = 20; - for (ItemStack richer : richers) { - inventory.setItem(index, richer); - index++; - } - } -} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/RankingListener.java b/src/main/java/net/epconsortium/cryptomarket/ui/RankingListener.java deleted file mode 100644 index 5acd40d..0000000 --- a/src/main/java/net/epconsortium/cryptomarket/ui/RankingListener.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.epconsortium.cryptomarket.ui; - -import java.util.Objects; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryClickEvent; - -import net.epconsortium.cryptomarket.CryptoMarket; -import net.epconsortium.cryptomarket.util.Configuration; - -/** - * Class used to listen to clicks on the Ranking menu and process them - * - * @author roinujnosde - */ -public class RankingListener implements Listener { - - private final CryptoMarket plugin; - private final Configuration config; - - public RankingListener(CryptoMarket plugin) { - this.plugin = Objects.requireNonNull(plugin); - config = new Configuration(plugin); - } - - @EventHandler - public void onInventoryClickEvent(InventoryClickEvent event) { - Player player = (Player) event.getWhoClicked(); - - if (!Helper.isCustomInventory(event)) { - return; - } - - if (event.getView().getTitle().equals(config.getRankingMenuName())) { - event.setCancelled(true); - processBackButton(event, player); - } - } - - private boolean processBackButton(InventoryClickEvent event, Player player) { - if (event.getCurrentItem().getItemMeta().getDisplayName().equals( - config.getRankingMenuBackButton())) { - player.closeInventory(); - Menu menu = new Menu(plugin, player); - menu.open(); - return true; - } - - return false; - } -} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/frames/MenuFrame.java b/src/main/java/net/epconsortium/cryptomarket/ui/frames/MenuFrame.java new file mode 100644 index 0000000..8fe6631 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/frames/MenuFrame.java @@ -0,0 +1,212 @@ +package net.epconsortium.cryptomarket.ui.frames; + +import com.cryptomorin.xseries.XMaterial; +import net.epconsortium.cryptomarket.database.dao.Investor; +import net.epconsortium.cryptomarket.finances.ExchangeRate; +import net.epconsortium.cryptomarket.finances.ExchangeRates; +import net.epconsortium.cryptomarket.ui.Component; +import net.epconsortium.cryptomarket.ui.ComponentImpl; +import net.epconsortium.cryptomarket.ui.ComponentImpl.Builder; +import net.epconsortium.cryptomarket.ui.Frame; +import net.epconsortium.cryptomarket.util.Formatter; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.math.BigDecimal; +import java.text.MessageFormat; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +import static com.cryptomorin.xseries.XMaterial.BLACK_STAINED_GLASS_PANE; +import static com.cryptomorin.xseries.XMaterial.GRAY_STAINED_GLASS_PANE; +import static net.epconsortium.cryptomarket.ui.Components.addPanels; +import static net.epconsortium.cryptomarket.ui.Components.generic; + +public class MenuFrame extends Frame { + private final Investor investor; + private final ExchangeRates rates; + + public MenuFrame(@Nullable Frame parent, @NotNull Player viewer) { + super(parent, viewer); + investor = plugin.getInvestorDao().getInvestor(viewer); + rates = plugin.getExchangeRates(); + } + + @Override + public @NotNull String getTitle() { + return configuration.getMenuName(); + } + + @Override + public int getSize() { + return 54; + } + + @Override + public void createComponents() { + add(profit()); + add(coins()); + add(wallet()); + add(ranking()); + add(generic(XMaterial.FILLED_MAP, configuration.getButtonCalendarName(), 25)); + add(generic(XMaterial.STRUCTURE_VOID, configuration.getButtonUpdateName(), 43)); + addGlasses(); + } + + private void addGlasses() { + int[] blackSlots = {28, 0, 3, 5, 8, 10, 16, 21, 23, 34, 45, 46, 49, 52, 52, 31}; + addPanels(this, BLACK_STAINED_GLASS_PANE, blackSlots); + + int[] greySlots = {1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 24, 26, 22, 27, 29, 47, 48, 51, 50, 30, 36, 38, 39, + 40, 41, 42, 44, 32, 33, 35}; + addPanels(this, GRAY_STAINED_GLASS_PANE, greySlots); + } + + private Component profit() { + return new Builder(XMaterial.LIME_DYE).withDisplayName(configuration.getButtonProfitName()) + .withLore(getProfitItemLore()).withSlot(19).build(); + } + + private List getProfitItemLore() { + List coinLines = new ArrayList<>(); + String coinLine = configuration.getButtonProfitCoinLine(); + ExchangeRate rate = rates.getExchangeRate(LocalDate.now()); + if (rate == null) { + rate = new ExchangeRate(); + } + for (String coin : configuration.getCoins()) { + BigDecimal profitD = investor.getBalance(coin).getProfitPercentage( + rate.getCoinValue(coin)); + String color = configuration.getButtonProfitNeuterColor(); + if (profitD.compareTo(BigDecimal.ZERO) > 0) { + color = configuration.getButtonProfitPositiveColor(); + } else if (profitD.compareTo(BigDecimal.ZERO) < 0) { + color = configuration.getButtonProfitNegativeColor(); + } + + coinLines.add(MessageFormat.format(coinLine, coin, color, + Formatter.formatServerCurrency(profitD))); + } + List lore = configuration.getButtonProfitLore(); + int indexPlaceholder = 0; + String tempLine = "{0}"; + for (int i = 0; i < lore.size(); i++) { + String l = lore.get(i); + if (l.contains("{0}")) { + indexPlaceholder = i; + tempLine = l; + } + } + lore.addAll(indexPlaceholder, coinLines); + lore.remove(tempLine); + return lore; + } + + private Component wallet() { + return new Builder(XMaterial.BOOK).withDisplayName(configuration.getButtonWalletName()) + .withLore(getWalletLore()).withSlot(14).build(); + } + + private Component coins() { + ItemStack coins = XMaterial.SUNFLOWER.parseItem(true); + if (coins == null) { + coins = new ItemStack(Material.STONE); + } + + ItemMeta meta = coins.getItemMeta(); + meta.addEnchant(Enchantment.ARROW_DAMAGE, 1, false); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + meta.setDisplayName(configuration.getButtonCoinsName()); + + coins.setItemMeta(meta); + return new ComponentImpl(configuration.getButtonCoinsName(), getCoinsLore(), coins, 12); + } + + private List getWalletLore() { + List lore = configuration.getButtonWalletLore(); + double vaultBalance = plugin.getVaultEconomy().getBalance(getViewer()); + + int balanceIndex = 0; + String tempBalance = "{0}"; + int coinsIndex = 1; + String coinsLineTemp = "{1}"; + for (int i = 0; i < lore.size(); i++) { + String l = lore.get(i); + if (l.contains("{0}")) { + balanceIndex = i; + tempBalance = l; + } + if (l.contains("{1}")) { + coinsIndex = i; + coinsLineTemp = l; + } + } + lore.add(balanceIndex, MessageFormat.format(tempBalance, + Formatter.formatServerCurrency(vaultBalance))); + lore.remove(tempBalance); + + List coinsTemp = new ArrayList<>(); + String coinLine = configuration.getButtonWalletCoinLine(); + for (String coin : configuration.getCoins()) { + String format = MessageFormat.format(coinLine, coin, Formatter.formatCryptocoin(investor.getBalance(coin) + .getValue())); + coinsTemp.add(format); + } + + lore.addAll(coinsIndex, coinsTemp); + lore.remove(coinsLineTemp); + + return lore; + } + + private List getCoinsLore() { + ExchangeRate er = rates.getExchangeRate(LocalDate.now()); + List lore = configuration.getButtonCoinsLore(); + if (er == null) { + er = new ExchangeRate(); + } + + //Configuring the line of values of the item + List coinsLine = new ArrayList<>(); + for (String coin : configuration.getCoins()) { + BigDecimal coinValue = er.getCoinValue(coin); + String format; + if (coinValue.equals(new BigDecimal(-1))) { + format = MessageFormat.format(configuration.getButtonCoinsCoinLine(), coin, + configuration.getButtonCoinsError()); + } else { + format = MessageFormat.format(configuration.getButtonCoinsCoinLine(), coin, + Formatter.formatServerCurrency(coinValue)); + } + coinsLine.add(format); + } + + //Adding the line of values to the lore + int index = 0; // FIXME: 16/05/2021 Duplicate code + String remove = null; + for (int i = 0; i < lore.size(); i++) { + String s = lore.get(i); + if (s.contains("{0}")) { + index = i; + remove = s; + } + } + lore.addAll(index, coinsLine); + if (remove != null) { + lore.remove(remove); + } + return lore; + } + + private Component ranking() { + return new Builder(XMaterial.PLAYER_HEAD).withDisplayName(configuration.getButtonRankingName()).withSlot(37) + .build(); + } +} diff --git a/src/main/java/net/epconsortium/cryptomarket/ui/frames/RankingFrame.java b/src/main/java/net/epconsortium/cryptomarket/ui/frames/RankingFrame.java new file mode 100644 index 0000000..6eb4360 --- /dev/null +++ b/src/main/java/net/epconsortium/cryptomarket/ui/frames/RankingFrame.java @@ -0,0 +1,143 @@ +package net.epconsortium.cryptomarket.ui.frames; + +import com.cryptomorin.xseries.XMaterial; +import net.epconsortium.cryptomarket.CryptoMarket; +import net.epconsortium.cryptomarket.database.dao.Investor; +import net.epconsortium.cryptomarket.finances.Economy; +import net.epconsortium.cryptomarket.finances.ExchangeRate; +import net.epconsortium.cryptomarket.ui.Component; +import net.epconsortium.cryptomarket.ui.ComponentImpl; +import net.epconsortium.cryptomarket.ui.Frame; +import net.epconsortium.cryptomarket.util.Configuration; +import net.epconsortium.cryptomarket.util.Formatter; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.math.BigDecimal; +import java.text.MessageFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ExecutionException; + +import static com.cryptomorin.xseries.XMaterial.*; +import static net.epconsortium.cryptomarket.ui.Components.addPanels; + +public class RankingFrame extends Frame { + private final CryptoMarket plugin = CryptoMarket.getInstance(); + + private final Economy econ; + private final List richersList; + private final double totalInvestments; + private final Configuration config; + + public RankingFrame(@Nullable Frame parent, @NotNull Player viewer) throws ExecutionException, InterruptedException { + super(parent, viewer); + config = new Configuration(plugin); + econ = plugin.getEconomy(); + richersList = econ.getTopInvestors(5); + totalInvestments = econ.getTotalInvestments(); + } + + @Override + public @NotNull String getTitle() { + return configuration.getRankingMenuName(); + } + + @Override + public int getSize() { + return 45; + } + + @Override + public void createComponents() { + addGlasses(); + add(backButton()); + add(totalInvestments()); + add(lastUpdated()); + for (int i = 0; i < 5; i++) { + add(richer(i, i + 20)); + } + } + + /** + * Configures the Richer on the index + * + * @param index index + * @return the Richer item + */ + private Component richer(int index, int slot) { + ItemStack head = XMaterial.PLAYER_HEAD.parseItem(true); + ItemMeta meta = Objects.requireNonNull(head).getItemMeta(); + int rank = index + 1; + + String displayName; + ArrayList lore = new ArrayList<>(); + if (index >= richersList.size()) { + displayName = MessageFormat.format(config.getRankingMenuNoRicherLore(), rank); + head.setItemMeta(meta); + } else { + Investor richer = richersList.get(index); + SkullMeta skullMeta = (SkullMeta) head.getItemMeta(); + skullMeta.setOwner(richer.getPlayer().getName()); + displayName = MessageFormat.format(config.getRankingMenuRicherItemName(), rank, richer.getPlayer().getName()); + + List configLore = config.getRankingMenuRicherItemLore(); + ExchangeRate exchangeRate = plugin.getExchangeRates().getExchangeRate(LocalDate.now()); + BigDecimal patrimony = richer.getConvertedPatrimony(exchangeRate); + double percentage = 0; + if (totalInvestments > 0) { + percentage = (patrimony.doubleValue() / totalInvestments) * 100; + } + for (String s : configLore) { + lore.add(MessageFormat.format(s, Formatter.formatServerCurrency(patrimony), + Formatter.formatPercentage(percentage))); + } + head.setItemMeta(skullMeta); + } + + return new ComponentImpl(displayName, lore, head, slot); + } + + private Component lastUpdated() { + List lastUpdateLore = new ArrayList<>(); + for (String s : config.getRankingMenuLastUpdatedItemLore()) { + lastUpdateLore.add(MessageFormat.format(s, + econ.getRichersLastUpdate().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)))); + } + return new ComponentImpl(config.getRankingMenuLastUpdatedItemName(), lastUpdateLore, CLOCK, 38); + } + + private Component totalInvestments() { + List totalLore = new ArrayList<>(); + for (String s : config.getRankingMenuTotalInvestmentsItemLore()) { + totalLore.add(MessageFormat.format(s, Formatter.formatServerCurrency(totalInvestments))); + } + + return new ComponentImpl(config.getRankingMenuTotalInvestmentsItemName(), totalLore, XMaterial.SUNFLOWER, 36); + } + + /** + * Configures the Back button + * + * @return the back button + */ + private Component backButton() { + return new ComponentImpl(config.getRankingMenuBackButton(), null, XMaterial.ARROW, 4); + } + + private void addGlasses() { + int[] blackSlots = {0, 3, 5, 8, 9, 11, 12, 14, 15, 17, 18, 19, 25, 26, 27, 29, 30, 32, 33, 35, 41, 39, 44}; + addPanels(this, BLACK_STAINED_GLASS_PANE, blackSlots); + + int[] greySlots = {1, 2, 6, 7, 10, 13, 16, 28, 31, 34, 37, 40, 42, 43}; + addPanels(this, GRAY_STAINED_GLASS_PANE, greySlots); + } +} diff --git a/src/main/java/net/epconsortium/cryptomarket/util/Configuration.java b/src/main/java/net/epconsortium/cryptomarket/util/Configuration.java index a9d4e1f..0b30586 100644 --- a/src/main/java/net/epconsortium/cryptomarket/util/Configuration.java +++ b/src/main/java/net/epconsortium/cryptomarket/util/Configuration.java @@ -145,12 +145,12 @@ public long getIntervalExchangeRatesUpdateInMillis() { } /** - * Returns the richers update interval in milliseconds + * Returns the richers update interval in ticks * * @return the interval */ - public long getIntervalRichersUpdateInMillis() { - return getConfig().getInt("richers-update-interval", 15) * 60 * 1000; + public long getIntervalRichersUpdateInTicks() { + return getConfig().getLong("richers-update-interval", 15) * 60 * 20; } /** @@ -531,7 +531,7 @@ public String getButtonProfitName() { * @return button name */ public String getButtonCalendarName() { - return getColoredString("menu.item.calendar", "Calendar"); + return getColoredString("menu.items.calendar", "Calendar"); } /** diff --git a/src/main/java/net/epconsortium/cryptomarket/util/Logger.java b/src/main/java/net/epconsortium/cryptomarket/util/Logger.java index c87d241..ced2322 100644 --- a/src/main/java/net/epconsortium/cryptomarket/util/Logger.java +++ b/src/main/java/net/epconsortium/cryptomarket/util/Logger.java @@ -15,7 +15,7 @@ import org.bukkit.scheduler.BukkitRunnable; /** - * This class logs the negociations to a file + * This class logs the negotiations to a file * * @author roinujnosde */ @@ -27,10 +27,8 @@ public class Logger { public Logger(CryptoMarket plugin) { this.plugin = Objects.requireNonNull(plugin); - logsFolder = new File(plugin.getDataFolder() + File.separator - + "logs"); - file = new File(logsFolder, - LocalDate.now() + ".txt"); + logsFolder = new File(plugin.getDataFolder() + File.separator + "logs"); + file = new File(logsFolder, LocalDate.now() + ".txt"); } /** @@ -42,8 +40,7 @@ public Logger(CryptoMarket plugin) { * @param coin * @param vaultValue */ - public void log(Investor investor, Negotiation negotiation, - BigDecimal cryptoValue, String coin, double vaultValue) { + public void log(Investor investor, Negotiation negotiation, BigDecimal cryptoValue, String coin, double vaultValue) { new BukkitRunnable() { @Override public void run() { @@ -63,7 +60,7 @@ public void run() { writer.flush(); } } catch (IOException ex) { - CryptoMarket.warn("Error logging a negociation to file!"); + CryptoMarket.warn("Error logging a negotiation to file!"); ex.printStackTrace(); } }