package com.librewiki.coalgov.command; import com.librewiki.coalgov.CoalGovPlugin; import com.librewiki.coalgov.model.Fine; import com.librewiki.coalgov.util.CoalMoney; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import java.sql.SQLException; import java.util.List; public final class CoalCommand implements CommandExecutor { private final CoalGovPlugin plugin; public CoalCommand(CoalGovPlugin plugin) { this.plugin = plugin; } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (!(sender instanceof Player player)) { sender.sendMessage("Players only."); return true; } if (args.length == 0) { player.sendMessage(plugin.messages().text("&eUsage: /coal ")); return true; } try { plugin.economyService().ensurePlayer(player); switch (args[0].toLowerCase()) { case "balance" -> balance(player); case "deposit" -> deposit(player); case "withdraw" -> withdraw(player, args); case "pay" -> pay(player, args); case "fines" -> fines(player, args); case "networth" -> networth(player); case "lottery" -> lottery(player, args); default -> player.sendMessage(plugin.messages().text("&eUsage: /coal ")); } } catch (SQLException exception) { plugin.getLogger().warning("Coal command failed: " + exception.getMessage()); player.sendMessage(plugin.messages().text("&cCoal ledger unavailable.")); } return true; } private void balance(Player player) throws SQLException { player.sendMessage(plugin.messages().text("&eBalance: &f" + CoalMoney.format(plugin.economyService().balance(player.getUniqueId())))); } private void networth(Player player) throws SQLException { long balance = plugin.economyService().balance(player.getUniqueId()); long inventory = 0L; for (ItemStack item : player.getInventory().getStorageContents()) { if (item == null || item.getType().isAir()) { continue; } Double price = plugin.marketService().basePrices().get(item.getType()); if (price != null) { inventory += CoalMoney.fromCoal(price * item.getAmount()); } } long claims = plugin.claimService().list(player.getUniqueId()).stream() .mapToLong(plugin.claimService()::claimPurchaseCost) .filter(value -> value > 0L) .sum(); long total = balance + inventory + claims; player.sendMessage(plugin.messages().text("&eNet worth: &f" + CoalMoney.format(total))); player.sendMessage(plugin.messages().text("&7Balance: &f" + CoalMoney.format(balance) + " &7Inventory: &f" + CoalMoney.format(inventory) + " &7Claims: &f" + CoalMoney.format(claims))); } private void deposit(Player player) throws SQLException { boolean coalEnabled = plugin.getConfig().getBoolean("economy.deposit_coal", true); boolean blocksEnabled = plugin.getConfig().getBoolean("economy.deposit_coal_blocks", true); long credit = 0; for (ItemStack item : player.getInventory().getContents()) { if (item == null) { continue; } if (coalEnabled && item.getType() == Material.COAL) { credit += item.getAmount() * CoalMoney.CENTS_PER_COAL; item.setAmount(0); } else if (blocksEnabled && item.getType() == Material.COAL_BLOCK) { credit += item.getAmount() * 9L * CoalMoney.CENTS_PER_COAL; item.setAmount(0); } } if (credit <= 0) { player.sendMessage(plugin.messages().text("&cNo depositable coal found.")); return; } plugin.economyService().deposit(player.getUniqueId(), credit); player.sendMessage(plugin.messages().text("&aDeposited &f" + CoalMoney.format(credit) + "&a.")); } private void withdraw(Player player, String[] args) throws SQLException { if (args.length != 2) { player.sendMessage(plugin.messages().text("&eUsage: /coal withdraw ")); return; } long amount = CoalMoney.parsePositive(args[1]); if (amount <= 0) { player.sendMessage(plugin.messages().text("&cAmount must be greater than zero.")); return; } if (amount % CoalMoney.CENTS_PER_COAL != 0L) { player.sendMessage(plugin.messages().text("&cWithdrawals must be whole coal because they create coal items.")); return; } long coalItems = amount / CoalMoney.CENTS_PER_COAL; if (plugin.economyService().balance(player.getUniqueId()) < amount) { player.sendMessage(plugin.messages().text("&cBalance too low.")); return; } if (!canFitCoal(player, coalItems)) { player.sendMessage(plugin.messages().text("&cYou need more inventory space.")); return; } if (!plugin.economyService().withdraw(player.getUniqueId(), amount)) { player.sendMessage(plugin.messages().text("&cBalance too low.")); return; } long remaining = coalItems; while (remaining > 0) { int stack = (int) Math.min(Material.COAL.getMaxStackSize(), remaining); player.getInventory().addItem(new ItemStack(Material.COAL, stack)); remaining -= stack; } player.sendMessage(plugin.messages().text("&aWithdrew &f" + CoalMoney.format(amount) + "&a.")); } private void pay(Player player, String[] args) throws SQLException { if (args.length != 3) { player.sendMessage(plugin.messages().text("&eUsage: /coal pay ")); return; } Player target = Bukkit.getPlayerExact(args[1]); if (target == null) { player.sendMessage(plugin.messages().text("&cThat player must be online.")); return; } long amount = CoalMoney.parsePositive(args[2]); if (amount <= 0) { player.sendMessage(plugin.messages().text("&cAmount must be greater than zero.")); return; } plugin.economyService().ensurePlayer(target); if (!plugin.economyService().pay(player.getUniqueId(), target.getUniqueId(), amount)) { player.sendMessage(plugin.messages().text("&cPayment failed. Check your balance.")); return; } player.sendMessage(plugin.messages().text("&aPaid &f" + CoalMoney.format(amount) + " &ato " + target.getName() + ".")); target.sendMessage(plugin.messages().text("&aReceived &f" + CoalMoney.format(amount) + " &afrom " + player.getName() + ".")); } private void fines(Player player, String[] args) throws SQLException { if (args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase("list"))) { List fines = plugin.governmentService().unpaidFines(player.getUniqueId()); if (fines.isEmpty()) { player.sendMessage(plugin.messages().text("&aYou have no unpaid fines.")); return; } long total = fines.stream().mapToLong(Fine::amount).sum(); player.sendMessage(plugin.messages().text("&eUnpaid fines: &f" + CoalMoney.format(total) + " &etotal")); for (Fine fine : fines) { player.sendMessage(plugin.messages().raw("&7#" + fine.id() + " &f" + CoalMoney.format(fine.amount()) + " &7" + fine.reason())); } player.sendMessage(plugin.messages().text("&7Use &f/coal fines pay &7.")); return; } if (args.length == 3 && args[1].equalsIgnoreCase("pay")) { if (args[2].equalsIgnoreCase("all")) { var result = plugin.governmentService().payAllFines(player.getUniqueId()); if (!result.success()) { player.sendMessage(plugin.messages().text("&c" + result.message())); return; } player.sendMessage(plugin.messages().text("&aPaid &f" + CoalMoney.format(result.amount()) + " &ain fines.")); return; } long id = parsePositive(args[2]); if (id <= 0L) { player.sendMessage(plugin.messages().text("&cInvalid fine id.")); return; } var result = plugin.governmentService().payFine(player.getUniqueId(), id); if (!result.success()) { player.sendMessage(plugin.messages().text("&c" + result.message())); return; } player.sendMessage(plugin.messages().text("&aPaid fine #" + id + " for &f" + CoalMoney.format(result.amount()) + "&a.")); return; } player.sendMessage(plugin.messages().text("&eUsage: /coal fines [list|pay ]")); } private void lottery(Player player, String[] args) throws SQLException { if (args.length == 1 || (args.length == 2 && args[1].equalsIgnoreCase("status"))) { var status = plugin.lotteryService().status(); player.sendMessage(plugin.messages().text("&eLottery round #" + status.round() + ": &f" + status.tickets() + " &etickets from &f" + status.players() + " &eplayers. Pot: &f" + CoalMoney.format(status.pot()))); return; } if (args.length == 2 && args[1].equalsIgnoreCase("buy")) { buyLottery(player, 1); return; } if (args.length == 3 && args[1].equalsIgnoreCase("buy")) { int tickets = (int) parsePositive(args[2]); buyLottery(player, tickets); return; } if (args.length == 2 && args[1].equalsIgnoreCase("draw")) { if (!player.hasPermission("coalgov.admin")) { player.sendMessage(plugin.messages().text("&cOnly CoalGov admins can draw the lottery.")); return; } var result = plugin.lotteryService().draw(); if (!result.success()) { player.sendMessage(plugin.messages().text("&c" + result.message())); return; } Bukkit.broadcastMessage(plugin.messages().text("&6Lottery round #" + result.round() + " won by &f" + result.winnerName() + " &6for &f" + CoalMoney.format(result.pot()) + " &6from &f" + result.tickets() + " &6tickets.")); return; } player.sendMessage(plugin.messages().text("&eUsage: /coal lottery ")); } private void buyLottery(Player player, int tickets) throws SQLException { var result = plugin.lotteryService().buy(player, tickets); if (!result.success()) { player.sendMessage(plugin.messages().text("&c" + result.message())); return; } player.sendMessage(plugin.messages().text("&aBought &f" + result.tickets() + " &alottery ticket(s) for &f" + CoalMoney.format(result.cost()) + " &ain round #" + result.round() + ".")); } private boolean canFitCoal(Player player, long amount) { if (amount > Integer.MAX_VALUE) { return false; } long capacity = 0; for (ItemStack item : player.getInventory().getStorageContents()) { if (item == null || item.getType().isAir()) { capacity += Material.COAL.getMaxStackSize(); } else if (item.getType() == Material.COAL) { capacity += Material.COAL.getMaxStackSize() - item.getAmount(); } if (capacity >= amount) { return true; } } return false; } private long parsePositive(String raw) { try { return Long.parseLong(raw); } catch (NumberFormatException exception) { return -1L; } } }