package com.craftbank.items; import com.craftbank.CraftBank; import com.craftbank.model.PlayerAccount; import com.craftbank.util.Text; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * 银行卡实体物品的创建与校验。银行卡通过 PDC 绑定持卡人 UUID 与序列号, * 序列号用于挂失/补办: 旧卡序列号与账户当前序列号不符即作废。 */ public class BankCardManager { private final CraftBank plugin; private final Keys keys; public BankCardManager(CraftBank plugin) { this.plugin = plugin; this.keys = plugin.getKeys(); } /** * 为玩家签发一张新银行卡, 并更新账户的有效序列号 (旧卡随之作废)。 */ public ItemStack issueCard(Player player, PlayerAccount account) { long serial = System.currentTimeMillis(); account.setCardSerial(serial); plugin.persistAsync(account); return buildCard(player.getName(), player.getUniqueId(), serial); } private ItemStack buildCard(String ownerName, UUID owner, long serial) { Material material = parseMaterial(plugin.getConfig().getString("Items.bank_card.material", "PAPER"), Material.PAPER); ItemStack item = new ItemStack(material); ItemMeta meta = item.getItemMeta(); if (meta == null) { return item; } String name = plugin.getConfig().getString("Items.bank_card.name", "&b工艺银行 · 储蓄卡"); meta.setDisplayName(Text.color(name.replace("%owner%", ownerName == null ? "?" : ownerName))); List lore = new ArrayList<>(); for (String line : plugin.getConfig().getStringList("Items.bank_card.lore")) { lore.add(Text.color(line.replace("%owner%", ownerName == null ? "?" : ownerName))); } meta.setLore(lore); int cmd = plugin.getConfig().getInt("Items.bank_card.custom_model_data", 0); if (cmd > 0) { meta.setCustomModelData(cmd); } PersistentDataContainer pdc = meta.getPersistentDataContainer(); pdc.set(keys.cardOwner, PersistentDataType.STRING, owner.toString()); pdc.set(keys.cardSerial, PersistentDataType.LONG, serial); item.setItemMeta(meta); return item; } public boolean isCard(ItemStack item) { if (item == null) { return false; } ItemMeta meta = item.getItemMeta(); return meta != null && meta.getPersistentDataContainer().has(keys.cardOwner, PersistentDataType.STRING); } public UUID getOwner(ItemStack item) { ItemMeta meta = item.getItemMeta(); if (meta == null) { return null; } String raw = meta.getPersistentDataContainer().get(keys.cardOwner, PersistentDataType.STRING); if (raw == null) { return null; } try { return UUID.fromString(raw); } catch (IllegalArgumentException ex) { return null; } } public long getSerial(ItemStack item) { ItemMeta meta = item.getItemMeta(); if (meta == null) { return 0; } Long serial = meta.getPersistentDataContainer().get(keys.cardSerial, PersistentDataType.LONG); return serial == null ? 0 : serial; } /** 银行卡是否仍然有效 (持卡人匹配且序列号未被挂失作废)。 */ public boolean isValid(ItemStack item, PlayerAccount account) { if (account == null || !isCard(item)) { return false; } UUID owner = getOwner(item); return account.getUuid().equals(owner) && account.hasValidCard() && account.getCardSerial() == getSerial(item); } private Material parseMaterial(String name, Material def) { if (name == null) { return def; } Material m = Material.matchMaterial(name.toUpperCase()); return m == null ? def : m; } }