package com.craftbank.hooks; import com.craftbank.CraftBank; import com.craftbank.model.PlayerAccount; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** * XConomy PlaceholderAPI 兼容层, 让原有 %xconomy_*% 变量无需替换即可使用。 */ public final class XConomyExpansion extends PlaceholderExpansion { private static final int RANKING_SIZE = 100; private final CraftBank plugin; private final DecimalFormat numberFormat = new DecimalFormat("#,##0.00"); private final List> top = new CopyOnWriteArrayList<>(); private volatile double sumBalance; public XConomyExpansion(CraftBank plugin) { this.plugin = plugin; } @Override public @NotNull String getIdentifier() { return "xconomy"; } @Override public @NotNull String getAuthor() { return "CraftBank"; } @Override public @NotNull String getVersion() { return plugin.getDescription().getVersion(); } @Override public boolean persist() { return true; } @Override public String onRequest(OfflinePlayer player, @NotNull String identifier) { String id = identifier.toLowerCase(); if (id.equals("balance") || id.equals("balance_value") || id.equals("balance_formatted")) { double cash = getCash(player); return switch (id) { case "balance_value" -> decimal(cash); case "balance_formatted" -> formatCompact(cash); default -> formatDisplay(cash); }; } if (id.startsWith("top_player_")) { Integer index = parseIndex(id, "top_player_"); if (index == null) { return "[XConomy]Invalid index"; } return topName(index); } if (id.equals("top_rank") || id.startsWith("top_rank_")) { String name = id.equals("top_rank") ? (player == null ? null : player.getName()) : identifier.substring("top_rank_".length()); return rankOf(name); } if (id.startsWith("top_balance_formatted_")) { Integer index = parseIndex(id, "top_balance_formatted_"); return index == null ? "[XConomy]Invalid index" : topBalance(index, true, false); } if (id.startsWith("top_balance_value_")) { Integer index = parseIndex(id, "top_balance_value_"); return index == null ? "[XConomy]Invalid index" : topBalance(index, false, true); } if (id.startsWith("top_balance_")) { Integer index = parseIndex(id, "top_balance_"); return index == null ? "[XConomy]Invalid index" : topBalance(index, false, false); } if (id.contains("top_hidden")) { return "0"; } if (id.contains("paypermission")) { if (id.contains("_global")) { return "1"; } return player == null ? "Error" : "DEFAULT"; } if (id.equals("paytoggle")) { return player == null ? "Error" : "1"; } if (id.contains("sum_balance")) { return id.contains("sum_balance_value") ? decimal(sumBalance) : formatDisplay(sumBalance); } return null; } public void refreshCache() { top.clear(); top.addAll(plugin.getDatabaseManager().getTopCash(RANKING_SIZE)); sumBalance = plugin.getDatabaseManager().getTotalCash(); } private double getCash(OfflinePlayer player) { if (player == null) { return 0.0; } PlayerAccount account = plugin.getEconomyManager().getCached(player.getUniqueId()); return account == null ? 0.0 : account.getCash(); } private String topName(int oneBasedIndex) { if (oneBasedIndex > top.size()) { return "No data"; } return top.get(oneBasedIndex - 1).getKey(); } private String topBalance(int oneBasedIndex, boolean compact, boolean raw) { if (oneBasedIndex > top.size()) { return "No data"; } double balance = top.get(oneBasedIndex - 1).getValue(); if (raw) { return decimal(balance); } return compact ? formatCompact(balance) : formatDisplay(balance); } private String rankOf(String name) { if (name == null) { return "No data"; } for (int i = 0; i < top.size(); i++) { if (name.equalsIgnoreCase(top.get(i).getKey())) { return Integer.toString(i + 1); } } return "No data"; } private Integer parseIndex(String id, String prefix) { String value = id.substring(prefix.length()); if (!value.matches("\\d+") || value.matches("0+")) { return null; } return Integer.parseInt(value); } private String formatDisplay(double amount) { return ChatColor.translateAlternateColorCodes('&', numberFormat.format(amount) + " " + (round(amount).compareTo(BigDecimal.ONE) == 0 ? "dollar" : "dollars")); } private String formatCompact(double amount) { double abs = Math.abs(amount); if (abs >= 1_000_000.0) { return numberFormat.format(amount / 1_000_000.0) + "m dollars"; } if (abs >= 1_000.0) { return numberFormat.format(amount / 1_000.0) + "k dollars"; } return formatDisplay(amount); } private String decimal(double amount) { return round(amount).toString(); } private BigDecimal round(double amount) { return BigDecimal.valueOf(amount).setScale(2, RoundingMode.DOWN); } }