finish every thing maybe...
Some checks failed
Java CI-CD with Maven / build (push) Failing after 1h39m1s

This commit is contained in:
zhangyuheng 2024-01-10 17:38:59 +08:00
parent ae252cb6ab
commit 4ece6c085e
15 changed files with 433 additions and 109 deletions

182
README.md
View File

@ -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颜色代码表示颜色例如`&#000000`表示黑色。可以使用 [Minecraft 渐变颜色生成器](https://ssl.lunadeer.cn:14440/) 来生成具有渐变效果的称号。
- 创建成功后会自动扣除所需的花费。
![image-20240110171242703](https://ssl.lunadeer.cn:14437/i/2024/01/10/659e5f8b2f5fb.png)
## 管理员指南
### 1. 创建称号
使用 `/mplt create [称号名称] [称号描述]` 创建称号称号支持RGB彩色字需要使用 `&#`为开头的十六进制RGB颜色代码表示颜色例如`&#000000`表示黑色。可以使用 [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

View File

@ -6,7 +6,7 @@
<groupId>cn.lunadeer</groupId>
<artifactId>MiniPlayerTitle</artifactId>
<version>1.14-beta</version>
<version>2.0</version>
<packaging>jar</packaging>
<name>MiniPlayerTitle</name>

View File

@ -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 <use|list|shop|buy>");
Notification.warn(player, "用法: /mplt <use|list|shop|buy|custom|custominfo>");
if (player.isOp()) {
Notification.warn(player, "用法: /mplt <create|delete|setdesc|setname|addshop|removeshop|setprice|setamount|setendat|listall>");
}
} else {
XLogger.info("用法: /mplt <use|list|shop|buy>");
XLogger.info("用法: /mplt <use|list|shop|buy|custom>");
XLogger.info("用法: /mplt <create|delete|setdesc|setname|addshop|removeshop|setprice|setamount|setendat|listall>");
}
}
@ -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<String> 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<String> 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");
}

View File

@ -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;
}

View File

@ -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<Integer, SaleTitle> entry : titles.entrySet()) {
Integer title_sale_id = entry.getKey();
TextComponent idx = Component.text("[" + title_sale_id + "] ");

View File

@ -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<TextComponent> 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();

View File

@ -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<PlayerTitle> 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, "称号已购买至永久");
return;
}
} else {
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());
}
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;
}
List<String> 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() + "称号币");
}
}

View File

@ -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, "已设置商品数量");
}

View File

@ -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
if (!MiniPlayerTitle.config.isEnableCustom()) {
Notification.error(player, "自定义称号功能已关闭");
return;
}
XPlayer xPlayer = new XPlayer(player);
xPlayer.custom(args[1]);
}
}

View File

@ -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;
}

View File

@ -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 (" +

View File

@ -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) {

View File

@ -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<TextComponent> 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(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(" "));
}

View File

@ -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);
}

View File

@ -8,4 +8,10 @@ Database:
Prefix: "["
Suffix: "]"
CustomCost:
Enabled: true
Cost: 1000
DefaultCoin: 0
Debug: false