ATM.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. package de.Linus122.TimeIsMoney;
  2. import com.earth2me.essentials.api.Economy;
  3. import com.google.common.primitives.Doubles;
  4. import net.milkbowl.vault.economy.EconomyResponse;
  5. import net.milkbowl.vault.economy.EconomyResponse.ResponseType;
  6. import org.bukkit.Bukkit;
  7. import org.bukkit.Material;
  8. import org.bukkit.OfflinePlayer;
  9. import org.bukkit.World;
  10. import org.bukkit.block.Block;
  11. import org.bukkit.block.Sign;
  12. import org.bukkit.command.Command;
  13. import org.bukkit.command.CommandExecutor;
  14. import org.bukkit.command.CommandSender;
  15. import org.bukkit.configuration.file.YamlConfiguration;
  16. import org.bukkit.entity.Player;
  17. import org.bukkit.event.Event.Result;
  18. import org.bukkit.event.EventHandler;
  19. import org.bukkit.event.EventPriority;
  20. import org.bukkit.event.Listener;
  21. import org.bukkit.event.block.SignChangeEvent;
  22. import org.bukkit.event.inventory.InventoryClickEvent;
  23. import org.bukkit.event.inventory.InventoryCloseEvent;
  24. import org.bukkit.event.inventory.InventoryDragEvent;
  25. import org.bukkit.event.inventory.InventoryMoveItemEvent;
  26. import org.bukkit.event.player.PlayerInteractEvent;
  27. import org.bukkit.inventory.Inventory;
  28. import org.bukkit.inventory.ItemStack;
  29. import org.bukkit.inventory.meta.ItemMeta;
  30. import org.bukkit.plugin.Plugin;
  31. import java.io.File;
  32. import java.io.IOException;
  33. import java.util.ArrayList;
  34. import java.util.Arrays;
  35. import java.util.Comparator;
  36. import java.util.Iterator;
  37. import java.util.List;
  38. import java.util.Map;
  39. import java.util.Map.Entry;
  40. import java.util.stream.Collectors;
  41. import java.util.TreeMap;
  42. import static de.Linus122.TimeIsMoney.tools.Utils.CC;
  43. /**
  44. * ATM listener and command executor.
  45. *
  46. * @author Linus122
  47. * @since 1.9.6.1
  48. */
  49. public class ATM implements Listener, CommandExecutor {
  50. /**
  51. * The {@link Plugin}.
  52. */
  53. private final Plugin plugin;
  54. /**
  55. * The bank accounts {@link java.io.File} that stores all data.
  56. */
  57. private static final File bankAccountsFile = new File("plugins/TimeIsMoney/data.dat");
  58. /**
  59. * The bank accounts {@link org.bukkit.configuration.file.YamlConfiguration} to manage the {@link #bankAccountsFile}.
  60. */
  61. private static YamlConfiguration bankAccountsConfig;
  62. /**
  63. * The different amounts of money shown in the atm to withdraw and deposit (atm_worth_gradation).
  64. */
  65. private double[] worths = new double[4];
  66. private List<Inventory> openATMs = new ArrayList<Inventory>();
  67. final String atmSignLabel = Main.finalconfig.getString("atm_sign_label");
  68. /**
  69. * Creates a new atm instance with the {@link de.Linus122.TimeIsMoney.Main} class.
  70. *
  71. * @param plugin The {@link de.Linus122.TimeIsMoney.Main} class that implements {@link org.bukkit.plugin.java.JavaPlugin}.
  72. */
  73. public ATM(Main plugin) {
  74. this.plugin = plugin;
  75. plugin.getServer().getPluginManager().registerEvents(this, plugin);
  76. plugin.getCommand("atm").setExecutor(this);
  77. if (!bankAccountsFile.exists()) {
  78. try {
  79. bankAccountsFile.createNewFile();
  80. } catch (IOException e) {
  81. e.printStackTrace();
  82. }
  83. }
  84. bankAccountsConfig = YamlConfiguration.loadConfiguration(bankAccountsFile);
  85. worths = Doubles.toArray(Main.finalconfig.getDoubleList("atm_worth_gradation"));
  86. }
  87. /**
  88. * Withdraws the specified amount of money from the specified player's bank.
  89. *
  90. * @param player The player to withdraw money from.
  91. * @param amount The amount of money to withdraw.
  92. */
  93. private static void withdrawBank(Player player, double amount) {
  94. withdrawBank(player, player.getWorld(), amount);
  95. }
  96. private static void withdrawBank(OfflinePlayer offlinePlayer, World inWorld, double amount) {
  97. String bankString = getBankString(offlinePlayer, inWorld);
  98. if (!bankAccountsConfig.contains(bankString)) bankAccountsConfig.set(bankString, 0.0);
  99. bankAccountsConfig.set(bankString, getBankBalance(offlinePlayer, inWorld) - amount);
  100. saveBanks();
  101. }
  102. /**
  103. * Deposits the specified amount of money to the specified player's bank.
  104. *
  105. * @param player The player to deposit money to.
  106. * @param amount The amount of money to deposit.
  107. */
  108. public static void depositBank(Player player, double amount) {
  109. depositBank(player, player.getWorld(), amount);
  110. }
  111. public static void depositBank(OfflinePlayer offlinePlayer, World inWorld, double amount) {
  112. String bankString = getBankString(offlinePlayer, inWorld);
  113. if (!bankAccountsConfig.contains(bankString)) bankAccountsConfig.set(bankString, 0.0);
  114. bankAccountsConfig.set(bankString, getBankBalance(offlinePlayer, inWorld) + amount);
  115. saveBanks();
  116. }
  117. /**
  118. * Checks if the player has the specified amount of money in their bank.
  119. *
  120. * @param p The player to check the balance of.
  121. * @param amount The amount of money.
  122. * @return True if the player has the specified amount of money, false otherwise.
  123. */
  124. private static boolean bankHas(Player player, double amount) {
  125. return bankHas(player, player.getWorld(), amount);
  126. }
  127. private static boolean bankHas(OfflinePlayer offlinePlayer, World inWorld, double amount) {
  128. String bankString = getBankString(offlinePlayer, inWorld);
  129. if (!bankAccountsConfig.contains(bankString)) bankAccountsConfig.set(bankString, 0.0);
  130. return getBankBalance(offlinePlayer) >= amount;
  131. }
  132. /**
  133. * Gets the balance of the specified player's bank (doesn't support groups).
  134. *
  135. * @param offlinePlayer The offline player to get the balance of.
  136. * @return The offline player's balance in the bank.
  137. */
  138. public static double getBankBalance(OfflinePlayer offlinePlayer) {
  139. String bankString = offlinePlayer.getName() + "_TimBANK";
  140. if (!bankAccountsConfig.contains(bankString)) bankAccountsConfig.set(bankString, 0.0);
  141. return bankAccountsConfig.getDouble(bankString);
  142. }
  143. /**
  144. * Gets the balance of the specified player's bank.
  145. *
  146. * @param player The player to get the balance of.
  147. * @return The player's balance in the bank.
  148. */
  149. public static double getBankBalance(Player player) {
  150. return getBankBalance(player, player.getWorld());
  151. }
  152. public static double getBankBalance(OfflinePlayer offlinePlayer, World inWorld) {
  153. String bankString = getBankString(offlinePlayer, inWorld);
  154. if (!bankAccountsConfig.contains(bankString)) bankAccountsConfig.set(bankString, 0.0);
  155. return bankAccountsConfig.getDouble(bankString);
  156. }
  157. /**
  158. * Saves the banks.
  159. */
  160. private static void saveBanks() {
  161. try {
  162. bankAccountsConfig.save(bankAccountsFile);
  163. } catch (IOException e) {
  164. e.printStackTrace();
  165. }
  166. }
  167. /**
  168. * Converts the old TimeIsMoney bank data to the new format.
  169. *
  170. * @deprecated ancient method, will be deleted soon
  171. * @param p The player to convert data for.
  172. */
  173. @Deprecated
  174. private static void convertOldBank(Player p) {
  175. String bankString = getBankString(p, p.getWorld());
  176. if (Main.economy.hasAccount(bankString)) {
  177. if (Main.economy.getBalance(bankString) > 0) {
  178. p.sendMessage(CC("&aSuccessfully converted your old TIM-Bank to new version!"));
  179. depositBank(p, Main.economy.getBalance(bankString));
  180. Main.economy.withdrawPlayer(bankString, Main.economy.getBalance(bankString));
  181. }
  182. }
  183. }
  184. /**
  185. * Gets the bank string for the specified player.
  186. * Converts old bank accounts (those saved using the user name) to new bank accounts using UUID's.
  187. *
  188. * @param player The player to get the bank string of.
  189. * @param inWorld The World. Only needs to be specified when working with grouped ATM's (world-wise)
  190. * @return The bank string of the specified player.
  191. */
  192. private static String getBankString(OfflinePlayer player, World inWorld) {
  193. String oldBank = getBankStringByPrefix(player.getName(), inWorld);
  194. if(bankAccountsConfig.contains(oldBank)) {
  195. double oldMoneyAmount = bankAccountsConfig.getDouble(oldBank);
  196. bankAccountsConfig.set(getBankStringByPrefix(player.getUniqueId().toString(), inWorld), oldMoneyAmount);
  197. bankAccountsConfig.set(oldBank, null);
  198. }
  199. return getBankStringByPrefix(player.getUniqueId().toString(), inWorld);
  200. }
  201. /**
  202. * Returns the bank string of a player that is used internally for storing the money on.
  203. *
  204. * @param prefix The prefix to work with
  205. * @param inWorld The World. Only needs to be specified when working with grouped ATM's (world-wise)
  206. * @return The bank string of the specified player.
  207. */
  208. private static String getBankStringByPrefix(String prefix, World inWorld) {
  209. if (!Main.finalconfig.getBoolean("group-atms")) {
  210. return prefix + "_TimBANK";
  211. } else {
  212. for (String key : Main.finalconfig.getConfigurationSection("atm_groups").getKeys(false)) {
  213. List<String> list = Main.finalconfig.getStringList("atm_groups." + key);
  214. if (list.contains(inWorld.getName())) {
  215. return inWorld.getName() + "_TimBANK_" + key;
  216. }
  217. }
  218. }
  219. return prefix + "_TimBANK";
  220. }
  221. @EventHandler(priority = EventPriority.HIGHEST)
  222. public void onInteract(PlayerInteractEvent e) {
  223. if (e.getClickedBlock() != null) {
  224. if (e.getClickedBlock().getState() instanceof Sign) {
  225. Sign sign = (Sign) e.getClickedBlock().getState();
  226. if (sign.getLine(0).equalsIgnoreCase(CC(atmSignLabel))) {
  227. if (!e.getPlayer().hasPermission("tim.atm.use")) {
  228. e.getPlayer().sendMessage(CC(Main.finalconfig.getString("message_atm_noperms")));
  229. } else {
  230. this.openGUI(e.getPlayer());
  231. }
  232. }
  233. }
  234. }
  235. }
  236. @EventHandler
  237. public void onClose(InventoryCloseEvent e) {
  238. if (e.getInventory() != null)
  239. openATMs.remove(e.getInventory());
  240. }
  241. @EventHandler
  242. public void onMove(InventoryMoveItemEvent e) {
  243. if (e.getSource() == null || e.getSource().getViewers().size() == 0 || e.getSource().getViewers().get(0).getOpenInventory() == null) return;
  244. if (openATMs.contains(e.getSource().getViewers().get(0).getOpenInventory().getTopInventory())) {
  245. e.setCancelled(true);
  246. }
  247. }
  248. @SuppressWarnings("deprecation")
  249. @EventHandler
  250. public void onClick(InventoryClickEvent e) {
  251. try {
  252. if (e == null || e.getInventory() == null) return;
  253. if (openATMs.contains(e.getView().getTopInventory())) {
  254. e.setResult(Result.DENY);
  255. Player p = (Player) e.getWhoClicked();
  256. //e.setCancelled(true);
  257. if (e.getCurrentItem() != null) {
  258. // left side
  259. if (e.getSlot() < 4) {
  260. double amount = worths[3 - e.getSlot()];
  261. if (ATM.bankHas(p, amount)) {
  262. EconomyResponse response = Main.economy.depositPlayer(p, amount);
  263. if (response.type == ResponseType.SUCCESS) {
  264. ATM.withdrawBank(p, amount);
  265. e.getWhoClicked().sendMessage(CC(Main.finalconfig.getString("atm_withdraw")) + " " + Main.economy.format(amount));
  266. }
  267. } else {
  268. e.getWhoClicked().sendMessage(CC(Main.finalconfig.getString("message_atm_nomoneyinbank")));
  269. }
  270. } else {
  271. // right side
  272. if (e.getSlot() > 4) {
  273. double amount = worths[3 - (3 - (e.getSlot() - 5))];
  274. if (Main.economy.has((Player) e.getWhoClicked(), amount)) {
  275. ATM.depositBank(p, amount);
  276. Main.economy.withdrawPlayer((Player) e.getWhoClicked(), amount);
  277. e.getWhoClicked().sendMessage(CC(Main.finalconfig.getString("atm_deposit")) + " " + Main.economy.format(amount));
  278. } else {
  279. e.getWhoClicked().sendMessage(CC(Main.finalconfig.getString("message_atm_nomoney")));
  280. }
  281. }
  282. }
  283. // updating atm balance
  284. ItemStack is = new ItemStack(Material.GOLD_NUGGET, 1);
  285. ItemMeta im = is.getItemMeta();
  286. im.setDisplayName(CC(Main.finalconfig.getString("atm_balance")) + " " + Main.economy.format(ATM.getBankBalance(p)));
  287. is.setItemMeta(im);
  288. e.getInventory().setItem(4, is);
  289. }
  290. }
  291. } catch (Exception ignored) {
  292. }
  293. }
  294. /**
  295. * Opens the atm gui for the specified player.
  296. *
  297. * @param player The player to open the atm gui for.
  298. */
  299. private void openGUI(Player player) {
  300. if(worths.length == 0) {
  301. player.sendMessage("§cError in config.yml: atm_worth_gradation is empty.");
  302. return;
  303. }
  304. convertOldBank(player);
  305. Inventory atm_gui = Bukkit.createInventory(null, 9, CC(Main.finalconfig.getString("atm_title")));
  306. // Balance
  307. ItemStack is = new ItemStack(Material.GOLD_NUGGET, 1);
  308. ItemMeta im = is.getItemMeta();
  309. im.setDisplayName(CC(Main.finalconfig.getString("atm_balance")) + " " + Main.economy.format(ATM.getBankBalance(player)));
  310. is.setItemMeta(im);
  311. atm_gui.setItem(4, is);
  312. // Withdraw
  313. is = new ItemStack(Material.getMaterial("CLAY_BRICK"), 1);
  314. im = is.getItemMeta();
  315. im.setDisplayName(CC(Main.finalconfig.getString("atm_withdraw") + " &a") + Main.economy.format(worths[0]));
  316. is.setItemMeta(im);
  317. atm_gui.setItem(3, is);
  318. is = new ItemStack(Material.IRON_INGOT, 1);
  319. im = is.getItemMeta();
  320. im.setDisplayName(CC(Main.finalconfig.getString("atm_withdraw") + " &a") + Main.economy.format(worths[1]));
  321. is.setItemMeta(im);
  322. atm_gui.setItem(2, is);
  323. is = new ItemStack(Material.GOLD_INGOT, 1);
  324. im = is.getItemMeta();
  325. im.setDisplayName(CC(Main.finalconfig.getString("atm_withdraw") + " &a") + Main.economy.format(worths[2]));
  326. is.setItemMeta(im);
  327. atm_gui.setItem(1, is);
  328. is = new ItemStack(Material.DIAMOND, 1);
  329. im = is.getItemMeta();
  330. im.setDisplayName(CC(Main.finalconfig.getString("atm_withdraw") + " &a") + Main.economy.format(worths[3]));
  331. is.setItemMeta(im);
  332. atm_gui.setItem(0, is);
  333. // Deposit
  334. is = new ItemStack(Material.getMaterial("CLAY_BRICK"), 1);
  335. im = is.getItemMeta();
  336. im.setDisplayName(CC(Main.finalconfig.getString("atm_deposit") + " &4") + Main.economy.format(worths[0]));
  337. is.setItemMeta(im);
  338. atm_gui.setItem(5, is);
  339. //
  340. is = new ItemStack(Material.IRON_INGOT, 1);
  341. im = is.getItemMeta();
  342. im.setDisplayName(CC(Main.finalconfig.getString("atm_deposit") + " &4") + Main.economy.format(worths[1]));
  343. is.setItemMeta(im);
  344. atm_gui.setItem(6, is);
  345. //
  346. is = new ItemStack(Material.GOLD_INGOT, 1);
  347. im = is.getItemMeta();
  348. im.setDisplayName(CC(Main.finalconfig.getString("atm_deposit") + " &4") + Main.economy.format(worths[2]));
  349. is.setItemMeta(im);
  350. atm_gui.setItem(7, is);
  351. //
  352. is = new ItemStack(Material.DIAMOND, 1);
  353. im = is.getItemMeta();
  354. im.setDisplayName(CC(Main.finalconfig.getString("atm_deposit") + " &4") + Main.economy.format(worths[3]));
  355. is.setItemMeta(im);
  356. atm_gui.setItem(8, is);
  357. openATMs.add(atm_gui);
  358. player.openInventory(atm_gui);
  359. }
  360. @EventHandler
  361. public void onInventoryDrag(InventoryDragEvent e) {
  362. if (e == null || e.getInventory() == null) return;
  363. if (openATMs.contains(e.getView().getTopInventory())) {
  364. e.setResult(Result.DENY);
  365. }
  366. }
  367. @EventHandler
  368. public void onSignChange(final SignChangeEvent e) {
  369. final Block b = e.getBlock();
  370. if (b.getState() instanceof Sign) {
  371. plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
  372. if (b.getState() instanceof Sign) {
  373. Sign sign = (Sign) e.getBlock().getState();
  374. if (sign.getLine(0).equalsIgnoreCase("[ATM]") || sign.getLine(0).equalsIgnoreCase(atmSignLabel) || sign.getLine(0).equalsIgnoreCase(CC(atmSignLabel))) {
  375. if (!e.getPlayer().hasPermission("tim.atm.place")) {
  376. e.getPlayer().sendMessage(CC("&cYou dont have permissions to build ATM's (tim.atm.place)"));
  377. sign.setLine(0, "");
  378. } else {
  379. sign.setLine(0, CC(atmSignLabel));
  380. sign.update();
  381. e.getPlayer().sendMessage(CC("&2ATM created! (You can also write something in the Lines 2-4)"));
  382. }
  383. }
  384. }
  385. }, 10L);
  386. }
  387. }
  388. @Override
  389. public boolean onCommand(CommandSender cs, Command arg1, String arg2, String[] args) {
  390. if (args.length == 0) {
  391. if (!(cs instanceof Player)) {
  392. cs.sendMessage("Only players can use atms.");
  393. return true;
  394. }
  395. if (cs.hasPermission("tim.use")) {
  396. openGUI((Player) cs);
  397. return true;
  398. }
  399. }
  400. if (cs.hasPermission("tim.admin")) {
  401. if (args.length > 0) {
  402. switch (args[0]) {
  403. case "balance":
  404. if (args.length > 1) {
  405. cs.sendMessage(CC("&2ATM-Balance of&c " + args[1] + "&2: &c") + getBankBalance(Bukkit.getOfflinePlayer(args[1])));
  406. } else {
  407. cs.sendMessage("/atm balance <player>");
  408. }
  409. break;
  410. case "balancetop":
  411. cs.sendMessage("§cTop Bank Accounts:");
  412. Map<String, Double> topBal = new TreeMap<String, Double>();
  413. for (String keyBankString : bankAccountsConfig.getKeys(false)) {
  414. double amount = bankAccountsConfig.getDouble(keyBankString);
  415. topBal.put(keyBankString, amount);
  416. }
  417. topBal.entrySet().stream().
  418. sorted(Entry.comparingByValue(Comparator.reverseOrder())).limit(10).forEachOrdered(entry -> cs.sendMessage("§a" + entry.getKey() + "§2: " + Main.economy.format(entry.getValue())));
  419. break;
  420. case "take":
  421. if(args.length > 2) {
  422. OfflinePlayer playerToTake = Bukkit.getOfflinePlayer(args[1]);
  423. String inWorld = args.length > 3 ? args[3] : "world";
  424. if(playerToTake == null) {
  425. cs.sendMessage("§cThis player does not exists");
  426. return true;
  427. }
  428. try {
  429. double amount = Double.parseDouble(args[2]);
  430. double bal = ATM.getBankBalance(playerToTake);
  431. if(amount > bal) {
  432. cs.sendMessage("§cAmount to high! Player only has " + Economy.format(bal));
  433. return true;
  434. }
  435. ATM.withdrawBank(playerToTake, Bukkit.getWorld(inWorld), amount);
  436. cs.sendMessage("§aWithdrew §2" + Economy.format(amount) + ".");
  437. }catch(NumberFormatException e) {
  438. cs.sendMessage("§cPlease enter a valid decimal");
  439. }
  440. }else {
  441. cs.sendMessage("§c/tim take <player> <amount> [world]");
  442. }
  443. break;
  444. case "give":
  445. if(args.length > 2) {
  446. OfflinePlayer playerToGive = Bukkit.getOfflinePlayer(args[1]);
  447. String inWorld = args.length > 3 ? args[3] : "world";
  448. if(playerToGive == null) {
  449. cs.sendMessage("§cThis player does not exists");
  450. return true;
  451. }
  452. try {
  453. double amount = Double.parseDouble(args[2]);
  454. double bal = ATM.getBankBalance(playerToGive);
  455. ATM.depositBank(playerToGive, Bukkit.getWorld(inWorld), amount);
  456. cs.sendMessage("§aDeposited §2" + Economy.format(amount) + ".");
  457. }catch(NumberFormatException e) {
  458. cs.sendMessage("§cPlease enter a valid decimal");
  459. }
  460. }else {
  461. cs.sendMessage("§c/tim give <player> <amount> [world]");
  462. }
  463. break;
  464. default:
  465. @SuppressWarnings("deprecation")
  466. OfflinePlayer op = Bukkit.getOfflinePlayer(args[0]);
  467. if (op == null) {
  468. cs.sendMessage("Player is offline");
  469. return true;
  470. }
  471. if (op.isOnline()) {
  472. openGUI(op.getPlayer());
  473. cs.sendMessage("opened!");
  474. return true;
  475. }
  476. cs.sendMessage(CC("&c/atm <player> &a- opens atm for player"));
  477. cs.sendMessage(CC("&c/atm balance <player> &a- gets balance of player"));
  478. cs.sendMessage(CC("&c/atm balancetop - Shows the top 10 player atm balances"));
  479. cs.sendMessage(CC("&c/atm give <player> [world] &a- Deposits money into a players atm"));
  480. cs.sendMessage(CC("&c/atm take <player> [world] &a- Withdraws money from a players atm"));
  481. break;
  482. }
  483. }
  484. }
  485. return true;
  486. }
  487. }