From 4ece6c085ee780f06a007892e8b2b61a9f83350b Mon Sep 17 00:00:00 2001 From: zhangyuheng Date: Wed, 10 Jan 2024 17:38:59 +0800 Subject: [PATCH] finish every thing maybe... --- README.md | 182 ++++++++++++++++++ pom.xml | 2 +- .../cn/lunadeer/miniplayertitle/Commands.java | 48 ++++- .../miniplayertitle/MiniPlayerTitle.java | 5 +- .../cn/lunadeer/miniplayertitle/Shop.java | 2 +- .../cn/lunadeer/miniplayertitle/Title.java | 21 +- .../cn/lunadeer/miniplayertitle/XPlayer.java | 107 +++++----- .../commands/AdminCommands.java | 32 ++- .../commands/PlayerCommands.java | 24 +-- .../miniplayertitle/utils/ConfigManager.java | 39 +++- .../miniplayertitle/utils/Database.java | 26 +-- .../utils/STUI/Pagination.java | 4 +- .../miniplayertitle/utils/STUI/View.java | 38 +++- .../utils/STUI/ViewStyles.java | 6 +- src/main/resources/config.yml | 6 + 15 files changed, 433 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 3cc6ca6..5db668c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,184 @@ # MiniPlayerTitle +## 简易玩家称号插件 + +[PlayerTitle](https://ricedoc.handyplus.cn/wiki/PlayerTitle/) 青春版 + +![image-20240110164757834](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e59bfc8f7b.png) + +## 说明 + +- 本插件为 [PlayerTitle](https://ricedoc.handyplus.cn/wiki/PlayerTitle/) 的简易版,基本实现了其大部分功能 +- 由于历史原因 PlayerTitle 使用玩家名称而非 UUID 作为数据库主键,因此玩家改名后称号会丢失,本插件使用 UUID 作为主键,不会出现该问题 + +## 功能介绍 + +- 本插件支持 PlayerTitle 的 [新版RGB颜色格式](https://ricedoc.handyplus.cn/wiki/PlayerTitle/rgb/#新版本格式) (详情见下文) +- 本插件仅支持 PostgresSQL 数据库,不支持 MySQL、Sqlite 等 +- 本插件使用 **TUI** 作为简易的交互方式,非 PlayerTitle 的箱子UI +- 支持设置称号**限量销售、限时销售** +- 支持玩家使用称号币自定义称号 + +## 支持版本 + +- 1.20.1+ (Paper) + +## 安装方法 + +1. 将插件放入服务器的 `plugins` 目录下 +2. 重启服务器 +3. 在 `plugins/MiniPlayerTitle/config.yml` 中配置 +4. 重启服务器 + +## 使用方法 + +使用 `/mplt` 指令打开 TUI 界面 + +### 主页 + +- 点击【称号背包】可查看自己拥有的所有称号; +- 点击【称号商店】可查看商店中出售的称号; +- 点击【自定义称号】可查看自定义称号的相关帮助信息; + +![image-20240110164757834](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e59bfc8f7b.png) + +### 称号背包 + +- 称号背包中会显示当前拥有的所有称号以及相应到到期时间。 +- 点击【卸下】可以取消当前正在使用的称号,点击【使用】会装备对应称号或替换当前称号。 +- 每页最多显示5条信息,可以点击【下一页】向后翻页。 +- 鼠标移动到称号上可以显示相应称号的描述信息。 +- 称号有效期只能精确到天,例如:20240115表示此称号将在2024年1月16日开始无法使用。 + +![image-20240110170535331](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e5ddfc16dd.png) + +### 称号商店 + +- 称号商店会显示称号销售列表、拥有的称号币余额、出售称号的价格、可购买天数、销售截止日期、可购买余量信息。 + +- 每页最多显示5条信息,可以点击【下一页】向后翻页。 + +- 点击【购买】即可购买相应的称号,称号购买后不会自动装备,需要前往背包手动使用。 + +- 在一个称号没有过期时无法再次购买此称号。 +- 售卖截止日期只能精确到天。 + +![image-20240110170621073](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e5e0d772ce.png) + +### 自定义称号 + +- 在自定义称号帮助页面会显示当前管理员配置的自定义称号规则。 +- 如果自定义称号处于【开启】状态,那么玩家可以消耗称号币自定义喜欢的称号。 +- 自定义称号支持RGB彩色字,需要使用 `&#`为开头的十六进制RGB颜色代码表示颜色,例如`�`表示黑色。可以使用 [Minecraft 渐变颜色生成器](https://ssl.lunadeer.cn:14440/) 来生成具有渐变效果的称号。 +- 创建成功后会自动扣除所需的花费。 + +![image-20240110171242703](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e5f8b2f5fb.png) + +## 管理员指南 + +### 1. 创建称号 + +使用 `/mplt create [称号名称] [称号描述]` 创建称号,称号支持RGB彩色字,需要使用 `&#`为开头的十六进制RGB颜色代码表示颜色,例如`�`表示黑色。可以使用 [Minecraft 渐变颜色生成器](https://ssl.lunadeer.cn:14440/) 来生成具有渐变效果的称号。 + +![image-20240110172102245](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e617ea7351.png) + +创建成功后会显示创建称号的 ID 以及称号名。 + +### 2. 添加到商店 + +使用`/mplt addshop [称号ID]` 添加称号到商店,添加成功后会显示添加的商品ID。 + +添加到商店的默认销售信息为:**0元购买0天、常驻销售、0库存**,需要使用相应指令设置称号的销售信息,此默认配置是无法购买的(因为库存和销售天数都是0)。 + +### 3. 设置销售信息 + +首先使用`/mplt setprice [商品ID] [价格] [天数]` 设置称号的价格信息,例如可以设置成 1 个称号币购买 7 天`/mplt setprice [商品ID] 1 7` 。如果你希望这是一个永久称号,那么你可以将天数设置为-1。 + +接着需要使用`/mplt setamount [商品ID] [数量]` 设置称号出售数量。同理,如果你希望这是一个无限供应的称号,那么可以将数量设置为-1则表示无限量销售。 + +假如你希望这个称号是一个限时销售的称号可以使用`/mplt setendat [商品ID] [结束时间]` 设置称号结束销售时间,时间格式为 `YYYYMMDD` ,在超过这个日期后玩家将无法购买此称号(但是仍然会显示在商店列表里)。 + +将销售结束时间设置为-1可以将其重新修改为常驻销售。 + +### 4. 其他操作 + +其他操作详见下方的管理员指令说明。 + +提示: + +- 你可以安全的删除一个称号,此操作会自动删除玩家拥有的此称号记录以及商店的相关数据。 +- 修改称号的名称、描述也会同步变动玩家已经购买的称号信息。 +- 修改商店的购买有效期不会改变玩家已购买的时间。 +- 一个称号可以多次被添加到商店,因此你可以将一个称号以多种不同的销售方式添加到商店,例如:1币购买1天,5币购买7天,100币购买永久。 + +## 指令 + +### 玩家指令 + +`/mplt` 打开 TUI 界面 + +`/mplt use [称号ID]` 使用称号 + +`/mplt list [页数(可选)]` 查看已拥有的称号 + +`/mplt shop [页数(可选)]` 查看商店 + +`/mplt buy [商品ID]` 购买称号 + +`/mplt custom [称号名称]` 自定义称号 + +`/mplt custominfo` 查看自定义称号帮助 + +### 管理员指令 + +`/mplt create [称号名称] [称号描述]` 创建称号 + +`/mplt delete [称号ID]` 删除称号 + +`/mplt setdesc [称号ID] [描述]` 设置称号描述 + +`/mplt setname [称号ID] [名称]` 设置称号名称 + +`/mplt addshop [称号ID]` 添加称号到商店 + +`/mplt removeshop [商品ID]` 从商店移除称号 + +`/mplt setprice [商品ID] [价格] [天数(-1为永久)]` 设置称号价格 + +`/mplt setamount [商品ID] [数量(-1为无限)]` 设置称号出售数量 + +`/mplt setendat [商品ID] [结束时间(格式:YYYYMMDD -1为永久)]` 设置称号销售结束时间 + +`/mplt listall [页数(可选)]` 查看所有称号 + +`/mplt addcoin [玩家名称] [数量]` 给玩家添加称号币 + +`/mplt setcoin [玩家名称] [数量]` 设置玩家称号币数量 + +## 配置文件参考 + +```yaml +# 数据库配置 +Database: + Host: localhost + Port: 5432 + Name: miniplayertitle + User: miniplayertitle + Pass: miniplayertitle + +# 称号前缀后缀 +Prefix: "[" +Suffix: "]" + +# 自定义称号配置 +CustomCost: + Enabled: true + Cost: 1000 + +# 玩家称号币初始值 +DefaultCoin: 0 + +Debug: false +``` + +## TODO diff --git a/pom.xml b/pom.xml index 57eda4e..09b9ffd 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ cn.lunadeer MiniPlayerTitle - 1.14-beta + 2.0 jar MiniPlayerTitle diff --git a/src/main/java/cn/lunadeer/miniplayertitle/Commands.java b/src/main/java/cn/lunadeer/miniplayertitle/Commands.java index 96cb39d..2b9b57f 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/Commands.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/Commands.java @@ -5,8 +5,11 @@ import cn.lunadeer.miniplayertitle.utils.Notification; import cn.lunadeer.miniplayertitle.utils.STUI.Button; import cn.lunadeer.miniplayertitle.utils.STUI.Line; import cn.lunadeer.miniplayertitle.utils.STUI.View; +import cn.lunadeer.miniplayertitle.utils.STUI.ViewStyles; import cn.lunadeer.miniplayertitle.utils.XLogger; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -55,6 +58,12 @@ public class Commands implements TabExecutor { case "buy": buy(sender, args); return true; + case "custom": + custom(sender, args); + return true; + case "custominfo": + custom_info(sender); + return true; case "create": AdminCommands.createTitle(sender, args); return true; @@ -103,12 +112,12 @@ public class Commands implements TabExecutor { private void printHelp(@NotNull CommandSender sender) { if (sender instanceof Player) { Player player = (Player) sender; - Notification.warn(player, "用法: /mplt "); + Notification.warn(player, "用法: /mplt "); if (player.isOp()) { Notification.warn(player, "用法: /mplt "); } } else { - XLogger.info("用法: /mplt "); + XLogger.info("用法: /mplt "); XLogger.info("用法: /mplt "); } } @@ -122,12 +131,39 @@ public class Commands implements TabExecutor { view.title("称号系统"); Component backpack = Button.create("称号背包", "/mplt list"); Component shop = Button.create("称号商店", "/mplt shop"); + Component custom = Button.create("自定义称号", "/mplt custominfo"); Line line = Line.create(); - line.append(backpack).append(shop); + line.append(backpack).append(shop).append(custom); view.actionBar(line); view.showOn((Player) sender); } + private void custom_info(CommandSender sender) { + if (!(sender instanceof Player)) { + printHelp(sender); + return; + } + Player player = (Player) sender; + View view = View.create(); + view.title("自定义称号帮助"); + view.subtitle("当前余额: " + XPlayer.getCoin(player) + "称号币"); + Line line_1 = Line.create(); + line_1.append("当前自定义称号状态:") + .append(MiniPlayerTitle.config.isEnableCustom() ? + Component.text("开启", ViewStyles.success_color) : + Component.text("关闭", ViewStyles.error_color)); + Line line_2 = Line.create(); + line_2.append("自定义称号花费:") + .append(MiniPlayerTitle.config.getCustomCost().toString()); + Line line_3 = Line.create(); + line_3.append("自定义方法:") + .append(Component.text("在聊天框输入 /mplt custom <称号>")); + view.addLine(line_1) + .addLine(line_2) + .addLine(line_3); + view.showOn(player); + } + /** * Requests a list of possible completions for a command argument. * @@ -144,7 +180,7 @@ public class Commands implements TabExecutor { @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if (args.length == 1) { - String[] player_cmd = {"use", "list", "shop", "buy"}; + String[] player_cmd = {"use", "list", "shop", "buy", "custom", "custominfo"}; String[] admin_cmd = {"create", "delete", "setdesc", "setname", "addshop", "removeshop", "setprice", "setamount", "setendat", "listall", "addcoin", "setcoin"}; List res = new ArrayList<>(); if (sender instanceof Player) { @@ -165,6 +201,8 @@ public class Commands implements TabExecutor { switch (args[0]) { case "use": return Collections.singletonList("要使用的称号ID"); + case "custom": + return Collections.singletonList("自定义称号"); case "list": case "shop": case "listall": @@ -223,7 +261,7 @@ public class Commands implements TabExecutor { return Collections.singletonList("<天数>(-1为永久)"); } } - return Arrays.asList("use", "list", "shop", "buy"); + return Arrays.asList("use", "list", "shop", "buy", "custom", "custominfo"); } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/MiniPlayerTitle.java b/src/main/java/cn/lunadeer/miniplayertitle/MiniPlayerTitle.java index 69ec5ad..2f24745 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/MiniPlayerTitle.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/MiniPlayerTitle.java @@ -6,6 +6,7 @@ import cn.lunadeer.miniplayertitle.utils.XLogger; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; +import java.sql.Connection; import java.util.Objects; public final class MiniPlayerTitle extends JavaPlugin { @@ -15,13 +16,14 @@ public final class MiniPlayerTitle extends JavaPlugin { // Plugin startup logic instance = this; config = new ConfigManager(instance); + dbConnection = Database.createConnection(); Database.migrate(); Bukkit.getPluginManager().registerEvents(new Events(), this); Objects.requireNonNull(Bukkit.getPluginCommand("MiniPlayerTitle")).setExecutor(new Commands()); Objects.requireNonNull(Bukkit.getPluginCommand("MiniPlayerTitle")).setTabCompleter(new Commands()); - String logo = "称号插件已加载\n"; + String logo = "称号插件已加载 版本: " + getPluginMeta().getVersion() + "\n"; // http://patorjk.com/software/taag/#p=display&f=Big&t=MiniPlayerTitle logo += " __ __ _ _ _____ _ _______ _ _ _\n" + " | \\/ (_) (_) __ \\| | |__ __(_) | | |\n" + @@ -41,4 +43,5 @@ public final class MiniPlayerTitle extends JavaPlugin { public static MiniPlayerTitle instance; public static ConfigManager config; + public static Connection dbConnection; } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/Shop.java b/src/main/java/cn/lunadeer/miniplayertitle/Shop.java index 5845803..3694b4d 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/Shop.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/Shop.java @@ -28,7 +28,7 @@ public class Shop { Player player = (Player) sender; ListView view = ListView.create(5, "/mplt shop"); view.title("称号商店"); - view.subtitle("当前余额: " + XPlayer.getCoin(player) + "金币"); + view.subtitle("当前余额: " + XPlayer.getCoin(player) + "称号币"); for (Map.Entry entry : titles.entrySet()) { Integer title_sale_id = entry.getKey(); TextComponent idx = Component.text("[" + title_sale_id + "] "); diff --git a/src/main/java/cn/lunadeer/miniplayertitle/Title.java b/src/main/java/cn/lunadeer/miniplayertitle/Title.java index 1626323..0d4a432 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/Title.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/Title.java @@ -123,14 +123,13 @@ public class Title { return this._id; } - public Component getTitle() { + public TextComponent getTitle() { TextComponent prefix = Component.text(MiniPlayerTitle.config.getPrefix()); TextComponent suffix = Component.text(MiniPlayerTitle.config.getSuffix()); String[] parts = this._title.split("&#"); List components = new ArrayList<>(); components.add(prefix); for (String part : parts) { - XLogger.debug(part); if (part.isEmpty()) { continue; } @@ -154,6 +153,24 @@ public class Title { return title_component.build().hoverEvent(HoverEvent.hoverEvent(HoverEvent.Action.SHOW_TEXT, Component.text(this._description))); } + public String getTitleContent() { + String[] parts = this._title.split("&#"); + StringBuilder res = new StringBuilder(); + for (String part : parts) { + if (part.isEmpty()) { + continue; + } + String content; + if (part.length() > 6 && part.substring(0, 6).matches("^[0-9a-fA-F]{6}$")) { + content = part.substring(6); + } else { + content = part; + } + res.append(content); + } + return res.toString(); + } + public void setTitle(String title) { this._title = title; this.save(); diff --git a/src/main/java/cn/lunadeer/miniplayertitle/XPlayer.java b/src/main/java/cn/lunadeer/miniplayertitle/XPlayer.java index f086091..9ba88a4 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/XPlayer.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/XPlayer.java @@ -23,8 +23,7 @@ public class XPlayer { public XPlayer(Player player) { _player = player; _titles = getTitles(player.getUniqueId()); - _current_title_id = getCurrentTitleId(player.getUniqueId()); - _coin = getCoin(player.getUniqueId()); + getInfo(); checkTitleValid(); } @@ -37,7 +36,7 @@ public class XPlayer { public void openBackpack(Integer page) { Collection titles = getTitles(_player.getUniqueId()).values(); - ListView view = ListView.create(4, "/mplt list"); + ListView view = ListView.create(5, "/mplt list"); view.title("我的称号"); for (PlayerTitle title : titles) { int title_id = title.getId(); @@ -58,17 +57,16 @@ public class XPlayer { _current_title_id = title_id; checkTitleValid(); String sql = ""; - sql += "UPDATE mplt_player_using_title "; - sql += "SET title_id = " + _current_title_id + ", "; + sql += "UPDATE mplt_player_info "; + sql += "SET using_title_id = " + _current_title_id + ", "; sql += "updated_at = CURRENT_TIMESTAMP "; - sql += "WHERE uuid = '" + _player.getUniqueId().toString() + "';"; + sql += "WHERE uuid = '" + _player.getUniqueId() + "';"; Database.query(sql); if (_current_title_id == -1) { Notification.info(_player, "成功卸下称号"); return; } - Notification.info(_player, "成功使用称号: "); - Notification.info(_player, _titles.get(_current_title_id).getTitle()); + Notification.info(_player, Component.text("成功使用称号: ").append(_titles.get(_current_title_id).getTitle())); } private void checkTitleValid() { @@ -82,8 +80,7 @@ public class XPlayer { } PlayerTitle title = _titles.get(_current_title_id); if (title.isExpired()) { - Notification.error(_player, "称号已过期"); - Notification.error(_player, title.getTitle()); + Notification.error(_player, title.getTitle().append(Component.text(" 称号已过期"))); _current_title_id = -1; } } @@ -91,7 +88,7 @@ public class XPlayer { public void set_coin(Integer coin) { _coin = coin; String sql = ""; - sql += "UPDATE mplt_player_coin "; + sql += "UPDATE mplt_player_info "; sql += "SET coin = " + coin + ", "; sql += "updated_at = CURRENT_TIMESTAMP "; sql += "WHERE uuid = '" + _player.getUniqueId().toString() + "';"; @@ -131,49 +128,29 @@ public class XPlayer { return titles; } - private static Integer getCurrentTitleId(UUID uuid) { + private void getInfo() { + UUID uuid = _player.getUniqueId(); String sql = ""; - sql += "SELECT title_id "; - sql += "FROM mplt_player_using_title "; + sql += "SELECT coin, using_title_id "; + sql += "FROM mplt_player_info "; sql += "WHERE uuid = '" + uuid.toString() + "';"; - int current_title_id = -1; + this._coin = MiniPlayerTitle.config.getDefaultCoin(); + this._current_title_id = -1; try (ResultSet rs = Database.query(sql)) { if (rs != null && rs.next()) { - current_title_id = rs.getInt("title_id"); + this._coin = rs.getInt("coin"); + this._current_title_id = rs.getInt("using_title_id"); } else { sql = ""; - sql += "INSERT INTO mplt_player_using_title (uuid, title_id) VALUES ("; + sql += "INSERT INTO mplt_player_info (uuid, coin, using_title_id) VALUES ("; sql += "'" + uuid + "', "; - sql += current_title_id + ");"; + sql += this._coin + ", "; + sql += this._current_title_id + ");"; Database.query(sql); } } catch (Exception e) { - XLogger.err("XPlayer getCurrentTitleId failed: " + e.getMessage()); + XLogger.err("XPlayer getInfo failed: " + e.getMessage()); } - return current_title_id; - } - - private static Integer getCoin(UUID uuid) { - String sql = ""; - sql += "SELECT coin "; - sql += "FROM mplt_player_coin "; - sql += "WHERE uuid = '" + uuid.toString() + "';"; - Integer coin = null; - try (ResultSet rs = Database.query(sql)) { - if (rs != null && rs.next()) { - coin = rs.getInt("coin"); - } else { - coin = 0; - sql = ""; - sql += "INSERT INTO mplt_player_coin (uuid, coin) VALUES ("; - sql += "'" + uuid + "', "; - sql += coin + ");"; - Database.query(sql); - } - } catch (Exception e) { - XLogger.err("XPlayer getCoin failed: " + e.getMessage()); - } - return coin; } public void buyTitle(SaleTitle title) { @@ -205,18 +182,46 @@ public class XPlayer { } set_coin(_coin - title.getPrice()); SaleTitle.setAmount(title.getId(), title.getAmount() - 1); - Notification.info(_player, "成功购买称号: "); - Notification.info(_player, title.getTitle()); + Notification.info(_player, Component.text("成功购买称号: ").append(title.getTitle())); + Notification.info(_player, "花费: " + title.getPrice() + "称号币,余额: " + _coin + "称号币"); if (title.getDays() == -1) { title_bought.setExpireAt(-1L); - Notification.info(_player, "称号已购买至永久"); + } else { + Long timestamp = System.currentTimeMillis() + title.getDays() * 24 * 60 * 60 * 1000L; + title_bought.setExpireAt((long) Time.getFromTimestamp(timestamp)); + } + Notification.info(_player, title.getTitle().append(Component.text(" 已购买至 " + title_bought.getExpireAtStr()))); + } + + public void custom(String title_str){ + if (this.get_coin() < MiniPlayerTitle.config.getCustomCost()) { + Notification.error(this._player, "称号币不足"); return; } - Long timestamp = System.currentTimeMillis() + title.getDays() * 24 * 60 * 60 * 1000L; - title_bought.setExpireAt((long) Time.getFromTimestamp(timestamp)); - Notification.info(_player, title.getTitle()); - Notification.info(_player, "称号已购买至 " + title_bought.getExpireAtStr()); - + List exist_titles = new ArrayList<>(); + for (Title title : Title.all()) { + exist_titles.add(title.getTitleContent()); + } + Title title = Title.create(title_str, this._player.getName() + "的自定义称号"); + if (title == null) { + Notification.error(this._player, "创建称号失败"); + return; + } + if (exist_titles.contains(title.getTitleContent())) { + Notification.error(this._player, "已存在同名称号"); + Title.delete(title.getId()); + return; + } + PlayerTitle playerTitle = PlayerTitle.create(title.getId(), this._player.getUniqueId()); + if (playerTitle == null) { + Notification.error(this._player, "创建称号失败"); + Title.delete(title.getId()); + return; + } + playerTitle.setExpireAt(-1L); + this.set_coin(this.get_coin() - MiniPlayerTitle.config.getCustomCost()); + Notification.info(this._player, Component.text("成功创建自定义称号: ").append(title.getTitle())); + Notification.info(this._player, "花费: " + MiniPlayerTitle.config.getCustomCost() + "称号币,余额: " + this.get_coin() + "称号币"); } } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/commands/AdminCommands.java b/src/main/java/cn/lunadeer/miniplayertitle/commands/AdminCommands.java index 79d8fdd..bc533a1 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/commands/AdminCommands.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/commands/AdminCommands.java @@ -116,7 +116,7 @@ public class AdminCommands { if (title == null) { Notification.error(sender, "添加商品失败"); } else { - Notification.info(sender, "已添加称号到商店, 商品ID: " + title.getId()); + Notification.info(sender, "已添加称号到商店, 商品ID: " + title.getSaleId()); Notification.info(sender, title.getTitle()); } } @@ -149,8 +149,23 @@ public class AdminCommands { Notification.warn(sender, "用法: /mplt setprice <商品ID> <价格> <天数>(-1为永久)"); return; } - SaleTitle.setPrice(Integer.parseInt(args[1]), Integer.parseInt(args[2])); - SaleTitle.setDays(Integer.parseInt(args[1]), Integer.parseInt(args[3])); + int price; + int days; + int id; + try { + price = Integer.parseInt(args[2]); + days = Integer.parseInt(args[3]); + id = Integer.parseInt(args[1]); + } catch (Exception e) { + Notification.error(sender, "价格或天数格式错误"); + return; + } + if (price < 0 || days < -1) { + Notification.error(sender, "价格或天数格式错误"); + return; + } + SaleTitle.setPrice(id, price); + SaleTitle.setDays(id, days); Notification.info(sender, "已设置商品价格"); } @@ -166,7 +181,16 @@ public class AdminCommands { Notification.warn(sender, "用法: /mplt setamount <商品ID> <数量>(-1为无限)"); return; } - SaleTitle.setAmount(Integer.parseInt(args[1]), Integer.parseInt(args[2])); + int amount; + int id; + try { + amount = Integer.parseInt(args[2]); + id = Integer.parseInt(args[1]); + } catch (Exception e) { + Notification.error(sender, "数量格式错误"); + return; + } + SaleTitle.setAmount(id, amount); Notification.info(sender, "已设置商品数量"); } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/commands/PlayerCommands.java b/src/main/java/cn/lunadeer/miniplayertitle/commands/PlayerCommands.java index 5372a5c..3cd41df 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/commands/PlayerCommands.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/commands/PlayerCommands.java @@ -1,11 +1,11 @@ package cn.lunadeer.miniplayertitle.commands; -import cn.lunadeer.miniplayertitle.SaleTitle; -import cn.lunadeer.miniplayertitle.Shop; -import cn.lunadeer.miniplayertitle.XPlayer; +import cn.lunadeer.miniplayertitle.*; import cn.lunadeer.miniplayertitle.utils.Notification; import cn.lunadeer.miniplayertitle.utils.XLogger; +import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; public class PlayerCommands { public static void use(CommandSender sender, String[] args) { @@ -22,7 +22,6 @@ public class PlayerCommands { XPlayer xPlayer = new XPlayer(player); Integer title_id = Integer.parseInt(args[1]); xPlayer.updateUsingTitle(title_id); - return; } public static void list(CommandSender sender, String[] args) { @@ -42,7 +41,6 @@ public class PlayerCommands { } XPlayer xPlayer = new XPlayer(player); xPlayer.openBackpack(page); - return; } public static void shop(CommandSender sender, String[] args) { @@ -54,7 +52,6 @@ public class PlayerCommands { } } Shop.open(sender, page); - return; } public static void buy(CommandSender sender, String[] args) { @@ -75,7 +72,6 @@ public class PlayerCommands { return; } xPlayer.buyTitle(saleTitle); - return; } public static void custom(CommandSender sender, String[] args) { @@ -83,16 +79,16 @@ public class PlayerCommands { XLogger.warn("该命令只能由玩家执行"); return; } - org.bukkit.entity.Player player = (org.bukkit.entity.Player) sender; + Player player = (Player) sender; if (args.length != 2) { Notification.warn(player, "用法: /mplt custom <称号>"); return; } - // todo add custom title - // add title - // description = player.getDisplayName() + "的自定义称号"; - // add player title - // expire_at = -1 - return; + if (!MiniPlayerTitle.config.isEnableCustom()) { + Notification.error(player, "自定义称号功能已关闭"); + return; + } + XPlayer xPlayer = new XPlayer(player); + xPlayer.custom(args[1]); } } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/utils/ConfigManager.java b/src/main/java/cn/lunadeer/miniplayertitle/utils/ConfigManager.java index b21267c..47208d8 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/utils/ConfigManager.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/utils/ConfigManager.java @@ -8,6 +8,7 @@ public class ConfigManager { _plugin = plugin; _plugin.saveDefaultConfig(); reload(); + _plugin.saveConfig(); } public void reload() { @@ -21,6 +22,9 @@ public class ConfigManager { _db_pass = _file.getString("Database.Pass", "postgres"); _prefix = _file.getString("Prefix", "["); _suffix = _file.getString("Suffix", "]"); + _default_coin = _file.getInt("DefaultCoin", 0); + _enable_custom = _file.getBoolean("CustomCost.Enabled", true); + _custom_cost = _file.getInt("CustomCost.Cost", 1000); } public Boolean isDebug() { @@ -33,7 +37,7 @@ public class ConfigManager { _plugin.saveConfig(); } - public String getDBConnectionUrl(){ + public String getDBConnectionUrl() { return "jdbc:postgresql://" + _db_host + ":" + _db_port + "/" + _db_name; } @@ -93,6 +97,36 @@ public class ConfigManager { return _suffix; } + public Integer getDefaultCoin() { + return _default_coin; + } + + public Boolean isEnableCustom() { + return _enable_custom; + } + + public Integer getCustomCost() { + return _custom_cost; + } + + public void enableCustom(){ + _enable_custom = true; + _file.set("CustomCost.Enabled", true); + _plugin.saveConfig(); + } + + public void disableCustom(){ + _enable_custom = false; + _file.set("CustomCost.Enabled", false); + _plugin.saveConfig(); + } + + public void setCustomCost(Integer cost){ + _custom_cost = cost; + _file.set("CustomCost.Cost", cost); + _plugin.saveConfig(); + } + private final MiniPlayerTitle _plugin; private FileConfiguration _file; @@ -105,4 +139,7 @@ public class ConfigManager { private String _db_name; private String _prefix; private String _suffix; + private Integer _default_coin; + private Boolean _enable_custom; + private Integer _custom_cost; } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/utils/Database.java b/src/main/java/cn/lunadeer/miniplayertitle/utils/Database.java index 77bce4b..f50c58b 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/utils/Database.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/utils/Database.java @@ -6,7 +6,7 @@ import java.sql.*; public class Database { - private static Connection getConnection() { + public static Connection createConnection(){ try { Class.forName("org.postgresql.Driver"); return DriverManager.getConnection(MiniPlayerTitle.config.getDBConnectionUrl(), MiniPlayerTitle.config.getDbUser(), MiniPlayerTitle.config.getDbPass()); @@ -17,7 +17,7 @@ public class Database { } public static ResultSet query(String sql) { - Connection conn = getConnection(); + Connection conn = MiniPlayerTitle.dbConnection; if (conn == null) { return null; } @@ -42,7 +42,7 @@ public class Database { // title table sql += "CREATE TABLE IF NOT EXISTS mplt_title (" + " id SERIAL PRIMARY KEY," + - " title TEXT NOT NULL," + + " title TEXT NOT NULL UNIQUE," + " description TEXT NOT NULL," + " enabled BOOLEAN NOT NULL DEFAULT TRUE," + " created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + @@ -62,12 +62,14 @@ public class Database { " FOREIGN KEY (title_id) REFERENCES mplt_title(id) ON DELETE CASCADE" + ");"; - // player coin table - sql += "CREATE TABLE IF NOT EXISTS mplt_player_coin (" + + // player title info table + sql += "CREATE TABLE IF NOT EXISTS mplt_player_info (" + " uuid UUID PRIMARY KEY," + " coin INTEGER NOT NULL DEFAULT 0," + + " using_title_id INTEGER NOT NULL DEFAULT -1," + " created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + - " updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" + + " updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + + " FOREIGN KEY (using_title_id) REFERENCES mplt_title(id) ON DELETE CASCADE" + ");"; // player title table @@ -78,16 +80,8 @@ public class Database { " expire_at BIGINT NOT NULL DEFAULT -1," + " created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + " updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + - " FOREIGN KEY (title_id) REFERENCES mplt_title(id) ON DELETE CASCADE" + - ");"; - - // player using title table - sql += "CREATE TABLE IF NOT EXISTS mplt_player_using_title (" + - " uuid UUID PRIMARY KEY," + - " title_id INTEGER NOT NULL," + - " created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + - " updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," + - " FOREIGN KEY (title_id) REFERENCES mplt_title(id) ON DELETE CASCADE" + + " FOREIGN KEY (title_id) REFERENCES mplt_title(id) ON DELETE CASCADE," + + " FOREIGN KEY (player_uuid) REFERENCES mplt_player_info(uuid) ON DELETE CASCADE" + ");"; sql += "INSERT INTO mplt_title (" + diff --git a/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/Pagination.java b/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/Pagination.java index c0d8f68..8479404 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/Pagination.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/Pagination.java @@ -24,10 +24,10 @@ public class Pagination { componentList.add(Component.text(page_count, sub_color)); componentList.add(Component.text(" 页 ", main_color)); if (page > 1) { - componentList.add(Button.create("[上一页]", command + " " + (page - 1))); + componentList.add(Button.create("上一页", command + " " + (page - 1))); } if (page < page_count) { - componentList.add(Button.create("[下一页]", command + " " + (page + 1))); + componentList.add(Button.create("下一页", command + " " + (page + 1))); } TextComponent.Builder builder = Component.text(); for (Component component : componentList) { diff --git a/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/View.java b/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/View.java index 5f3d4f2..5779be2 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/View.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/View.java @@ -4,30 +4,50 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import org.bukkit.entity.Player; +import javax.swing.*; import java.util.ArrayList; import java.util.List; import static cn.lunadeer.miniplayertitle.utils.STUI.ViewStyles.main_color; public class View { - protected TextComponent title_decorate = Component.text("===========", main_color); - protected TextComponent sub_title_decorate = Component.text("=====", main_color); - protected TextComponent line_decorate = Component.text("- ", main_color); - protected TextComponent action_decorate = Component.text("> ", main_color); + protected TextComponent title_decorate = Component.text("━", main_color); + protected TextComponent space = Component.text(" "); + protected TextComponent sub_title_decorate = Component.text("- ", main_color); + protected TextComponent line_decorate = Component.text("⌗ ", main_color); + protected TextComponent action_decorate = Component.text("▸ ", main_color); protected TextComponent title = Component.text(" "); - protected TextComponent subtitle = Component.text(" "); + protected TextComponent subtitle = Component.text(""); protected List content_lines = new ArrayList<>(); protected TextComponent actionbar = Component.text(" "); - protected TextComponent bottom_decorate = Component.text("=================================", main_color); + protected TextComponent edge = Component.text("━━━━━━━━━━━━━━━━━━━━━━━━━━━━", main_color); + protected TextComponent divide_line = Component.text("━━━━━━━━━━━━━━━━━━━━━━━━━━━━", main_color); public void showOn(Player player) { - player.sendMessage(Component.text().append(title_decorate).append(title).append(title_decorate).build()); - player.sendMessage(Component.text().append(sub_title_decorate).append(subtitle).build()); + player.sendMessage(edge); + TextComponent.Builder builder = Component.text(); + int title_length = title.content().length(); + int title_width = title_length * 2 + 2; + int decorate_count = divide_line.content().length() - title_width; + for (int i = 0; i < decorate_count / 2; i++) { + builder.append(title_decorate); + } + builder.append(space).append(title).append(space); + for (int i = 0; i < decorate_count / 2; i++) { + builder.append(title_decorate); + } + player.sendMessage(builder.build()); + if (subtitle.content().length() > 0) { + player.sendMessage(divide_line); + player.sendMessage(Component.text().append(sub_title_decorate).append(subtitle).build()); + } + player.sendMessage(divide_line); for (TextComponent content_line : content_lines) { player.sendMessage(Component.text().append(line_decorate).append(content_line).build()); } + player.sendMessage(divide_line); player.sendMessage(Component.text().append(action_decorate).append(actionbar).build()); - player.sendMessage(bottom_decorate); + player.sendMessage(edge); player.sendMessage(Component.text(" ")); } diff --git a/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/ViewStyles.java b/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/ViewStyles.java index b073b54..2e3ecb0 100644 --- a/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/ViewStyles.java +++ b/src/main/java/cn/lunadeer/miniplayertitle/utils/STUI/ViewStyles.java @@ -3,7 +3,9 @@ package cn.lunadeer.miniplayertitle.utils.STUI; import net.kyori.adventure.text.format.TextColor; public class ViewStyles { - public static TextColor main_color = TextColor.color(0, 179, 255); - public static TextColor sub_color = TextColor.color(143, 143, 143); + public static TextColor main_color = TextColor.color(0, 148, 213); + public static TextColor sub_color = TextColor.color(122, 122, 122); public static TextColor action_color = TextColor.color(251, 255, 139); + public static TextColor error_color = TextColor.color(255, 96, 72); + public static TextColor success_color = TextColor.color(139, 255, 123); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 18ad695..756ebb2 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,4 +8,10 @@ Database: Prefix: "[" Suffix: "]" +CustomCost: + Enabled: true + Cost: 1000 + +DefaultCoin: 0 + Debug: false \ No newline at end of file