commit dd2ecca1a897af21c589626da8fa64044bce0e20
Author: MiniDay <372403923@qq.com>
Date: Fri Sep 10 22:52:05 2021 +0800
Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bb84fa3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/.gradle
+/.idea
+/build
+*/build
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c7b598b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 叁只仓鼠
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.MD b/README.MD
new file mode 100644
index 0000000..07f020e
--- /dev/null
+++ b/README.MD
@@ -0,0 +1,63 @@
+# HamsterCurrency
+
+[](https://jitpack.io/#cn.hamster3/HamsterCurrency)
+仓鼠的多货币经济插件
+
+# 依赖前置
+
+- [HamsterAPI](https://github.com/MiniDay/HamsterAPI/releases)
+- [HamsterService](https://github.com/MiniDay/HamsterService/releases) (仅跨服模式需要)
+- [Vault](https://www.spigotmc.org/resources/vault.34315/) (仅开启Vault经济系统时需要)
+- [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.6245/) (非必须)
+
+# 开发者
+
+## 依赖导入
+
+### Maven
+
+添加仓库:
+
+```xml
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+```
+
+添加导入:
+
+```xml
+
+ cn.hamster3
+ HamsterCurrency
+ 2.0.6-SNAPSHOT
+
+```
+
+### Gradle
+
+添加仓库:
+
+```groovy
+allprojects {
+ repositories {
+ maven { url 'https://jitpack.io' }
+ }
+}
+```
+
+添加导入:
+
+```groovy
+dependencies {
+ implementation 'cn.hamster3:HamsterCurrency:1.3.7-SNAPSHOT'
+}
+```
+
+## API
+
+请参考[CurrencyAPI](/currency-plugin/src/main/java/cn/hamster3/currency/api/CurrencyAPI.java)
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..e69de29
diff --git a/currency-plugin/build.gradle b/currency-plugin/build.gradle
new file mode 100644
index 0000000..243618e
--- /dev/null
+++ b/currency-plugin/build.gradle
@@ -0,0 +1,42 @@
+plugins {
+ id 'java'
+}
+
+group 'cn.hamster3'
+version '2.0.6-SNAPSHOT'
+
+repositories {
+ maven {
+ url = "https://maven.airgame.net/repository/maven-public/"
+ }
+ maven {
+ url = "https://repo.codemc.org/repository/maven-public"
+ }
+}
+
+dependencies {
+ compileOnly "org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT"
+ // https://mvnrepository.com/artifact/org.jetbrains/annotations
+ compileOnly group: 'org.jetbrains', name: 'annotations', version: '22.0.0'
+ compileOnly "cn.hamster3:HamsterService-Bukkit:2.6.2-SNAPSHOT"
+ compileOnly "cn.hamster3:HamsterAPI:2.4.0-SNAPSHOT"
+ compileOnly "com.github.MilkBowl:VaultAPI:1.7"
+ compileOnly "org.black_ixx:PlayerPoints:2.1.3"
+ compileOnly "me.clip:placeholderapi:2.10.9"
+}
+
+processResources {
+ filesMatching("plugin.yml") {
+ expand "version": project.version
+ }
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+jar {
+ archivesBaseName = "HamsterCurrency"
+ destinationDir(rootProject.buildDir)
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/HamsterCurrency.java b/currency-plugin/src/main/java/cn/hamster3/currency/HamsterCurrency.java
new file mode 100644
index 0000000..b58ba8c
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/HamsterCurrency.java
@@ -0,0 +1,159 @@
+package cn.hamster3.currency;
+
+import cn.hamster3.api.utils.LogUtils;
+import cn.hamster3.currency.api.CurrencyAPI;
+import cn.hamster3.currency.command.currency.CurrencyCommand;
+import cn.hamster3.currency.command.vault.VaultCommand;
+import cn.hamster3.currency.command.vault.VaultPayCommand;
+import cn.hamster3.currency.command.vault.VaultSeeCommand;
+import cn.hamster3.currency.command.vault.VaultTopCommand;
+import cn.hamster3.currency.core.FileDataManager;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.SQLDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.hook.PlaceholderHook;
+import cn.hamster3.currency.hook.VaultEconomyHook;
+import cn.hamster3.currency.listener.CurrencyListener;
+import cn.hamster3.currency.listener.SQLListener;
+import cn.hamster3.service.bukkit.api.ServiceMessageAPI;
+import net.milkbowl.vault.economy.Economy;
+import org.bukkit.Bukkit;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.ServicePriority;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.sql.SQLException;
+
+public final class HamsterCurrency extends JavaPlugin {
+ private static LogUtils logUtils;
+ private IDataManager dataManager;
+ private CurrencyListener listener;
+ private boolean loaded;
+
+ public static LogUtils getLogUtils() {
+ return logUtils;
+ }
+
+ @Override
+ public void onLoad() {
+ FileManager.reload(this);
+ logUtils = new LogUtils(this);
+ logUtils.infoDividingLine();
+ if (FileManager.isUseBC()) {
+ logUtils.info("使用多服务器模式...");
+ try {
+ SQLDataManager sqlDataManager = new SQLDataManager(this);
+ logUtils.info("SQL存档管理器初始化完成!");
+ listener = new SQLListener(this, sqlDataManager);
+ logUtils.info("事件监听器初始化完成!");
+ dataManager = sqlDataManager;
+ } catch (SQLException | ClassNotFoundException e) {
+ logUtils.error(e, "插件加载时遇到了一个错误: ");
+ loaded = false;
+ }
+ } else {
+ logUtils.info("使用单服务器模式...");
+ FileDataManager fileDataManager = new FileDataManager(this);
+ logUtils.info("文件存档管理器初始化完成!");
+ listener = new CurrencyListener(this, fileDataManager);
+ logUtils.info("事件监听器初始化完成!");
+ dataManager = fileDataManager;
+ }
+ CurrencyAPI.setDataManager(dataManager);
+ logUtils.info("API初始化完成!");
+ loaded = true;
+ logUtils.infoDividingLine();
+ }
+
+ @Override
+ public void onEnable() {
+ logUtils.infoDividingLine();
+ if (!loaded) {
+ logUtils.warning("插件未能成功启动!");
+ setEnabled(false);
+ return;
+ }
+
+ dataManager.loadConfig();
+
+ PluginCommand command = getCommand("HamsterCurrency");
+ new CurrencyCommand(command, dataManager);
+ logUtils.info("插件命令已注册!");
+
+ Bukkit.getPluginManager().registerEvents(listener, this);
+ logUtils.info("事件监听器已注册!");
+
+ registerVault();
+
+ Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
+ dataManager.onEnable();
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ dataManager.loadPlayerData(player.getUniqueId());
+ }
+ if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
+ logUtils.info("检测到 PlaceholderAPI 已启动...");
+ new PlaceholderHook(dataManager).register();
+ logUtils.info("已挂载 PlaceholderAPI 变量!");
+ } else {
+ logUtils.info("未检测到 PlaceholderAPI!");
+ }
+ });
+
+ ServiceMessageAPI.subscribeTag("HamsterCurrency");
+
+ logUtils.info("插件已启动!");
+ logUtils.infoDividingLine();
+ }
+
+ private void registerVault() {
+ logUtils.infoDividingLine();
+
+ if (!FileManager.isVaultHook()) {
+ Bukkit.getServicesManager().unregister(this);
+ logUtils.info("不使用Vault经济系统挂接...");
+ return;
+ }
+
+ if (!Bukkit.getPluginManager().isPluginEnabled("Vault")) {
+ logUtils.warning("未找到 Vault 插件! 取消注册Vault经济系统...");
+ return;
+ }
+
+ String type = FileManager.getVaultCurrencyType();
+ logUtils.info("尝试以 %s 注册Vault经济系统...", type);
+
+ CurrencyType currencyType = dataManager.getCurrencyType(type);
+ if (currencyType == null) {
+ logUtils.warning("未找到经济类型 %s! 取消注册Vault经济系统...", type);
+ return;
+ }
+
+ VaultEconomyHook hook = new VaultEconomyHook(dataManager);
+ logUtils.info("已初始化Vault连接器...");
+
+ Bukkit.getServicesManager().register(Economy.class, hook, this, ServicePriority.Normal);
+ logUtils.info("Vault经济系统注册成功!");
+
+ new VaultPayCommand(getCommand("payMoney"), dataManager);
+ new VaultSeeCommand(getCommand("balance"), dataManager);
+ new VaultTopCommand(getCommand("balanceTop"), dataManager);
+ new VaultCommand(getCommand("economy"), dataManager);
+
+ logUtils.infoDividingLine();
+ }
+
+ @Override
+ public void onDisable() {
+ logUtils.infoDividingLine();
+ if (dataManager != null) {
+ dataManager.onDisable();
+ }
+ Bukkit.getServicesManager().unregister(this);
+ logUtils.info("插件已关闭!");
+ logUtils.infoDividingLine();
+ logUtils.close();
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/api/CurrencyAPI.java b/currency-plugin/src/main/java/cn/hamster3/currency/api/CurrencyAPI.java
new file mode 100644
index 0000000..7b512b2
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/api/CurrencyAPI.java
@@ -0,0 +1,88 @@
+package cn.hamster3.currency.api;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.black_ixx.playerpoints.PlayerPoints;
+import org.bukkit.Bukkit;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+/**
+ * 当 currencyID 为 PlayerPoints 且服务器安装了点券插件时,会自动更改为 PlayerPoints 接口
+ */
+@SuppressWarnings({"unused", "ConstantConditions"})
+public abstract class CurrencyAPI {
+ private static IDataManager dataManager;
+
+ public static void setDataManager(IDataManager dataManager) {
+ CurrencyAPI.dataManager = dataManager;
+ }
+
+ public static double getPlayerCurrency(UUID uuid, String currencyID) {
+ if (currencyID.equals("PlayerPoints") && Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
+ return ((PlayerPoints) Bukkit.getPluginManager().getPlugin("PlayerPoints")).getAPI().look(uuid);
+ }
+ PlayerData data = dataManager.getPlayerData(uuid);
+ if (data == null) {
+ return 0;
+ }
+ return data.getPlayerCurrency(currencyID);
+ }
+
+ public static void setPlayerCurrency(UUID uuid, String currencyID, double amount) {
+ if (currencyID.equals("PlayerPoints") && Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
+ ((PlayerPoints) Bukkit.getPluginManager().getPlugin("PlayerPoints")).getAPI().set(uuid, (int) amount);
+ return;
+ }
+ PlayerData data = dataManager.getPlayerData(uuid);
+ if (data == null) {
+ return;
+ }
+ data.setPlayerCurrency(currencyID, amount);
+ dataManager.savePlayerData(data);
+ }
+
+ public static void addPlayerCurrency(UUID uuid, String currencyID, double amount) {
+ if (currencyID.equals("PlayerPoints") && Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
+ ((PlayerPoints) Bukkit.getPluginManager().getPlugin("PlayerPoints")).getAPI().give(uuid, (int) amount);
+ return;
+ }
+ PlayerData data = dataManager.getPlayerData(uuid);
+ if (data == null) {
+ return;
+ }
+ data.setPlayerCurrency(currencyID, data.getPlayerCurrency(currencyID) + amount);
+ dataManager.savePlayerData(data);
+ }
+
+ public static void takePlayerCurrency(UUID uuid, String currencyID, double amount) {
+ if (currencyID.equals("PlayerPoints") && Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
+ ((PlayerPoints) Bukkit.getPluginManager().getPlugin("PlayerPoints")).getAPI().take(uuid, (int) amount);
+ return;
+ }
+ PlayerData data = dataManager.getPlayerData(uuid);
+ if (data == null) {
+ return;
+ }
+ data.setPlayerCurrency(currencyID, data.getPlayerCurrency(currencyID) - amount);
+ dataManager.savePlayerData(data);
+ }
+
+ public static boolean hasPlayerCurrency(UUID uuid, String currencyID, double amount) {
+ if (currencyID.equals("PlayerPoints") && Bukkit.getPluginManager().isPluginEnabled("PlayerPoints")) {
+ return ((PlayerPoints) Bukkit.getPluginManager().getPlugin("PlayerPoints")).getAPI().look(uuid) >= amount;
+ }
+ PlayerData data = dataManager.getPlayerData(uuid);
+ if (data == null) {
+ return false;
+ }
+ return data.getPlayerCurrency(currencyID) >= amount;
+ }
+
+ public ArrayList getAllCurrencyType() {
+ return new ArrayList<>(dataManager.getCurrencyTypes());
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/ReloadCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/ReloadCommand.java
new file mode 100644
index 0000000..1d00737
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/ReloadCommand.java
@@ -0,0 +1,34 @@
+package cn.hamster3.currency.command;
+
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.IDataManager;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.util.List;
+
+public class ReloadCommand extends CommandExecutor {
+ private final IDataManager dataManager;
+
+ public ReloadCommand(IDataManager dataManager) {
+ super("reload", "重载服务器");
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ dataManager.reloadConfig();
+ sender.sendMessage("§a插件重载完成!");
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyAdminSetCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyAdminSetCommand.java
new file mode 100644
index 0000000..4df19c5
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyAdminSetCommand.java
@@ -0,0 +1,106 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public abstract class CurrencyAdminSetCommand extends CommandExecutor {
+ protected final IDataManager dataManager;
+
+ public CurrencyAdminSetCommand(IDataManager dataManager, String name, String description, String permission) {
+ super(
+ name,
+ description,
+ permission,
+ Message.notHasPermission.toString(),
+ new String[]{
+ "玩家",
+ "货币类型",
+ "数额"
+ }
+ );
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ public String getPermissionMessage() {
+ return Message.notHasPermission.toString();
+ }
+
+ protected abstract void doSet(PlayerData data, CurrencyType type, double amount);
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(Message.notInputPlayerName.toString());
+ return true;
+ }
+ PlayerData data = dataManager.getPlayerData(args[1]);
+ if (data == null) {
+ sender.sendMessage(Message.playerNotFound.toString());
+ return true;
+ }
+ if (args.length < 3) {
+ sender.sendMessage(Message.notInputCurrencyType.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(args[2]);
+ if (type == null) {
+ sender.sendMessage(Message.currencyTypeNotFound.toString());
+ return true;
+ }
+ if (args.length < 4) {
+ sender.sendMessage(Message.notInputAmount.toString());
+ return true;
+ }
+ double amount;
+ try {
+ amount = Double.parseDouble(args[3]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(Message.amountNumberError.toString());
+ return true;
+ }
+ doSet(data, type, amount);
+ sender.sendMessage(
+ Message.playerCurrencySetSuccess.toString()
+ .replace("%player%", data.getPlayerName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", data.getPlayerCurrency(type.getId())))
+ );
+ dataManager.savePlayerData(data);
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ switch (args.length) {
+ case 2: {
+ return HamsterAPI.getOnlinePlayersName(args[1]);
+ }
+ case 3: {
+ List types = dataManager.getCurrencyTypes().stream().map(CurrencyType::getId).collect(Collectors.toList());
+ types = HamsterAPI.startWithIgnoreCase(types, args[2]);
+ if (types.size() > 10) {
+ types = types.subList(0, 9);
+ }
+ return types;
+ }
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyCommand.java
new file mode 100644
index 0000000..7c22960
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyCommand.java
@@ -0,0 +1,34 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.api.command.CommandManager;
+import cn.hamster3.currency.command.ReloadCommand;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.SQLDataManager;
+import org.bukkit.command.PluginCommand;
+
+public class CurrencyCommand extends CommandManager {
+ public CurrencyCommand(PluginCommand command, IDataManager dataManager) {
+ super(command);
+ addCommandExecutor(
+ new CurrencyGiveCommand(dataManager),
+ new CurrencyPayCommand(dataManager),
+ new ReloadCommand(dataManager),
+ new CurrencySeeCommand(dataManager),
+ new CurrencySetCommand(dataManager),
+ new CurrencyTakeCommand(dataManager),
+ new CurrencyTopCommand(dataManager)
+ );
+ if (FileManager.isUseBC()) {
+ addCommandExecutor(new CurrencyImportCommand((SQLDataManager) dataManager));
+ }
+ command.setExecutor(this);
+ command.setTabCompleter(this);
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyGiveCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyGiveCommand.java
new file mode 100644
index 0000000..b6ca325
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyGiveCommand.java
@@ -0,0 +1,22 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+public class CurrencyGiveCommand extends CurrencyAdminSetCommand {
+ public CurrencyGiveCommand(IDataManager dataManager) {
+ super(
+ dataManager,
+ "give",
+ "为玩家货币添加余额",
+ "currency.give"
+ );
+ }
+
+ @Override
+ protected void doSet(PlayerData data, CurrencyType type, double amount) {
+ data.setPlayerCurrency(type.getId(), data.getPlayerCurrency(type.getId()) + amount);
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyImportCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyImportCommand.java
new file mode 100644
index 0000000..021d638
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyImportCommand.java
@@ -0,0 +1,52 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.core.SQLDataManager;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.util.List;
+
+public class CurrencyImportCommand extends CommandExecutor {
+ private final SQLDataManager dataManager;
+
+ public CurrencyImportCommand(SQLDataManager dataManager) {
+ super(
+ "import",
+ "从其他插件中导入数据",
+ "currency.import",
+ Message.notHasPermission.toString(),
+ new String[]{
+ "数据库",
+ "数据表",
+ "uuid列名",
+ "name列名",
+ "money列名",
+ "货币类型"
+ }
+ );
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (args.length < 7) {
+ sender.sendMessage("§a/currency import [数据库] [数据表] [uuid列名] [name列名] [money列名] [货币类型]");
+ return true;
+ }
+ dataManager.importFromOtherPluginData(args[1], args[2], args[3], args[4], args[5], args[6]);
+ sender.sendMessage("§a已开始从其他插件的数据库存档中导入数据, 详情请查看控制台输出...");
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyPayCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyPayCommand.java
new file mode 100644
index 0000000..d311577
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyPayCommand.java
@@ -0,0 +1,141 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import cn.hamster3.service.bukkit.api.ServiceMessageAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class CurrencyPayCommand extends CommandExecutor {
+ private final IDataManager dataManager;
+
+ public CurrencyPayCommand(IDataManager dataManager) {
+ super(
+ "pay",
+ "向其他玩家转账",
+ "currency.pay",
+ Message.notHasPermission.toString(),
+ new String[]{
+ "玩家",
+ "货币类型",
+ "数额"
+ }
+ );
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(Message.notInputPlayerName.toString());
+ return true;
+ }
+ PlayerData toData = dataManager.getPlayerData(args[1]);
+ if (toData == null) {
+ sender.sendMessage(Message.playerNotFound.toString());
+ return true;
+ }
+ if (args.length < 3) {
+ sender.sendMessage(Message.notInputCurrencyType.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(args[2]);
+ if (type == null) {
+ sender.sendMessage(Message.currencyTypeNotFound.toString());
+ return true;
+ }
+ if (!type.isCanTransfer()) {
+ sender.sendMessage(Message.currencyTypeCantTransfer.toString().replace("%type%", type.getId()));
+ return true;
+ }
+ if (args.length < 4) {
+ sender.sendMessage(Message.notInputPayAmount.toString());
+ return true;
+ }
+ double amount;
+ try {
+ amount = Double.parseDouble(args[3]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(Message.amountNumberError.toString());
+ return true;
+ }
+ if (amount <= 0) {
+ sender.sendMessage(Message.amountNumberError.toString());
+ return true;
+ }
+ Player player = (Player) sender;
+ PlayerData fromData = dataManager.getPlayerData(player.getUniqueId());
+ if (fromData.getPlayerCurrency(type.getId()) < amount) {
+ sender.sendMessage(
+ Message.currencyNotEnough.toString()
+ .replace("%type%", type.getId())
+ );
+ return true;
+ }
+ fromData.setPlayerCurrency(type.getId(), fromData.getPlayerCurrency(type.getId()) - amount);
+ toData.setPlayerCurrency(type.getId(), toData.getPlayerCurrency(type.getId()) + amount);
+ dataManager.savePlayerData(fromData);
+ dataManager.savePlayerData(toData);
+ sender.sendMessage(
+ Message.paySuccess.toString()
+ .replace("%player%", toData.getPlayerName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", amount))
+ );
+ if (FileManager.isUseBC()) {
+ ServiceMessageAPI.sendPlayerMessage(
+ toData.getUuid(),
+ Message.receivePay.toString()
+ .replace("%player%", player.getName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", amount))
+ );
+ } else {
+ Player toPlayer = Bukkit.getPlayer(toData.getUuid());
+ if (toPlayer != null) {
+ toPlayer.sendMessage(
+ Message.receivePay.toString()
+ .replace("%player%", player.getName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", amount))
+ );
+ }
+ }
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ switch (args.length) {
+ case 2: {
+ return HamsterAPI.getOnlinePlayersName(args[1]);
+ }
+ case 3: {
+ List types = dataManager.getCurrencyTypes().stream().map(CurrencyType::getId).collect(Collectors.toList());
+ types = HamsterAPI.startWithIgnoreCase(types, args[2]);
+ if (types.size() > 10) {
+ types = types.subList(0, 9);
+ }
+ return types;
+ }
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencySeeCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencySeeCommand.java
new file mode 100644
index 0000000..622a1b2
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencySeeCommand.java
@@ -0,0 +1,89 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class CurrencySeeCommand extends CommandExecutor {
+ private final IDataManager dataManager;
+
+ public CurrencySeeCommand(IDataManager dataManager) {
+ super(
+ "see",
+ "查看玩家的货币余额",
+ "currency.see",
+ Message.notHasPermission.toString(),
+ new String[]{
+ "货币类型",
+ "玩家"
+ }
+ );
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(Message.notInputCurrencyType.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(args[1]);
+ if (type == null) {
+ sender.sendMessage(Message.currencyTypeNotFound.toString());
+ return true;
+ }
+ PlayerData data;
+ if (args.length < 3) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(Message.notInputPlayerName.toString());
+ return true;
+ }
+ Player player = (Player) sender;
+ data = dataManager.getPlayerData(player.getUniqueId());
+ } else {
+ if (!sender.hasPermission("currency.see.other")) {
+ sender.sendMessage(Message.notHasPermission.toString());
+ return true;
+ }
+ data = dataManager.getPlayerData(args[2]);
+ if (data == null) {
+ sender.sendMessage(Message.playerNotFound.toString());
+ return true;
+ }
+ }
+ sender.sendMessage(
+ Message.seeCurrency.toString()
+ .replace("%player%", data.getPlayerName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", data.getPlayerCurrency(type.getId())))
+ );
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ if (args.length == 2) {
+ List types = dataManager.getCurrencyTypes().stream().map(CurrencyType::getId).collect(Collectors.toList());
+ return HamsterAPI.startWith(types, args[1]);
+ }
+ if (args.length == 3) {
+ return HamsterAPI.getOnlinePlayersName(args[2]);
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencySetCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencySetCommand.java
new file mode 100644
index 0000000..ccc7c95
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencySetCommand.java
@@ -0,0 +1,22 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+public class CurrencySetCommand extends CurrencyAdminSetCommand {
+ public CurrencySetCommand(IDataManager dataManager) {
+ super(
+ dataManager,
+ "set",
+ "为玩家货币设置余额",
+ "currency.set"
+ );
+ }
+
+ @Override
+ protected void doSet(PlayerData data, CurrencyType type, double amount) {
+ data.setPlayerCurrency(type.getId(), amount);
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyTakeCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyTakeCommand.java
new file mode 100644
index 0000000..263818d
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyTakeCommand.java
@@ -0,0 +1,22 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+public class CurrencyTakeCommand extends CurrencyAdminSetCommand {
+ public CurrencyTakeCommand(IDataManager dataManager) {
+ super(
+ dataManager,
+ "take",
+ "为玩家货币扣除余额",
+ "currency.take"
+ );
+ }
+
+ @Override
+ protected void doSet(PlayerData data, CurrencyType type, double amount) {
+ data.setPlayerCurrency(type.getId(), data.getPlayerCurrency(type.getId()) - amount);
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyTopCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyTopCommand.java
new file mode 100644
index 0000000..697fec2
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/currency/CurrencyTopCommand.java
@@ -0,0 +1,102 @@
+package cn.hamster3.currency.command.currency;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class CurrencyTopCommand extends CommandExecutor {
+ private final IDataManager dataManager;
+
+ public CurrencyTopCommand(IDataManager dataManager) {
+ super(
+ "top",
+ "查看玩家的货币余额排行榜",
+ "currency.top",
+ Message.notHasPermission.toString(),
+ new String[]{
+ "货币类型",
+ "页码"
+ }
+ );
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(Message.notInputCurrencyType.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(args[1]);
+ if (type == null) {
+ sender.sendMessage(Message.currencyTypeNotFound.toString());
+ return true;
+ }
+ int page = 1;
+ if (args.length >= 3) {
+ try {
+ page = Integer.parseInt(args[2]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(Message.pageError.toString());
+ return true;
+ }
+ }
+
+ page = page - 1;
+ String typeId = type.getId();
+
+ ArrayList playerData = dataManager.getPlayerData();
+ playerData.sort((o1, o2) -> -Double.compare(o1.getPlayerCurrency(typeId), o2.getPlayerCurrency(typeId)));
+
+ sender.sendMessage(
+ Message.topRankPageHead.toString()
+ .replace("%type%", typeId)
+ .replace("%page%", String.valueOf(page + 1))
+ );
+ for (int i = page * 10; i < (page + 1) * 10; i++) {
+ if (i >= playerData.size()) {
+ break;
+ }
+ PlayerData data = playerData.get(i);
+ sender.sendMessage(
+ Message.topRankPageItem.toString()
+ .replace("%rank%", String.valueOf(i + 1))
+ .replace("%name%", data.getPlayerName())
+ .replace("%amount%", String.format("%.2f", data.getPlayerCurrency(typeId)))
+ );
+ }
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ if (args.length == 2) {
+ List types = dataManager.getPlayerData()
+ .stream()
+ .map(PlayerData::getPlayerName)
+ .collect(Collectors.toList());
+ types = HamsterAPI.startWithIgnoreCase(types, args[1]);
+ if (types.size() > 10) {
+ types = types.subList(0, 9);
+ }
+ return types;
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultAdminSetCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultAdminSetCommand.java
new file mode 100644
index 0000000..7aea3df
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultAdminSetCommand.java
@@ -0,0 +1,86 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandExecutor;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+
+import java.util.List;
+
+public abstract class VaultAdminSetCommand extends CommandExecutor {
+ protected final IDataManager dataManager;
+
+ public VaultAdminSetCommand(IDataManager dataManager, String name, String description, String permission) {
+ super(
+ name,
+ description,
+ permission,
+ Message.notHasPermission.toString(),
+ new String[]{
+ "玩家",
+ "数额"
+ }
+ );
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ public abstract void doSet(PlayerData data, CurrencyType type, double amount);
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ CurrencyType type = dataManager.getCurrencyType(FileManager.getVaultCurrencyType());
+ if (type == null) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+ if (args.length < 2) {
+ sender.sendMessage(Message.notInputPlayerName.toString());
+ return true;
+ }
+ PlayerData data = dataManager.getPlayerData(args[1]);
+ if (data == null) {
+ sender.sendMessage(Message.playerNotFound.toString());
+ return true;
+ }
+ if (args.length < 3) {
+ sender.sendMessage(Message.notInputAmount.toString());
+ return true;
+ }
+ double amount;
+ try {
+ amount = Double.parseDouble(args[2]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(Message.amountNumberError.toString());
+ return true;
+ }
+ doSet(data, type, amount);
+ dataManager.savePlayerData(data);
+ sender.sendMessage(
+ Message.seeCurrency.toString()
+ .replace("%player%", data.getPlayerName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", data.getPlayerCurrency(type.getId())))
+ );
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ if (args.length == 2) {
+ return HamsterAPI.getOnlinePlayersName(args[0]);
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultCommand.java
new file mode 100644
index 0000000..64632ad
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultCommand.java
@@ -0,0 +1,24 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.api.command.CommandManager;
+import cn.hamster3.currency.core.IDataManager;
+import org.bukkit.command.PluginCommand;
+
+public class VaultCommand extends CommandManager {
+ public VaultCommand(PluginCommand command, IDataManager dataManager) {
+ super(command);
+ addCommandExecutor(
+ new VaultSetCommand(dataManager),
+ new VaultGiveCommand(dataManager),
+ new VaultTakeCommand(dataManager)
+ );
+ command.setExecutor(this);
+ command.setTabCompleter(this);
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultGiveCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultGiveCommand.java
new file mode 100644
index 0000000..b67586a
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultGiveCommand.java
@@ -0,0 +1,22 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+public class VaultGiveCommand extends VaultAdminSetCommand {
+ public VaultGiveCommand(IDataManager dataManager) {
+ super(
+ dataManager,
+ "give",
+ "给予玩家金币",
+ "currency.give"
+ );
+ }
+
+ @Override
+ public void doSet(PlayerData data, CurrencyType type, double amount) {
+ data.setPlayerCurrency(type.getId(), data.getPlayerCurrency(type.getId()) + amount);
+
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultPayCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultPayCommand.java
new file mode 100644
index 0000000..64dea14
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultPayCommand.java
@@ -0,0 +1,132 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandManager;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import cn.hamster3.service.bukkit.api.ServiceMessageAPI;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class VaultPayCommand extends CommandManager {
+ private final IDataManager dataManager;
+
+ public VaultPayCommand(PluginCommand command, IDataManager dataManager) {
+ super(command);
+ this.dataManager = dataManager;
+ command.setExecutor(this);
+ command.setTabCompleter(this);
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return true;
+ }
+
+ @Override
+ public boolean checkPermission(CommandSender sender) {
+ return sender.hasPermission("currency.pay");
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ protected boolean defaultCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!FileManager.isVaultHook()) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(FileManager.getVaultCurrencyType());
+ if (type == null) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+ if (!type.isCanTransfer()) {
+ sender.sendMessage(Message.currencyTypeCantTransfer.toString().replace("%type%", type.getId()));
+ return true;
+ }
+ if (args.length < 1) {
+ sender.sendMessage(Message.notInputPlayerName.toString());
+ return true;
+ }
+ if (args.length < 2) {
+ sender.sendMessage(Message.notInputPayAmount.toString());
+ return true;
+ }
+
+ PlayerData toData = dataManager.getPlayerData(args[0]);
+ if (toData == null) {
+ sender.sendMessage(Message.playerNotFound.toString());
+ return true;
+ }
+
+ double amount;
+ try {
+ amount = Double.parseDouble(args[1]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(Message.amountNumberError.toString());
+ return true;
+ }
+ if (amount <= 0) {
+ sender.sendMessage(Message.amountNumberError.toString());
+ return true;
+ }
+
+ Player player = (Player) sender;
+ PlayerData fromData = dataManager.getPlayerData(player.getUniqueId());
+ if (fromData.getPlayerCurrency(type.getId()) < amount) {
+ sender.sendMessage(
+ Message.currencyNotEnough.toString()
+ .replace("%type%", type.getId())
+ );
+ return true;
+ }
+
+ fromData.setPlayerCurrency(type.getId(), fromData.getPlayerCurrency(type.getId()) - amount);
+ toData.setPlayerCurrency(type.getId(), toData.getPlayerCurrency(type.getId()) + amount);
+ dataManager.savePlayerData(fromData);
+ dataManager.savePlayerData(toData);
+ sender.sendMessage(
+ Message.paySuccess.toString()
+ .replace("%player%", toData.getPlayerName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", amount))
+ );
+ if (FileManager.isUseBC()) {
+ ServiceMessageAPI.sendPlayerMessage(
+ toData.getUuid(),
+ Message.receivePay.toString()
+ .replace("%player%", player.getName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", amount))
+ );
+ } else {
+ Player toPlayer = Bukkit.getPlayer(toData.getUuid());
+ if (toPlayer != null) {
+ toPlayer.sendMessage(
+ Message.receivePay.toString()
+ .replace("%player%", player.getName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", amount))
+ );
+ }
+ }
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ if (args.length == 1) {
+ return HamsterAPI.getOnlinePlayersName(args[0]);
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultSeeCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultSeeCommand.java
new file mode 100644
index 0000000..f253bb2
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultSeeCommand.java
@@ -0,0 +1,81 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.api.command.CommandManager;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class VaultSeeCommand extends CommandManager {
+ private final IDataManager dataManager;
+
+ public VaultSeeCommand(PluginCommand command, IDataManager dataManager) {
+ super(command);
+ this.dataManager = dataManager;
+ command.setExecutor(this);
+ command.setTabCompleter(this);
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ protected boolean defaultCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!FileManager.isVaultHook()) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(FileManager.getVaultCurrencyType());
+ if (type == null) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+
+ PlayerData data;
+ if (args.length < 1) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(Message.notInputPlayerName.toString());
+ return true;
+ }
+ Player player = (Player) sender;
+ data = dataManager.getPlayerData(player.getUniqueId());
+ } else {
+ if (!sender.hasPermission("currency.see.other")) {
+ sender.sendMessage(Message.notHasPermission.toString());
+ return true;
+ }
+ data = dataManager.getPlayerData(args[0]);
+ if (data == null) {
+ sender.sendMessage(Message.playerNotFound.toString());
+ return true;
+ }
+ }
+ sender.sendMessage(
+ Message.seeCurrency.toString()
+ .replace("%player%", data.getPlayerName())
+ .replace("%type%", type.getId())
+ .replace("%amount%", String.format("%.2f", data.getPlayerCurrency(type.getId())))
+ );
+ return true;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
+ if (args.length == 1) {
+ return HamsterAPI.getOnlinePlayersName(args[0]);
+ }
+ return null;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultSetCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultSetCommand.java
new file mode 100644
index 0000000..cde8028
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultSetCommand.java
@@ -0,0 +1,21 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+public class VaultSetCommand extends VaultAdminSetCommand {
+ public VaultSetCommand(IDataManager dataManager) {
+ super(
+ dataManager,
+ "set",
+ "设置玩家的金币",
+ "currency.set"
+ );
+ }
+
+ @Override
+ public void doSet(PlayerData data, CurrencyType type, double amount) {
+ data.setPlayerCurrency(type.getId(), amount);
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultTakeCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultTakeCommand.java
new file mode 100644
index 0000000..2eb0891
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultTakeCommand.java
@@ -0,0 +1,21 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+public class VaultTakeCommand extends VaultAdminSetCommand {
+ public VaultTakeCommand(IDataManager dataManager) {
+ super(
+ dataManager,
+ "take",
+ "扣除玩家金币",
+ "currency.take"
+ );
+ }
+
+ @Override
+ public void doSet(PlayerData data, CurrencyType type, double amount) {
+ data.setPlayerCurrency(type.getId(), data.getPlayerCurrency(type.getId()) - amount);
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultTopCommand.java b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultTopCommand.java
new file mode 100644
index 0000000..23f46d2
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/command/vault/VaultTopCommand.java
@@ -0,0 +1,77 @@
+package cn.hamster3.currency.command.vault;
+
+import cn.hamster3.api.command.CommandManager;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+
+import java.util.ArrayList;
+
+public class VaultTopCommand extends CommandManager {
+ private final IDataManager dataManager;
+
+ public VaultTopCommand(PluginCommand command, IDataManager dataManager) {
+ super(command);
+ this.dataManager = dataManager;
+ command.setExecutor(this);
+ command.setTabCompleter(this);
+ }
+
+ @Override
+ public boolean isPlayerCommand() {
+ return false;
+ }
+
+ @Override
+ @SuppressWarnings("DuplicatedCode")
+ protected boolean defaultCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!FileManager.isVaultHook()) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+ CurrencyType type = dataManager.getCurrencyType(FileManager.getVaultCurrencyType());
+ if (type == null) {
+ sender.sendMessage(Message.vaultEconomySetError.toString());
+ return true;
+ }
+ int page = 1;
+ if (args.length >= 1) {
+ try {
+ page = Integer.parseInt(args[0]);
+ } catch (NumberFormatException e) {
+ sender.sendMessage(Message.pageError.toString());
+ return true;
+ }
+ }
+
+ page = page - 1;
+ String typeId = type.getId();
+
+ ArrayList playerData = dataManager.getPlayerData();
+ playerData.sort((o1, o2) -> -Double.compare(o1.getPlayerCurrency(typeId), o2.getPlayerCurrency(typeId)));
+
+ sender.sendMessage(
+ Message.topRankPageHead.toString()
+ .replace("%type%", typeId)
+ .replace("%page%", String.valueOf(page + 1))
+ );
+ for (int i = page * 10; i < (page + 1) * 10; i++) {
+ if (i >= playerData.size()) {
+ break;
+ }
+ PlayerData data = playerData.get(i);
+ sender.sendMessage(
+ Message.topRankPageItem.toString()
+ .replace("%rank%", String.valueOf(i + 1))
+ .replace("%name%", data.getPlayerName())
+ .replace("%amount%", String.format("%.2f", data.getPlayerCurrency(typeId)))
+ );
+ }
+ return true;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/core/FileDataManager.java b/currency-plugin/src/main/java/cn/hamster3/currency/core/FileDataManager.java
new file mode 100644
index 0000000..7a855d3
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/core/FileDataManager.java
@@ -0,0 +1,157 @@
+package cn.hamster3.currency.core;
+
+import cn.hamster3.currency.HamsterCurrency;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+import static cn.hamster3.currency.HamsterCurrency.getLogUtils;
+
+public class FileDataManager implements IDataManager {
+ private final HamsterCurrency plugin;
+ private final HashSet playerData;
+ private final HashSet currencyTypes;
+
+ public FileDataManager(HamsterCurrency plugin) {
+ this.plugin = plugin;
+ playerData = new HashSet<>();
+ currencyTypes = new HashSet<>();
+ }
+
+ @Override
+ public void onEnable() {
+ getLogUtils().info("从本地磁盘中读取玩家数据...");
+
+ File dataFolder = new File(plugin.getDataFolder(), "PlayerData");
+ if (dataFolder.mkdirs()) {
+ getLogUtils().info("创建玩家存档文件夹...");
+ }
+
+ File[] files = dataFolder.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ try {
+ PlayerData data = new PlayerData(YamlConfiguration.loadConfiguration(file));
+ playerData.add(data);
+ } catch (Exception e) {
+ getLogUtils().error(e, "加载玩家存档文件 %s 时出现了一个异常!", file.getName());
+ }
+ }
+ }
+ getLogUtils().info("从本地磁盘中读取玩家数据完成!");
+ }
+
+ @Override
+ public void onDisable() {
+ File dataFolder = new File(plugin.getDataFolder(), "PlayerData");
+ for (PlayerData data : playerData) {
+ File dataFile = new File(dataFolder, data.getUuid().toString() + ".yml");
+ try {
+ data.saveToConfig().save(dataFile);
+ } catch (IOException e) {
+ getLogUtils().error(e, "保存玩家 %s 的存档至文件时出现了一个异常!", data.getUuid());
+ }
+ }
+ }
+
+ @Override
+ public void loadConfig() {
+ reloadConfig();
+ }
+
+ @Override
+ @SuppressWarnings("ConstantConditions")
+ public void reloadConfig() {
+ getLogUtils().info("加载配置文件...");
+
+ plugin.saveDefaultConfig();
+ plugin.reloadConfig();
+ FileConfiguration config = plugin.getConfig();
+
+ currencyTypes.clear();
+ ConfigurationSection currencyTypesConfig = config.getConfigurationSection("currencyTypes");
+ for (String key : currencyTypesConfig.getKeys(false)) {
+ try {
+ currencyTypes.add(new CurrencyType(currencyTypesConfig.getConfigurationSection(key)));
+ getLogUtils().warning("已加载货币类型: %s", key);
+ } catch (Exception e) {
+ getLogUtils().error(e, "加载货币类型 %s 时出现了一个错误: ", key);
+ }
+ }
+ FileManager.setPluginConfig(config);
+ getLogUtils().info("配置文件加载完成!");
+ }
+
+ @Override
+ public void loadPlayerData(UUID uuid) {
+ // 由于服务器启动时已经加载了所有玩家的存档
+ // 所以当玩家进服时无需再加载
+ // 只需要给没有存档的新玩家初始化一个存档数据即可
+ PlayerData data = getPlayerData(uuid);
+ if (data == null) {
+ playerData.add(new PlayerData(uuid));
+ }
+ }
+
+ @Override
+ public void savePlayerData(PlayerData data) {
+ // 每一次修改存档都保存至磁盘一次会极大地浪费服务器性能
+ // 按照插件架构,我们只需要在关服的时候保存所有玩家的存档即可
+ // 所以这里什么都不做
+ }
+
+ @Override
+ public PlayerData getPlayerData(UUID uuid) {
+ synchronized (playerData) {
+ for (PlayerData data : playerData) {
+ if (uuid.equals(data.getUuid())) {
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public PlayerData getPlayerData(String name) {
+ synchronized (playerData) {
+ for (PlayerData data : playerData) {
+ if (name.equalsIgnoreCase(data.getPlayerName())) {
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ArrayList getPlayerData() {
+ synchronized (playerData) {
+ return new ArrayList<>(playerData);
+ }
+ }
+
+ @Override
+ public CurrencyType getCurrencyType(String id) {
+ for (CurrencyType type : currencyTypes) {
+ if (type.getId().equalsIgnoreCase(id)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Set getCurrencyTypes() {
+ return currencyTypes;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/core/FileManager.java b/currency-plugin/src/main/java/cn/hamster3/currency/core/FileManager.java
new file mode 100644
index 0000000..14e2261
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/core/FileManager.java
@@ -0,0 +1,61 @@
+package cn.hamster3.currency.core;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.currency.HamsterCurrency;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+
+public abstract class FileManager {
+ private static boolean useBC;
+ private static boolean mainServer;
+ private static boolean vaultHook;
+ private static String vaultCurrencyType;
+ private static FileConfiguration pluginConfig;
+
+ public static void reload(HamsterCurrency plugin) {
+ plugin.saveDefaultConfig();
+ plugin.reloadConfig();
+ pluginConfig = plugin.getConfig();
+ useBC = pluginConfig.getBoolean("useBC", false);
+ mainServer = pluginConfig.getBoolean("datasource.template");
+ setPluginConfig(pluginConfig);
+ }
+
+ public static FileConfiguration getPluginConfig() {
+ return pluginConfig;
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ public static void setPluginConfig(FileConfiguration pluginConfig) {
+ FileManager.pluginConfig = pluginConfig;
+
+ vaultHook = pluginConfig.getBoolean("vault.hook");
+ vaultCurrencyType = pluginConfig.getString("vault.type");
+
+ ConfigurationSection messagesConfig = pluginConfig.getConfigurationSection("messages");
+ for (String key : messagesConfig.getKeys(false)) {
+ try {
+ Message.valueOf(key).setMessage(HamsterAPI.replaceColorCode(messagesConfig.getString(key)));
+ } catch (IllegalArgumentException e) {
+ HamsterCurrency.getLogUtils().warning("初始化消息设置 %s 时发生了一个异常: ", key);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static boolean isUseBC() {
+ return useBC;
+ }
+
+ public static boolean isMainServer() {
+ return mainServer;
+ }
+
+ public static boolean isVaultHook() {
+ return vaultHook;
+ }
+
+ public static String getVaultCurrencyType() {
+ return vaultCurrencyType;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/core/IDataManager.java b/currency-plugin/src/main/java/cn/hamster3/currency/core/IDataManager.java
new file mode 100644
index 0000000..e3513b2
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/core/IDataManager.java
@@ -0,0 +1,54 @@
+package cn.hamster3.currency.core;
+
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.UUID;
+
+public interface IDataManager {
+
+ /**
+ * 插件启动时调用
+ * 此时应该加载全部玩家的数据
+ */
+ void onEnable();
+
+ /**
+ * 插件关闭时调用
+ * 此时应该保存全部玩家的数据
+ */
+ void onDisable();
+
+ void loadConfig();
+
+ /**
+ * 重载服务器
+ */
+ void reloadConfig();
+
+ /**
+ * 加载玩家的数据
+ *
+ * @param uuid -
+ */
+ void loadPlayerData(UUID uuid);
+
+ /**
+ * 保存玩家的数据
+ *
+ * @param data -
+ */
+ void savePlayerData(PlayerData data);
+
+ PlayerData getPlayerData(UUID uuid);
+
+ PlayerData getPlayerData(String name);
+
+ ArrayList getPlayerData();
+
+ CurrencyType getCurrencyType(String id);
+
+ Set getCurrencyTypes();
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/core/Message.java b/currency-plugin/src/main/java/cn/hamster3/currency/core/Message.java
new file mode 100644
index 0000000..a5473ad
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/core/Message.java
@@ -0,0 +1,43 @@
+package cn.hamster3.currency.core;
+
+public enum Message {
+ prefix("§a[仓鼠经济] "),
+ notHasPermission("§c你没有这个权限!"),
+ notInputPlayerName("请输入玩家名称!"),
+ playerNotFound("未找到该玩家!"),
+ notInputCurrencyType("请输入货币类型!"),
+ currencyTypeNotFound("未找到该货币类型!"),
+ notInputAmount("请输入货币额度!"),
+ notInputPayAmount("请输入转账金额!"),
+ amountNumberError("货币额度必须是一个数字!"),
+ playerCurrencySetSuccess("货币设置成功! 玩家 %player% 当前 %type% 余额为: %amount%"),
+ currencyTypeCantTransfer("%type% 不支持转账!"),
+ currencyNotEnough("你的 %type% 不足!"),
+ paySuccess("已将 %amount% %type% 转账至 %player% 账户!"),
+ receivePay("从 %player% 账户上收到 %amount% %type%."),
+ seeCurrency("玩家 %player% 当前货币 %type% 余额为: %amount%"),
+ pageError("页码必须是一个大于0的整数!"),
+ topRankPageHead("========== %type% 排行榜 第 %page% 页 =========="),
+ topRankPageItem("%rank%.%name% %amount%"),
+ currencyNamePlural("金币"),
+ currencyNameSingular("金币"),
+ vaultEconomySetError("服务器经济系统发生了一个错误, 请尝试联系服务器管理员汇报问题!");
+ private String message;
+
+ Message(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ return prefix.message + message;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/core/SQLDataManager.java b/currency-plugin/src/main/java/cn/hamster3/currency/core/SQLDataManager.java
new file mode 100644
index 0000000..a42b415
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/core/SQLDataManager.java
@@ -0,0 +1,316 @@
+package cn.hamster3.currency.core;
+
+import cn.hamster3.api.HamsterAPI;
+import cn.hamster3.currency.HamsterCurrency;
+import cn.hamster3.currency.data.CurrencyType;
+import cn.hamster3.currency.data.PlayerData;
+import cn.hamster3.service.bukkit.api.ServiceMessageAPI;
+import com.google.gson.JsonParser;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.*;
+
+import static cn.hamster3.currency.HamsterCurrency.getLogUtils;
+
+public class SQLDataManager implements IDataManager {
+ private final JsonParser parser;
+ private final Connection connection;
+ private final HamsterCurrency plugin;
+ private final HashSet playerData;
+ private final HashSet currencyTypes;
+
+ @SuppressWarnings("ConstantConditions")
+ public SQLDataManager(HamsterCurrency plugin) throws SQLException, ClassNotFoundException {
+ this.plugin = plugin;
+ parser = new JsonParser();
+ playerData = new HashSet<>();
+ currencyTypes = new HashSet<>();
+
+ connection = HamsterAPI.getSQLConnection(FileManager.getPluginConfig().getConfigurationSection("datasource"));
+ Statement statement = connection.createStatement();
+ statement.execute("CREATE TABLE IF NOT EXISTS hamster_currency_player_data(" +
+ "uuid VARCHAR(36) PRIMARY KEY," +
+ "data TEXT" +
+ ");");
+ statement.execute("CREATE TABLE IF NOT EXISTS hamster_currency_settings(" +
+ "title VARCHAR(64) PRIMARY KEY," +
+ "data TEXT" +
+ ");");
+
+ statement.close();
+ }
+
+ public void uploadConfigToSQL() {
+ getLogUtils().info("重载配置文件...");
+ FileManager.reload(plugin);
+ FileConfiguration config = FileManager.getPluginConfig();
+ getLogUtils().info("配置文件重载完成!");
+ try {
+ getLogUtils().info("将配置文件上传至数据库...");
+ Statement statement = connection.createStatement();
+ String data = Base64.getEncoder().encodeToString(config.saveToString().getBytes(StandardCharsets.UTF_8));
+ statement.executeUpdate(String.format(
+ "REPLACE INTO hamster_currency_settings VALUES('%s', '%s');",
+ "pluginConfig",
+ data
+ ));
+ statement.close();
+ getLogUtils().info("配置文件上传完成!");
+ } catch (SQLException e) {
+ getLogUtils().error(e, "插件上传 pluginConfig 至数据库时遇到了一个异常: ");
+ }
+ loadConfig(config);
+ ServiceMessageAPI.sendMessage("HamsterCurrency", "uploadConfigToSQL");
+ }
+
+ @SuppressWarnings("SwitchStatementWithTooFewBranches")
+ public void loadConfigFromSQL() {
+ try {
+ getLogUtils().info("从数据库中下载配置文件...");
+ Statement statement = connection.createStatement();
+ ResultSet set = statement.executeQuery("SELECT * FROM hamster_currency_settings;");
+ while (set.next()) {
+ String title = set.getString("title");
+ String data = new String(Base64.getDecoder().decode(set.getString("data")), StandardCharsets.UTF_8);
+ switch (title) {
+ case "pluginConfig": {
+ YamlConfiguration config = new YamlConfiguration();
+ try {
+ config.loadFromString(data);
+ } catch (InvalidConfigurationException e) {
+ getLogUtils().error(e, "插件加载 %s 时遇到了一个异常: ", title);
+ }
+ loadConfig(config);
+ }
+ }
+ }
+ statement.close();
+ getLogUtils().info("配置文件下载完成!");
+ } catch (SQLException e) {
+ getLogUtils().error(e, "插件从数据库中下载 pluginConfig 时遇到了一个异常: ");
+ }
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ private void loadConfig(FileConfiguration config) {
+ getLogUtils().info("加载配置文件...");
+ currencyTypes.clear();
+ ConfigurationSection currencyTypesConfig = config.getConfigurationSection("currencyTypes");
+ for (String key : currencyTypesConfig.getKeys(false)) {
+ try {
+ currencyTypes.add(new CurrencyType(currencyTypesConfig.getConfigurationSection(key)));
+ getLogUtils().warning("已加载货币类型: %s", key);
+ } catch (Exception e) {
+ getLogUtils().error(e, "加载货币类型 %s 时出现了一个错误: ", key);
+ }
+ }
+ FileManager.setPluginConfig(config);
+ getLogUtils().info("配置文件加载完成!");
+ }
+
+ public void importFromOtherPluginData(String database, String table, String uuidCol, String nameCol, String moneyCol, String currencyType) {
+ Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
+ getLogUtils().info("开始从其他插件的数据库存档中导入数据: ");
+ getLogUtils().info("数据库名: %s", database);
+ getLogUtils().info("数据表名: %s", table);
+ getLogUtils().info("玩家uuid列名: %s", uuidCol);
+ getLogUtils().info("玩家名称列名: %s", nameCol);
+ getLogUtils().info("玩家经济列名: %s", moneyCol);
+ getLogUtils().info("导入至经济类型: %s", currencyType);
+ try {
+ Statement statement = connection.createStatement();
+ ResultSet set = statement.executeQuery(String.format("SELECT * FROM %s.%s;", database, table));
+ synchronized (playerData) {
+ while (set.next()) {
+ try {
+ UUID uuid = UUID.fromString(set.getString(uuidCol));
+ String name = set.getString(nameCol);
+ double money = set.getDouble(moneyCol);
+ PlayerData data = getPlayerData(uuid);
+ if (data == null) {
+ data = new PlayerData(uuid, name);
+ playerData.add(data);
+ }
+ data.setPlayerCurrency(currencyType, money);
+ getLogUtils().info("已从其他插件中加载了玩家 %s 的存档数据.", data.getUuid());
+ } catch (Exception e) {
+ getLogUtils().error(e, "导入某一条数据时发生了一个错误: ");
+ }
+ }
+ }
+ for (PlayerData data : playerData) {
+ statement.executeUpdate(String.format(
+ "REPLACE INTO hamster_currency_player_data VALUES('%s', '%s');",
+ data.getUuid().toString(),
+ data.saveToJson().toString()
+ ));
+ getLogUtils().info("已保存玩家 %s 的存档数据.", data.getUuid());
+ ServiceMessageAPI.sendMessage("HamsterCurrency", "savedPlayerData", data.getUuid().toString());
+ }
+ statement.close();
+ } catch (SQLException e) {
+ getLogUtils().error(e, "从其他插件中导入数据时发生了一个异常:");
+ }
+ });
+ }
+
+ @Override
+ public void onEnable() {
+ getLogUtils().info("从数据库中读取玩家数据...");
+ try {
+ Statement statement = connection.createStatement();
+ ResultSet set = statement.executeQuery("SELECT * FROM hamster_currency_player_data;");
+ synchronized (playerData) {
+ while (set.next()) {
+ String uuid = set.getString("uuid");
+ String string = set.getString("data");
+ try {
+ PlayerData data = new PlayerData(parser.parse(string).getAsJsonObject());
+ playerData.add(data);
+ } catch (Exception e) {
+ getLogUtils().error(e, "从数据库中读取玩家 %s 的存档( %s )时出现了一个异常: ", uuid, string);
+ }
+ }
+ }
+ set.close();
+ statement.close();
+ } catch (SQLException e) {
+ getLogUtils().error(e, "从数据库中读取玩家数据时出现了一个异常:");
+ }
+ getLogUtils().info("从数据库中读取玩家数据完成!");
+ }
+
+ @Override
+ public void onDisable() {
+ // 因为SQL模式使用HamsterService前置
+ // 服务器之间数据实时同步
+ // 所以关服时无需保存任何数据
+ }
+
+ @Override
+ public void loadConfig() {
+ if (FileManager.isMainServer()) {
+ uploadConfigToSQL();
+ } else {
+ loadConfigFromSQL();
+ }
+ }
+
+ @Override
+ public void reloadConfig() {
+ ServiceMessageAPI.sendMessage("HamsterCurrency", "reload");
+ }
+
+ @Override
+ public void loadPlayerData(UUID uuid) {
+ try {
+ Statement statement = connection.createStatement();
+ ResultSet set = statement.executeQuery(String.format(
+ "SELECT * FROM hamster_currency_player_data WHERE uuid='%s';",
+ uuid
+ ));
+ PlayerData data;
+ if (set.next()) {
+ String string = set.getString("data");
+ try {
+ data = new PlayerData(parser.parse(string).getAsJsonObject());
+ } catch (Exception e) {
+ getLogUtils().error(e, "从数据库中读取玩家 %s 的存档( %s )时出现了一个异常: ", uuid, string);
+ statement.close();
+ return;
+ }
+ } else {
+ data = new PlayerData(uuid);
+ getLogUtils().info("初始化玩家 %s 的存档数据.", data.getUuid());
+ }
+ synchronized (playerData) {
+ playerData.remove(data);
+ playerData.add(data);
+ }
+ set.close();
+ statement.close();
+ getLogUtils().info("已加载玩家 %s 的存档数据.", data.getUuid());
+ } catch (SQLException e) {
+ getLogUtils().error(e, "加载玩家 %s 的存档数据时出错!", uuid);
+ }
+ }
+
+ @Override
+ public void savePlayerData(PlayerData data) {
+ Bukkit.getScheduler().runTaskAsynchronously(plugin,
+ () -> {
+ try {
+ Statement statement = connection.createStatement();
+ statement.executeUpdate(String.format(
+ "REPLACE INTO hamster_currency_player_data VALUES('%s', '%s');",
+ data.getUuid().toString(),
+ data.saveToJson().toString()
+ ));
+ statement.close();
+ } catch (SQLException e) {
+ getLogUtils().error(e, "保存玩家 %s 的存档数据时出错!", data.getUuid());
+ }
+ getLogUtils().info("已保存玩家 %s 的存档数据.", data.getUuid());
+ ServiceMessageAPI.sendMessage(
+ "HamsterCurrency",
+ "savedPlayerData",
+ data.getUuid().toString()
+ );
+ });
+ }
+
+ @Override
+ public PlayerData getPlayerData(UUID uuid) {
+ synchronized (playerData) {
+ for (PlayerData data : playerData) {
+ if (uuid.equals(data.getUuid())) {
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public PlayerData getPlayerData(String name) {
+ synchronized (playerData) {
+ for (PlayerData data : playerData) {
+ if (name.equalsIgnoreCase(data.getPlayerName())) {
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ArrayList getPlayerData() {
+ synchronized (playerData) {
+ return new ArrayList<>(playerData);
+ }
+ }
+
+ @Override
+ public CurrencyType getCurrencyType(String id) {
+ for (CurrencyType type : currencyTypes) {
+ if (type.getId().equalsIgnoreCase(id)) {
+ return type;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Set getCurrencyTypes() {
+ return currencyTypes;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/data/CurrencyType.java b/currency-plugin/src/main/java/cn/hamster3/currency/data/CurrencyType.java
new file mode 100644
index 0000000..b1ea281
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/data/CurrencyType.java
@@ -0,0 +1,46 @@
+package cn.hamster3.currency.data;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+/**
+ * 货币类型
+ */
+public class CurrencyType {
+ /**
+ * 货币识别符
+ */
+ private final String id;
+ /**
+ * 是否允许转账
+ */
+ private final boolean canTransfer;
+
+ public CurrencyType(ConfigurationSection config) {
+ id = config.getName();
+ canTransfer = config.getBoolean("canTransfer");
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ public boolean isCanTransfer() {
+ return canTransfer;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CurrencyType that = (CurrencyType) o;
+
+ return id.equalsIgnoreCase(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/data/PlayerData.java b/currency-plugin/src/main/java/cn/hamster3/currency/data/PlayerData.java
new file mode 100644
index 0000000..a491a76
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/data/PlayerData.java
@@ -0,0 +1,118 @@
+package cn.hamster3.currency.data;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class PlayerData {
+ private final UUID uuid;
+ private final String playerName;
+ private final HashMap playerCurrencies;
+
+ public PlayerData(UUID uuid) {
+ this.uuid = uuid;
+ playerName = Bukkit.getOfflinePlayer(uuid).getName();
+ playerCurrencies = new HashMap<>();
+ }
+
+ public PlayerData(UUID uuid, String playerName) {
+ this.uuid = uuid;
+ this.playerName = playerName;
+ playerCurrencies = new HashMap<>();
+ }
+
+ public PlayerData(JsonObject object) {
+ uuid = UUID.fromString(object.get("uuid").getAsString());
+ OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
+ if (player.getName() != null) {
+ playerName = player.getName();
+ } else if (object.has("playerName") && !object.get("playerName").isJsonNull()) {
+ playerName = object.get("playerName").getAsString();
+ } else {
+ playerName = null;
+ }
+ playerCurrencies = new HashMap<>();
+ JsonObject playerCurrenciesJson = object.getAsJsonObject("playerCurrencies");
+ for (Map.Entry entry : playerCurrenciesJson.entrySet()) {
+ playerCurrencies.put(entry.getKey(), entry.getValue().getAsDouble());
+ }
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ public PlayerData(ConfigurationSection config) {
+ uuid = UUID.fromString(config.getString("uuid"));
+ OfflinePlayer player = Bukkit.getOfflinePlayer(uuid);
+ if (player.getName() != null) {
+ playerName = player.getName();
+ } else {
+ playerName = config.getString("playerName");
+ }
+ playerCurrencies = new HashMap<>();
+ ConfigurationSection playerCurrenciesConfig = config.getConfigurationSection("playerCurrencies");
+ for (String key : playerCurrenciesConfig.getKeys(false)) {
+ playerCurrencies.put(key, playerCurrenciesConfig.getDouble(key));
+ }
+ }
+
+ public JsonObject saveToJson() {
+ JsonObject object = new JsonObject();
+ object.addProperty("uuid", uuid.toString());
+ object.addProperty("playerName", playerName);
+ JsonObject playerCurrenciesJson = new JsonObject();
+ for (Map.Entry entry : playerCurrencies.entrySet()) {
+ playerCurrenciesJson.addProperty(entry.getKey(), entry.getValue());
+ }
+ object.add("playerCurrencies", playerCurrenciesJson);
+ return object;
+ }
+
+ public YamlConfiguration saveToConfig() {
+ YamlConfiguration config = new YamlConfiguration();
+ config.set("uuid", uuid.toString());
+ config.set("playerName", playerName);
+ YamlConfiguration playerCurrenciesConfig = new YamlConfiguration();
+ for (Map.Entry entry : playerCurrencies.entrySet()) {
+ playerCurrenciesConfig.set(entry.getKey(), entry.getValue());
+ }
+ config.set("playerCurrencies", playerCurrenciesConfig);
+ return config;
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public String getPlayerName() {
+ return playerName;
+ }
+
+ public void setPlayerCurrency(String type, double amount) {
+ playerCurrencies.put(type, amount);
+ }
+
+ public double getPlayerCurrency(String type) {
+ return playerCurrencies.getOrDefault(type, 0D);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PlayerData that = (PlayerData) o;
+
+ return uuid.equals(that.uuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/hook/PlaceholderHook.java b/currency-plugin/src/main/java/cn/hamster3/currency/hook/PlaceholderHook.java
new file mode 100644
index 0000000..260de89
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/hook/PlaceholderHook.java
@@ -0,0 +1,45 @@
+package cn.hamster3.currency.hook;
+
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.data.PlayerData;
+import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+public class PlaceholderHook extends PlaceholderExpansion {
+ private final IDataManager dataManager;
+
+ public PlaceholderHook(IDataManager dataManager) {
+ this.dataManager = dataManager;
+ }
+
+ @Override
+ @NotNull
+ public String getIdentifier() {
+ return "Currency";
+ }
+
+ @Override
+ @NotNull
+ public String getAuthor() {
+ return "Hamster3";
+ }
+
+ @Override
+ @NotNull
+ public String getVersion() {
+ return "1.0";
+ }
+
+ @Override
+ public String onRequest(OfflinePlayer player, @NotNull String params) {
+ PlayerData data = dataManager.getPlayerData(player.getUniqueId());
+ return String.format("%.2f", data.getPlayerCurrency(params));
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player player, @NotNull String params) {
+ return onRequest(player, params);
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/hook/VaultEconomyHook.java b/currency-plugin/src/main/java/cn/hamster3/currency/hook/VaultEconomyHook.java
new file mode 100644
index 0000000..2fa10c6
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/hook/VaultEconomyHook.java
@@ -0,0 +1,247 @@
+package cn.hamster3.currency.hook;
+
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.IDataManager;
+import cn.hamster3.currency.core.Message;
+import cn.hamster3.currency.data.PlayerData;
+import net.milkbowl.vault.economy.AbstractEconomy;
+import net.milkbowl.vault.economy.EconomyResponse;
+import org.bukkit.OfflinePlayer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class VaultEconomyHook extends AbstractEconomy {
+ private static final EconomyResponse NOT_IMPLEMENTED_RESPONSE =
+ new EconomyResponse(
+ 0,
+ 0,
+ EconomyResponse.ResponseType.NOT_IMPLEMENTED,
+ "HamsterCurrency未实现该功能~"
+ );
+ private final IDataManager dataManager;
+
+ public VaultEconomyHook(IDataManager dataManager) {
+ this.dataManager = dataManager;
+ }
+
+ protected EconomyResponse depositPlayer(PlayerData data, double amount) {
+ if (data == null) {
+ return new EconomyResponse(amount, 0, EconomyResponse.ResponseType.FAILURE, "玩家账户不存在");
+ }
+ String type = FileManager.getVaultCurrencyType();
+ if (data.getPlayerCurrency(type) > 0 && data.getPlayerCurrency(type) + amount < 0) {
+ return new EconomyResponse(amount, 0, EconomyResponse.ResponseType.FAILURE, "玩家金额超出上限");
+ }
+ data.setPlayerCurrency(type, data.getPlayerCurrency(type) + amount);
+ dataManager.savePlayerData(data);
+ return new EconomyResponse(amount, data.getPlayerCurrency(type), EconomyResponse.ResponseType.SUCCESS, "");
+ }
+
+ protected EconomyResponse withdrawPlayer(PlayerData data, double amount) {
+ if (data == null) {
+ return new EconomyResponse(amount, 0, EconomyResponse.ResponseType.FAILURE, "玩家账户不存在");
+ }
+ String type = FileManager.getVaultCurrencyType();
+ if (data.getPlayerCurrency(type) < amount) {
+ return new EconomyResponse(amount, data.getPlayerCurrency(type), EconomyResponse.ResponseType.FAILURE, "余额不足");
+ }
+ data.setPlayerCurrency(type, data.getPlayerCurrency(type) - amount);
+ dataManager.savePlayerData(data);
+ return new EconomyResponse(amount, data.getPlayerCurrency(type), EconomyResponse.ResponseType.SUCCESS, "扣款成功");
+ }
+
+ private boolean has(PlayerData data, double amount) {
+ if (data == null) {
+ return false;
+ }
+ return data.getPlayerCurrency(FileManager.getVaultCurrencyType()) >= amount;
+ }
+
+ private double getBalance(PlayerData data) {
+ if (data == null) {
+ return 0;
+ }
+ return data.getPlayerCurrency(FileManager.getVaultCurrencyType());
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return FileManager.isVaultHook();
+ }
+
+ @Override
+ public String getName() {
+ return "HamsterCurrency";
+ }
+
+ @Override
+ public int fractionalDigits() {
+ return 2;
+ }
+
+ @Override
+ public String format(double amount) {
+ return String.format("%.2f", amount);
+ }
+
+ @Override
+ public String currencyNamePlural() {
+ return Message.currencyNamePlural.getMessage();
+ }
+
+ @Override
+ public String currencyNameSingular() {
+ return Message.currencyNameSingular.getMessage();
+ }
+
+ @Override
+ public double getBalance(String playerName) {
+ return getBalance(dataManager.getPlayerData(playerName));
+ }
+
+ @Override
+ public double getBalance(OfflinePlayer player) {
+ return getBalance(dataManager.getPlayerData(player.getUniqueId()));
+ }
+
+ @Override
+ public double getBalance(String playerName, String world) {
+ return getBalance(dataManager.getPlayerData(playerName));
+ }
+
+ @Override
+ public double getBalance(OfflinePlayer player, String world) {
+ return getBalance(dataManager.getPlayerData(player.getUniqueId()));
+ }
+
+ @Override
+ public boolean has(String playerName, double amount) {
+ return has(dataManager.getPlayerData(playerName), amount);
+ }
+
+ @Override
+ public boolean has(OfflinePlayer player, double amount) {
+ return has(dataManager.getPlayerData(player.getUniqueId()), amount);
+ }
+
+ @Override
+ public boolean has(String playerName, String worldName, double amount) {
+ return has(dataManager.getPlayerData(playerName), amount);
+ }
+
+ @Override
+ public boolean has(OfflinePlayer player, String worldName, double amount) {
+ return has(dataManager.getPlayerData(player.getUniqueId()), amount);
+ }
+
+ @Override
+ public EconomyResponse withdrawPlayer(String playerName, double amount) {
+ return withdrawPlayer(dataManager.getPlayerData(playerName), amount);
+ }
+
+ @Override
+ public EconomyResponse withdrawPlayer(OfflinePlayer player, double amount) {
+ return withdrawPlayer(dataManager.getPlayerData(player.getUniqueId()), amount);
+ }
+
+ @Override
+ public EconomyResponse withdrawPlayer(String playerName, String worldName, double amount) {
+ return withdrawPlayer(dataManager.getPlayerData(playerName), amount);
+ }
+
+ @Override
+ public EconomyResponse withdrawPlayer(OfflinePlayer player, String worldName, double amount) {
+ return withdrawPlayer(dataManager.getPlayerData(player.getUniqueId()), amount);
+ }
+
+ @Override
+ public EconomyResponse depositPlayer(String playerName, double amount) {
+ return depositPlayer(dataManager.getPlayerData(playerName), amount);
+ }
+
+ @Override
+ public EconomyResponse depositPlayer(OfflinePlayer player, double amount) {
+ return depositPlayer(dataManager.getPlayerData(player.getUniqueId()), amount);
+ }
+
+ @Override
+ public EconomyResponse depositPlayer(String playerName, String worldName, double amount) {
+ return depositPlayer(dataManager.getPlayerData(playerName), amount);
+ }
+
+ @Override
+ public EconomyResponse depositPlayer(OfflinePlayer player, String worldName, double amount) {
+ return depositPlayer(dataManager.getPlayerData(player.getUniqueId()), amount);
+ }
+
+ @Override
+ public boolean hasBankSupport() {
+ return false;
+ }
+
+ @Override
+ public boolean hasAccount(String playerName) {
+ return true;
+ }
+
+ @Override
+ public boolean hasAccount(String playerName, String worldName) {
+ return true;
+ }
+
+ @Override
+ public EconomyResponse createBank(String name, String player) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse deleteBank(String name) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse bankBalance(String name) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse bankHas(String name, double amount) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse bankWithdraw(String name, double amount) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse bankDeposit(String name, double amount) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse isBankOwner(String name, String playerName) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public EconomyResponse isBankMember(String name, String playerName) {
+ return NOT_IMPLEMENTED_RESPONSE;
+ }
+
+ @Override
+ public List getBanks() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public boolean createPlayerAccount(String playerName) {
+ return true;
+ }
+
+ @Override
+ public boolean createPlayerAccount(String playerName, String worldName) {
+ return true;
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/listener/CurrencyListener.java b/currency-plugin/src/main/java/cn/hamster3/currency/listener/CurrencyListener.java
new file mode 100644
index 0000000..1e8f04a
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/listener/CurrencyListener.java
@@ -0,0 +1,23 @@
+package cn.hamster3.currency.listener;
+
+import cn.hamster3.currency.HamsterCurrency;
+import cn.hamster3.currency.core.IDataManager;
+import org.bukkit.Bukkit;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+
+public class CurrencyListener implements Listener {
+ protected final HamsterCurrency plugin;
+ protected final IDataManager dataManager;
+
+ public CurrencyListener(HamsterCurrency plugin, IDataManager dataManager) {
+ this.plugin = plugin;
+ this.dataManager = dataManager;
+ }
+
+ @EventHandler(ignoreCancelled = true)
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> dataManager.loadPlayerData(event.getPlayer().getUniqueId()));
+ }
+}
diff --git a/currency-plugin/src/main/java/cn/hamster3/currency/listener/SQLListener.java b/currency-plugin/src/main/java/cn/hamster3/currency/listener/SQLListener.java
new file mode 100644
index 0000000..abda48c
--- /dev/null
+++ b/currency-plugin/src/main/java/cn/hamster3/currency/listener/SQLListener.java
@@ -0,0 +1,55 @@
+package cn.hamster3.currency.listener;
+
+import cn.hamster3.currency.HamsterCurrency;
+import cn.hamster3.currency.core.FileManager;
+import cn.hamster3.currency.core.SQLDataManager;
+import cn.hamster3.service.bukkit.api.ServiceInfoAPI;
+import cn.hamster3.service.bukkit.event.MessageReceivedEvent;
+import cn.hamster3.service.common.entity.ServiceMessageInfo;
+import org.bukkit.event.EventHandler;
+
+import java.util.UUID;
+
+/**
+ * 跨服模式时使用这个监听器
+ */
+public class SQLListener extends CurrencyListener {
+ public SQLListener(HamsterCurrency plugin, SQLDataManager dataManager) {
+ super(plugin, dataManager);
+ }
+
+ @EventHandler(ignoreCancelled = true)
+ public void onServiceReceive(MessageReceivedEvent event) {
+ ServiceMessageInfo info = event.getMessageInfo();
+ if (!"HamsterCurrency".equals(info.getTag())) {
+ return;
+ }
+ SQLDataManager dataManager = (SQLDataManager) super.dataManager;
+ switch (info.getAction()) {
+ case "reload": {
+ if (!FileManager.isMainServer()) {
+ return;
+ }
+ HamsterCurrency.getLogUtils().info("收到重载指令,开始重载服务器...");
+ dataManager.uploadConfigToSQL();
+ break;
+ }
+ case "uploadConfigToSQL": {
+ if (ServiceInfoAPI.getLocalSenderInfo().equals(info.getSenderInfo())) {
+ return;
+ }
+ HamsterCurrency.getLogUtils().info("主服务器已上传 pluginConfig, 准备从数据库中下载配置并重载插件...");
+ dataManager.loadConfigFromSQL();
+ break;
+ }
+ case "savedPlayerData": {
+ if (ServiceInfoAPI.getLocalSenderInfo().equals(info.getSenderInfo())) {
+ return;
+ }
+ UUID uuid = UUID.fromString(info.getContentAsString());
+ dataManager.loadPlayerData(uuid);
+ break;
+ }
+ }
+ }
+}
diff --git a/currency-plugin/src/main/resources/config.yml b/currency-plugin/src/main/resources/config.yml
new file mode 100644
index 0000000..916d243
--- /dev/null
+++ b/currency-plugin/src/main/resources/config.yml
@@ -0,0 +1,60 @@
+# 是否开启跨服模式
+# 若false则使用本地文件存储模式
+# 若true则需要HamsterService前置
+useBC: true
+
+# 若开启跨服模式,则需要配置datasource
+datasource:
+ driver: "com.mysql.jdbc.Driver"
+ url: "jdbc:mysql://test3.hamster3.cn:3306?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false"
+ user: Test
+ password: Test123..
+ database: Test
+ # 是否将这个服务器的配置文件设为模板
+ # 若设为true,config将会在服务器启动时自动上传至数据库
+ # 其他template为false的服务器将会在启动和重载时自动从数据库上下载config
+ # 可以节省一些config配置时的麻烦事情
+ # 但是请先保证template为true的服务器完全启动了再启动子服
+ # 如果觉得这样反而更麻烦,也可以直接把所有服务器的template设为true
+ # 这样每个服务器都会使用自己本地的config文件了
+ template: true
+
+currencyTypes:
+ # 货币ID
+ "金币":
+ # 是否允许转账
+ canTransfer: true
+ "一周年活动代币":
+ canTransfer: false
+ "比特币":
+ canTransfer: true
+
+# 开启这个选项前请先确保服务器安装了Vault前置
+vault:
+ # 是否挂接 Vault 经济系统
+ hook: true
+ # 使用哪一个货币来支持Vault的经济系统
+ type: "金币"
+
+messages:
+ prefix: "§a[仓鼠经济] "
+ notHasPermission: "§c你没有这个权限!"
+ notInputPlayerName: "请输入玩家名称!"
+ playerNotFound: "未找到该玩家!"
+ notInputCurrencyType: "请输入货币类型!"
+ currencyTypeNotFound: "未找到该货币类型!"
+ notInputAmount: "请输入货币额度!"
+ notInputPayAmount: "请输入转账金额!"
+ amountNumberError: "货币额度必须是一个数字!"
+ playerCurrencySetSuccess: "货币设置成功! 玩家 %player% 当前 %type% 余额为: %amount%"
+ currencyTypeCantTransfer: "%type% 不支持转账!"
+ currencyNotEnough: "你的 %type% 不足!"
+ paySuccess: "已将 %amount% %type% 转账至 %player% 账户!"
+ receivePay: "从 %player% 账户上收到 %amount% %type%."
+ seeCurrency: "玩家 %player% 当前货币 %type% 余额为: %amount%"
+ pageError: "页码必须是一个大于0的整数!"
+ topRankPageHead: "========== %type% 排行榜 第 %page% 页 =========="
+ topRankPageItem: "%rank%.%name% %amount%"
+ currencyNamePlural: "金币"
+ currencyNameSingular: "金币"
+ vaultEconomySetError: "服务器经济系统发生了一个错误, 请尝试联系服务器管理员汇报问题!"
diff --git a/currency-plugin/src/main/resources/plugin.yml b/currency-plugin/src/main/resources/plugin.yml
new file mode 100644
index 0000000..85d59c7
--- /dev/null
+++ b/currency-plugin/src/main/resources/plugin.yml
@@ -0,0 +1,46 @@
+name: HamsterCurrency
+version: ${version}
+main: cn.hamster3.currency.HamsterCurrency
+authors: [ Hamster3 ]
+description: 仓鼠的多货币支持
+website: https://www.hamster3.cn/
+
+load: STARTUP
+api-version: "1.16"
+
+depend:
+ - HamsterAPI
+
+softdepend:
+ - HasmterService-Bukkit
+ - PlaceholderAPI
+ - PlayerPoints
+ - Vault
+
+commands:
+ HamsterCurrency:
+ aliases: [ hcurrency, currency ]
+ balance:
+ aliases: [ bal, seemoney ]
+ balanceTop:
+ aliases: [ baltop ]
+ payMoney:
+ aliases: [ pay ]
+ economy:
+ aliases: [ eco, money ]
+
+permissions:
+ currency.import:
+ default: op
+ currency.give:
+ default: op
+ currency.take:
+ default: op
+ currency.set:
+ default: op
+ currency.look:
+ default: true
+ currency.look.other:
+ default: op
+ currency.top:
+ default: op
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7454180
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..69a9715
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..744e882
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MSYS* | MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..f2c4edb
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,4 @@
+rootProject.name = 'HamsterCurrency-Parent'
+include 'currency-plugin'
+include 'transform-essentials'
+
diff --git a/transform-essentials/README.md b/transform-essentials/README.md
new file mode 100644
index 0000000..cbf7229
--- /dev/null
+++ b/transform-essentials/README.md
@@ -0,0 +1,3 @@
+essentials 转换插件
+
+放入服务端根目录的**上一级目录**,然后使用控制台启动即可
\ No newline at end of file
diff --git a/transform-essentials/build.gradle b/transform-essentials/build.gradle
new file mode 100644
index 0000000..60e3eb2
--- /dev/null
+++ b/transform-essentials/build.gradle
@@ -0,0 +1,48 @@
+plugins {
+ id 'java'
+}
+
+group 'cn.hamster3'
+version '1.0.0-SNAPSHOT'
+
+repositories {
+ maven {
+ url = "https://maven.airgame.net/repository/maven-public/"
+ }
+}
+
+configurations {
+
+ implementationShade
+ implementation.extendsFrom implementationShade
+}
+
+dependencies {
+ // https://mvnrepository.com/artifact/com.electronwill.night-config/core
+ implementationShade group: 'com.electronwill.night-config', name: 'core', version: '3.6.4'
+ // https://mvnrepository.com/artifact/com.electronwill.night-config/yaml
+ implementationShade group: 'com.electronwill.night-config', name: 'yaml', version: '3.6.4'
+
+ // https://mvnrepository.com/artifact/com.google.code.gson/gson
+ implementationShade group: 'com.google.code.gson', name: 'gson', version: '2.8.8'
+ // https://mvnrepository.com/artifact/mysql/mysql-connector-java
+ implementationShade group: 'mysql', name: 'mysql-connector-java', version: '8.0.26'
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+jar {
+ archivesBaseName = "HamsterCurrency-Transform-Essentials"
+ manifest.attributes('Main-Class': 'cn.hamster3.transform.essentials.Main')
+ from([
+ configurations.implementationShade.collect {
+ it.isDirectory() ? it : zipTree(it)
+ },
+ rootProject.file("LICENSE")
+ ])
+ duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
+ destinationDir(rootProject.buildDir)
+}
diff --git a/transform-essentials/src/main/java/cn/hamster3/transform/essentials/Main.java b/transform-essentials/src/main/java/cn/hamster3/transform/essentials/Main.java
new file mode 100644
index 0000000..01de8dd
--- /dev/null
+++ b/transform-essentials/src/main/java/cn/hamster3/transform/essentials/Main.java
@@ -0,0 +1,159 @@
+package cn.hamster3.transform.essentials;
+
+import cn.hamster3.transform.essentials.data.PlayerData;
+import com.electronwill.nightconfig.core.Config;
+import com.electronwill.nightconfig.core.file.FileNotFoundAction;
+import com.electronwill.nightconfig.yaml.YamlFormat;
+import com.electronwill.nightconfig.yaml.YamlParser;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashSet;
+import java.util.Scanner;
+import java.util.UUID;
+
+public class Main {
+ private static final YamlParser parser = new YamlParser(YamlFormat.defaultInstance());
+ private static final HashSet playerData = new HashSet<>();
+
+ public static void main(String[] args) throws Exception {
+ Scanner scanner = new Scanner(System.in);
+ System.out.println("请输入数据库主机名: ");
+ String host = scanner.nextLine();
+ System.out.println("请输入数据库端口号: ");
+ String port = scanner.nextLine();
+ System.out.println("请输入数据库用户名: ");
+ String user = scanner.nextLine();
+ System.out.println("请输入数据库密码: ");
+ String password = scanner.nextLine();
+ System.out.println("请输入数据库库名: ");
+ String database = scanner.nextLine();
+
+ File file = new File(System.getProperty("user.dir"));
+ File[] files = file.listFiles();
+ if (files == null) {
+ return;
+ }
+ for (File subFile : files) {
+ System.out.println("开始扫描文件夹: " + subFile.getAbsolutePath());
+ if (!subFile.isDirectory()) {
+ continue;
+ }
+ scanServer(subFile);
+ System.out.println("文件夹扫描完成: " + subFile.getAbsolutePath());
+ }
+ System.out.println("加载 MySQL 数据库驱动...");
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ System.out.println("建立 MySQL 数据库连接...");
+
+ Connection connection = DriverManager.getConnection(
+ "jdbc:mysql://" + host + ":" + port + "?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false",
+ user,
+ password
+ );
+ Statement statement = connection.createStatement();
+ System.out.println("切换至数据库...");
+ statement.execute(String.format("CREATE DATABASE IF NOT EXISTS %s DEFAULT CHARACTER SET ='UTF8';", database));
+ statement.execute(String.format("USE %s;", database));
+ System.out.println("检查数据表...");
+ statement.execute("CREATE TABLE IF NOT EXISTS hamster_currency_player_data(" +
+ "uuid VARCHAR(36) PRIMARY KEY," +
+ "data TEXT" +
+ ");");
+ System.out.println("开始更新数据库...");
+ for (PlayerData data : playerData) {
+ String sql = String.format(
+ "REPLACE INTO hamster_currency_player_data VALUES('%s', '%s');",
+ data.getUuid().toString(),
+ data.saveToJson().toString().replace("'", "\\'")
+ );
+ try {
+ statement.executeUpdate(sql);
+ } catch (SQLException e) {
+ System.out.println("执行 sql " + sql + " 时遇到了一个异常:");
+ e.printStackTrace();
+ }
+ }
+ statement.close();
+ connection.close();
+ }
+
+ private static void scanServer(File folder) {
+ if (!folder.isDirectory()) {
+ System.out.println(folder.getAbsolutePath() + " 不是一个文件夹. 跳过扫描.");
+ return;
+ }
+ File pluginFolder = new File(folder, "plugins");
+ if (!pluginFolder.isDirectory()) {
+ System.out.println(pluginFolder.getAbsolutePath() + " 不是一个文件夹. 跳过扫描.");
+ return;
+ }
+ File essentialFolder = new File(pluginFolder, "Essentials");
+ if (!essentialFolder.isDirectory()) {
+ System.out.println(essentialFolder.getAbsolutePath() + " 不是一个文件夹. 跳过扫描.");
+ return;
+ }
+ File userdataFolder = new File(essentialFolder, "userdata");
+ if (!userdataFolder.isDirectory()) {
+ System.out.println(userdataFolder.getAbsolutePath() + " 不是一个文件夹. 跳过扫描.");
+ return;
+ }
+ File[] files = userdataFolder.listFiles();
+ if (files == null) {
+ return;
+ }
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ try {
+ scanUserData(file);
+ } catch (Exception e) {
+ System.out.println("读取文件 " + file.getAbsolutePath() + " 时出现了一个异常:");
+ e.printStackTrace();
+ }
+ if (i % 100 == 0) {
+ System.out.println("已完成: (" + i + "/" + files.length + ")");
+ }
+ }
+ }
+
+ private static void scanUserData(File file) {
+ UUID uuid = UUID.fromString(file.getName().substring(0, 36));
+ Config config = parser.parse(file, FileNotFoundAction.THROW_ERROR, StandardCharsets.UTF_8);
+
+ if (config.contains("npc")) {
+ boolean isNPC = config.get("npc");
+ if (isNPC) {
+ return;
+ }
+ }
+ if (!config.contains("lastAccountName")) {
+ return;
+ }
+ if (!config.contains("money")) {
+ return;
+ }
+ String lastAccountName = config.get("lastAccountName");
+ double money = Double.parseDouble(config.get("money"));
+ PlayerData data = getPlayerData(uuid, lastAccountName);
+ if (data.getPlayerCurrency("金币") >= money) {
+ return;
+ }
+ data.setPlayerCurrency("金币", money);
+ }
+
+ private static PlayerData getPlayerData(UUID uuid, String name) {
+ for (PlayerData data : playerData) {
+ if (data.getUuid().equals(uuid)) {
+ return data;
+ }
+ }
+ PlayerData data = new PlayerData(uuid, name);
+ playerData.add(data);
+ return data;
+ }
+
+}
diff --git a/transform-essentials/src/main/java/cn/hamster3/transform/essentials/data/CurrencyType.java b/transform-essentials/src/main/java/cn/hamster3/transform/essentials/data/CurrencyType.java
new file mode 100644
index 0000000..33d8261
--- /dev/null
+++ b/transform-essentials/src/main/java/cn/hamster3/transform/essentials/data/CurrencyType.java
@@ -0,0 +1,44 @@
+package cn.hamster3.transform.essentials.data;
+
+/**
+ * 货币类型
+ */
+public class CurrencyType {
+ /**
+ * 货币识别符
+ */
+ private final String id;
+ /**
+ * 是否允许转账
+ */
+ private final boolean canTransfer;
+
+ public CurrencyType(String id, boolean canTransfer) {
+ this.id = id;
+ this.canTransfer = canTransfer;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ public boolean isCanTransfer() {
+ return canTransfer;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CurrencyType that = (CurrencyType) o;
+
+ return id.equalsIgnoreCase(that.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+}
diff --git a/transform-essentials/src/main/java/cn/hamster3/transform/essentials/data/PlayerData.java b/transform-essentials/src/main/java/cn/hamster3/transform/essentials/data/PlayerData.java
new file mode 100644
index 0000000..e00cf34
--- /dev/null
+++ b/transform-essentials/src/main/java/cn/hamster3/transform/essentials/data/PlayerData.java
@@ -0,0 +1,63 @@
+package cn.hamster3.transform.essentials.data;
+
+import com.google.gson.JsonObject;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class PlayerData {
+ private final UUID uuid;
+ private final String playerName;
+ private final HashMap playerCurrencies;
+
+ public PlayerData(UUID uuid, String playerName) {
+ this.uuid = uuid;
+ this.playerName = playerName;
+ playerCurrencies = new HashMap<>();
+ }
+
+
+ public JsonObject saveToJson() {
+ JsonObject object = new JsonObject();
+ object.addProperty("uuid", uuid.toString());
+ object.addProperty("playerName", playerName);
+ JsonObject playerCurrenciesJson = new JsonObject();
+ for (Map.Entry entry : playerCurrencies.entrySet()) {
+ playerCurrenciesJson.addProperty(entry.getKey(), entry.getValue());
+ }
+ object.add("playerCurrencies", playerCurrenciesJson);
+ return object;
+ }
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public String getPlayerName() {
+ return playerName;
+ }
+
+ public void setPlayerCurrency(String type, double amount) {
+ playerCurrencies.put(type, amount);
+ }
+
+ public double getPlayerCurrency(String type) {
+ return playerCurrencies.getOrDefault(type, 0D);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PlayerData that = (PlayerData) o;
+
+ return uuid.equals(that.uuid);
+ }
+
+ @Override
+ public int hashCode() {
+ return uuid.hashCode();
+ }
+}