经济系统
经济是网游的骨架——有"赚"和"花",玩家才有目标。这一篇讲怎么自己实现一个经济系统,以及如何接入 Vault 生态。
自己实现 vs 接 Vault
| 方案 | 适合 |
|---|---|
| 接 Vault + 现成经济插件 | 正式服,求稳 |
| 自己实现经济 | 学习、或需求特殊(多种货币、绑定玩法) |
强烈建议先接 Vault
自己写经济 90% 的场景不如用 Vault 生态。它和 EssentialsX、商店插件、点券插件全打通。只有当你需要"打怪掉金币且金币是玩法核心"这种深度绑定时,才考虑自己写。
数据结构
最简模型:每个玩家一个余额。用 Map<UUID, Double> 存内存,定期落盘:
java
public class EconomyManager {
private final Map<UUID, Double> balances = new HashMap<>();
private final JavaPlugin plugin;
public EconomyManager(JavaPlugin plugin) {
this.plugin = plugin;
loadAll(); // 启动时从配置读入
}
public double getBalance(UUID id) {
return balances.getOrDefault(id, 0.0);
}
public void setBalance(UUID id, double amount) {
balances.put(id, amount);
}
public boolean withdraw(UUID id, double amount) {
double cur = getBalance(id);
if (cur < amount) return false; // 余额不足
setBalance(id, cur - amount);
return true;
}
public void deposit(UUID id, double amount) {
setBalance(id, getBalance(id) + amount);
}
}持久化
内存数据重启就丢。两种存法:
配置文件(小服)
java
public void saveAll() {
FileConfiguration cfg = new YamlConfiguration();
for (Map.Entry<UUID, Double> e : balances.entrySet()) {
cfg.set(e.getKey().toString(), e.getValue());
}
try {
cfg.save(new File(plugin.getDataFolder(), "balances.yml"));
} catch (IOException ex) {
plugin.getLogger().warning("保存经济数据失败: " + ex);
}
}定时保存 + 关服保存
别等关服才存——崩服会丢数据。用 runTaskTimer 每 5 分钟存一次,onDisable 再存一次:
数据库(中大型服)
玩家多了 balances.yml 会很大、读写慢。上 MySQL/Redis,见数据持久化。
并发安全
余额操作的竞态
两个线程同时给同一玩家扣钱,可能都读到旧余额、都扣成功,实际只扣了一次。经济操作必须加锁或用原子操作:
java
public synchronized boolean withdraw(UUID id, double amount) {
double cur = getBalance(id);
if (cur < amount) return false;
balances.put(id, cur - amount);
return true;
}synchronized 保证同一时刻只有一个线程能改。异步线程操作经济时尤其要注意。
接入 Vault
若用 Vault,你的插件不用自己管余额,调 Vault API:
java
// 获取 Vault 经济
RegisteredServiceProvider<Economy> rsp = Bukkit.getServicesManager().getRegistration(Economy.class);
Economy econ = rsp.getProvider();
// 查余额、扣钱、给钱
econ.getBalance(player);
econ.withdrawPlayer(player, 50);
econ.depositPlayer(player, 100);自己实现也要注册到 Vault
如果你自己写经济、又想兼容其他插件(商店、点券),把你的经济注册成 Vault 的 Economy provider,这样别的插件通过 Vault 调你的实现。实现 Economy 接口 + servicesManager.register。
玩法集成
经济要和玩法挂钩才有意义:
- 赚:打怪掉钱、卖物给 NPC、任务奖励、签到
- 花:商店买东西、升级技能、传送、开宝箱
打怪掉钱示例(监听怪物死亡):
java
@EventHandler
public void onMobDeath(EntityDeathEvent e) {
Player killer = e.getEntity().getKiller();
if (killer == null) return;
double reward = getReward(e.getEntityType()); // 按怪物类型给钱
econ.deposit(killer.getUniqueId(), reward);
killer.sendMessage(ChatColor.GREEN + "+" + reward + " 金币");
}常见坑
- 小数精度:
double算钱有精度问题(0.1+0.2≠0.3)。正式经济建议用整数(分)或BigDecimal - 通货膨胀:只赚不花,金币越来越不值钱。要有消耗出口(修理、税收、限时商店)
- 初始金额:新玩家给多少起步?太多没动力,太少卡体验
- 多货币:金币、钻石、点券——别用一个 Map 硬塞,设计成多账户
下一篇等级与职业。
