eddc706c9a
实现完整的现金/钱包、银行卡、支票、活期储蓄与定期存款系统, 实现并以 Highest 优先级注册 Vault Economy 接口,接入 PlaceholderAPI。 全程遵循 Folia 调度模型(AsyncScheduler / 实体区域线程), 数据缓存线程安全,支票兑现与定期领取做防刷处理。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
123 lines
4.2 KiB
Java
123 lines
4.2 KiB
Java
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<String> 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;
|
|
}
|
|
}
|