ATM.java 18 KB

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