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/v/cn.hamster3/HamsterCurrency.svg)](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(); + } +}