finish some basic function

This commit is contained in:
zhangyuheng 2024-01-04 17:57:35 +08:00
parent b8f6e8af41
commit d608243025
16 changed files with 724 additions and 6 deletions

View File

@ -1,2 +1,2 @@
# NoobTitle
# NewbTitle

View File

@ -71,5 +71,10 @@
<version>1.20.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,53 @@
package cn.lunadeer.newbtitle;
import cn.lunadeer.newbtitle.utils.XLogger;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor;
public class Color {
public Integer r;
public Integer g;
public Integer b;
public String hex;
public Color(Integer r, Integer g, Integer b) {
this.r = r;
this.g = g;
this.b = b;
this.hex = String.format("#%02x%02x%02x", r, g, b);
}
public Color(String r, String g, String b) {
try {
this.r = Integer.valueOf(r);
this.g = Integer.valueOf(g);
this.b = Integer.valueOf(b);
this.hex = String.format("#%02x%02x%02x", this.r, this.g, this.b);
} catch (NumberFormatException e) {
this.r = 0;
this.g = 0;
this.b = 0;
this.hex = "#000000";
XLogger.err("Invalid color: " + r + ", " + g + ", " + b);
}
}
public Color(String hex) {
try {
this.hex = hex;
this.r = Integer.valueOf(hex.substring(1, 3), 16);
this.g = Integer.valueOf(hex.substring(3, 5), 16);
this.b = Integer.valueOf(hex.substring(5, 7), 16);
} catch (NumberFormatException e) {
this.r = 0;
this.g = 0;
this.b = 0;
this.hex = "#000000";
XLogger.err("Invalid color: " + hex);
}
}
public Style getStyle() {
return Style.style(TextColor.color(r, g, b));
}
}

View File

@ -0,0 +1,46 @@
package cn.lunadeer.newbtitle;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class Commands implements TabExecutor {
/**
* Executes the given command, returning its success.
* <br>
* If false is returned, then the "usage" plugin.yml entry for this command
* (if defined) will be sent to the player.
*
* @param sender Source of the command
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args Passed command arguments
* @return true if a valid command, otherwise false
*/
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return false;
}
/**
* Requests a list of possible completions for a command argument.
*
* @param sender Source of the command. For players tab-completing a
* command inside a command block, this will be the player, not
* the command block.
* @param command Command which was executed
* @param label Alias of the command which was used
* @param args The arguments passed to the command, including final
* partial argument to be completed
* @return A List of possible completions for the final argument, or null
* to default to the command executor
*/
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return null;
}
}

View File

@ -0,0 +1,4 @@
package cn.lunadeer.newbtitle;
public class Events {
}

View File

@ -1,6 +1,7 @@
package cn.lunadeer.newbtitle;
import cn.lunadeer.newbtitle.utils.ConfigManager;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public final class NewbTitle extends JavaPlugin {
@ -11,6 +12,7 @@ public final class NewbTitle extends JavaPlugin {
instance = this;
config = new ConfigManager(instance);
}
@Override

View File

@ -0,0 +1,28 @@
package cn.lunadeer.newbtitle;
public class PlayerTitle extends Title {
private Long _expire_at = -1L;
public PlayerTitle(Integer id, Long expire_at) {
super(id);
this._expire_at = expire_at;
}
public String getExpireAt() {
if (this._expire_at == -1L) {
return "永久";
} else if (this._expire_at < System.currentTimeMillis()) {
return "已过期";
} else {
return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(this._expire_at));
}
}
public Boolean isExpired() {
if (this._expire_at == -1L) {
return false;
} else {
return this._expire_at < System.currentTimeMillis();
}
}
}

View File

@ -0,0 +1,107 @@
package cn.lunadeer.newbtitle;
import cn.lunadeer.newbtitle.utils.Database;
import cn.lunadeer.newbtitle.utils.XLogger;
import java.sql.ResultSet;
public class SaleTitle extends Title {
private final Integer _id;
private final Integer _title_id;
private Integer _price;
private Integer _days;
private Integer _amount;
private Long _sale_end_at;
public SaleTitle(Integer id, Integer title_id, Integer price, Integer days, Integer amount, Long sale_end_at) {
super(title_id);
this._id = id;
this._title_id = title_id;
this._price = price;
this._days = days;
this._amount = amount;
this._sale_end_at = sale_end_at;
}
public static SaleTitle create(Integer title_id) {
String sql = "";
sql += "INSERT INTO nt_title_shop (title_id, price, days, amount, sale_end_at) ";
sql += "VALUES (" + title_id + ", 0, 0, -1, CURRENT_TIMESTAMP) ";
sql += "RETURNING id;";
ResultSet rs = Database.query(sql);
try {
if (rs != null && rs.next()) {
Integer id = rs.getInt("id");
return new SaleTitle(id, title_id, 0, 0, -1, System.currentTimeMillis());
}
} catch (Exception e) {
XLogger.err("SaleTitle create failed: " + e.getMessage());
}
return null;
}
public Integer getPrice() {
return this._price;
}
public void setPrice(Integer price) {
this._price = price;
this.save();
}
public Integer getDays() {
return this._days;
}
public void setDays(Integer days) {
this._days = days;
this.save();
}
public Integer getAmount() {
return this._amount;
}
public void setAmount(Integer amount) {
this._amount = amount;
this.save();
}
public String getSaleEndAt() {
if (this._sale_end_at == -1L) {
return "常驻";
} else if (this._sale_end_at < System.currentTimeMillis()) {
return "已停售";
} else {
return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(this._sale_end_at));
}
}
public void setSaleEndAt(Long sale_end_at) {
this._sale_end_at = sale_end_at;
this.save();
}
public Boolean isSaleExpired() {
if (this._sale_end_at == -1L) {
return false;
} else {
return this._sale_end_at < System.currentTimeMillis();
}
}
private void save() {
String sql = "";
sql += "UPDATE nt_title_shop ";
sql += "SET title_id = " + this._title_id + ", ";
sql += "price = " + this._price + ", ";
sql += "days = " + this._days + ", ";
sql += "amount = " + this._amount + ", ";
sql += "sale_end_at = " + this._sale_end_at + ", ";
sql += "updated_at = CURRENT_TIMESTAMP ";
sql += "WHERE id = " + this._id + ";";
Database.query(sql);
}
}

View File

@ -0,0 +1,4 @@
package cn.lunadeer.newbtitle;
public class Shop {
}

View File

@ -0,0 +1,129 @@
package cn.lunadeer.newbtitle;
import cn.lunadeer.newbtitle.utils.Database;
import cn.lunadeer.newbtitle.utils.XLogger;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.TextComponent;
import java.sql.ResultSet;
public class Title {
protected Integer _id = null;
protected String _title;
protected String _description;
protected Boolean _enabled;
protected String _created_at;
protected String _updated_at;
JoinConfiguration join = JoinConfiguration.separator(Component.text(" "));
public Title(String title, String description) {
this._title = title;
this._description = description;
this._enabled = true;
this.save();
}
public Title(Integer id) {
this._id = id;
String sql = "";
sql += "SELECT id, title, description, enabled, ";
sql += "DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') AS created_at, ";
sql += "DATE_FORMAT(updated_at, '%Y-%m-%d %H:%i:%s') AS updated_at ";
sql += "FROM nt_title ";
sql += "WHERE id = " + id + ";";
ResultSet rs = Database.query(sql);
try {
if (rs != null && rs.next()) {
this._title = rs.getString("title");
this._description = rs.getString("description");
this._enabled = rs.getBoolean("enabled");
this._created_at = rs.getString("created_at");
this._updated_at = rs.getString("updated_at");
}
} catch (Exception e) {
XLogger.err("Title load failed: " + e.getMessage());
}
}
public static void delete(Integer id) {
String sql = "";
sql += "DELETE FROM nt_title WHERE id = " + id + ";";
Database.query(sql);
}
private void save() {
String sql = "";
if (this._id == null) {
sql += "INSERT INTO nt_title (title, description, enabled) VALUES (";
sql += "'" + this._title + "', ";
sql += "'" + this._description + "', ";
sql += this._enabled + " ";
sql += ");";
} else {
sql += "UPDATE nt_title SET ";
sql += "title = '" + this._title + "', ";
sql += "description = '" + this._description + "', ";
sql += "enabled = " + this._enabled + " ";
sql += "updated_at = CURRENT_TIMESTAMP ";
sql += "WHERE id = " + this._id + ";";
}
Database.query(sql);
}
public Integer getId() {
return this._id;
}
public Component getTitle() {
String[] parts = this._title.split("&#");
TextComponent[] components = new TextComponent[parts.length];
if (parts[0].length() > 0) {
components[0] = Component.text(parts[0]);
}
for (int i = 1; i < parts.length; i++) {
String part = parts[i];
String color_str = part.substring(0, 6);
String text = part.substring(6);
Color color = new Color(color_str);
components[i] = Component.text(text, color.getStyle());
}
TextComponent prefix = Component.text(NewbTitle.config.getPrefix());
TextComponent suffix = Component.text(NewbTitle.config.getSuffix());
components[0] = prefix.append(components[0]);
components[parts.length - 1] = components[parts.length - 1].append(suffix);
return Component.join(join, components);
}
public void setTitle(String title) {
this._title = title;
this.save();
}
public String getDescription() {
return this._description;
}
public void setDescription(String description) {
this._description = description;
this.save();
}
public Boolean getEnabled() {
return this._enabled;
}
public void setEnabled(Boolean enabled) {
this._enabled = enabled;
this.save();
}
public String getCreatedAt() {
return this._created_at;
}
public String getUpdatedAt() {
return this._updated_at;
}
}

View File

@ -0,0 +1,158 @@
package cn.lunadeer.newbtitle;
import cn.lunadeer.newbtitle.utils.Database;
import cn.lunadeer.newbtitle.utils.Notification;
import cn.lunadeer.newbtitle.utils.XLogger;
import org.bukkit.entity.Player;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class XPlayer {
private final Player _player;
private Integer _coin;
private final Map<Integer, PlayerTitle> _titles;
private Integer _current_title_id = -1;
public XPlayer(Player player) {
_player = player;
_titles = getTitles(player.getUniqueId());
_current_title_id = getCurrentTitleId(player.getUniqueId());
_coin = getCoin(player.getUniqueId());
applyCurrentTitle();
}
public void updateUsingTitle(Integer title_id) {
_current_title_id = title_id;
applyCurrentTitle();
String sql = "";
sql += "UPDATE nt_player_using_title ";
sql += "SET title_id = " + title_id + ", ";
sql += "updated_at = CURRENT_TIMESTAMP ";
sql += "WHERE uuid = '" + _player.getUniqueId().toString() + "';";
Database.query(sql);
_current_title_id = title_id;
Notification.info(_player, "成功使用称号: " + _titles.get(title_id).getTitle());
}
private void applyCurrentTitle() {
if (_current_title_id == -1) {
return;
}
if (!_titles.containsKey(_current_title_id)) {
Notification.error(_player, "你没有这个称号");
_current_title_id = -1;
return;
}
PlayerTitle title = _titles.get(_current_title_id);
if (title.isExpired()) {
Notification.error(_player, "此称号已经过期");
_current_title_id = -1;
return;
}
_player.sendPlayerListHeader(title.getTitle());
}
public void set_coin(Integer coin) {
_coin = coin;
String sql = "";
sql += "UPDATE nt_player_coin ";
sql += "SET coin = " + coin + ", ";
sql += "updated_at = CURRENT_TIMESTAMP ";
sql += "WHERE uuid = '" + _player.getUniqueId().toString() + "';";
Database.query(sql);
}
public void add_coin(Integer coin) {
set_coin(_coin + coin);
}
private static Map<Integer, PlayerTitle> getTitles(UUID uuid) {
String sql = "";
sql += "SELECT ";
sql += "title_id, expire_at ";
sql += "FROM nt_player_title ";
sql += "WHERE player_uuid = '" + uuid.toString() + "';";
ResultSet rs = Database.query(sql);
Map<Integer, PlayerTitle> titles = new HashMap<>();
try {
while (rs != null && rs.next()) {
Integer title_id = rs.getInt("title_id");
Long expire_at = rs.getLong("expire_at");
PlayerTitle title = new PlayerTitle(title_id, expire_at);
titles.put(title_id, title);
}
} catch (Exception e) {
XLogger.err("XPlayer getTitles failed: " + e.getMessage());
}
return titles;
}
private static Integer getCurrentTitleId(UUID uuid) {
String sql = "";
sql += "SELECT title_id ";
sql += "FROM nt_player_using_title ";
sql += "WHERE uuid = '" + uuid.toString() + "';";
ResultSet rs = Database.query(sql);
Integer current_title_id = null;
try {
if (rs != null && rs.next()) {
current_title_id = rs.getInt("title_id");
} else {
current_title_id = -1;
sql = "";
sql += "INSERT INTO nt_player_using_title (uuid, title_id) VALUES (";
sql += "'" + uuid + "', ";
sql += current_title_id + ");";
Database.query(sql);
}
} catch (Exception e) {
XLogger.err("XPlayer getCurrentTitleId failed: " + e.getMessage());
}
return current_title_id;
}
private static Integer getCoin(UUID uuid) {
String sql = "";
sql += "SELECT coin ";
sql += "FROM nt_player_coin ";
sql += "WHERE uuid = '" + uuid.toString() + "';";
ResultSet rs = Database.query(sql);
Integer coin = null;
try {
if (rs != null && rs.next()) {
coin = rs.getInt("coin");
} else {
coin = 0;
sql = "";
sql += "INSERT INTO nt_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) {
if (title.isSaleExpired()) {
Notification.error(_player, "此称号已停止销售");
return;
}
if (title.getAmount() != -1 && title.getAmount() <= 0) {
Notification.error(_player, "此称号已售罄");
return;
}
if (title.getPrice() > _coin) {
Notification.error(_player, "你的余额不足");
return;
}
// todo 校验是否已有此称号 以及是否已过期
// todo 如果已则续费 如果未则购买
}
}

View File

@ -14,6 +14,13 @@ public class ConfigManager {
_plugin.reloadConfig();
_file = _plugin.getConfig();
_debug = _file.getBoolean("Debug", false);
_db_host = _file.getString("Database.Host", "localhost");
_db_port = _file.getString("Database.Port", "5432");
_db_name = _file.getString("Database.Name", "newbtitle");
_db_user = _file.getString("Database.User", "postgres");
_db_pass = _file.getString("Database.Pass", "postgres");
_prefix = _file.getString("Prefix", "[");
_suffix = _file.getString("Suffix", "]");
}
public Boolean isDebug() {
@ -26,9 +33,76 @@ public class ConfigManager {
_plugin.saveConfig();
}
public String getDBConnectionUrl(){
return "jdbc:postgresql://" + _db_host + ":" + _db_port + "/" + _db_name;
}
public void setDbHost(String db_host) {
_db_host = db_host;
_file.set("Database.Host", db_host);
_plugin.saveConfig();
}
private NewbTitle _plugin;
public void setDbPort(String db_port) {
_db_port = db_port;
_file.set("Database.Port", db_port);
_plugin.saveConfig();
}
public void setDbUser(String db_user) {
_db_user = db_user;
_file.set("Database.User", db_user);
_plugin.saveConfig();
}
public String getDbUser() {
if (_db_user.contains("@")) {
setDbUser("'" + _db_user + "'");
}
return _db_user;
}
public void setDbPass(String db_pass) {
_db_pass = db_pass;
_file.set("Database.Pass", db_pass);
_plugin.saveConfig();
}
public String getDbPass() {
if (_db_pass.contains("@")) {
setDbPass("'" + _db_pass + "'");
}
return _db_pass;
}
public void setDbName(String db_name) {
_db_name = db_name;
_file.set("Database.Name", db_name);
_plugin.saveConfig();
}
public String getPrefix() {
return _prefix;
}
public String getSuffix() {
return _suffix;
}
private final NewbTitle _plugin;
private FileConfiguration _file;
private Boolean _debug;
private String _db_host;
private String _db_port;
private String _db_user;
private String _db_pass;
private String _db_name;
private String _prefix;
private String _suffix;
}

View File

@ -0,0 +1,90 @@
package cn.lunadeer.newbtitle.utils;
import cn.lunadeer.newbtitle.NewbTitle;
import java.sql.*;
import java.util.Objects;
public class Database {
private static Connection getConnection() {
try {
Class.forName("org.postgresql.Driver");
return DriverManager.getConnection(NewbTitle.config.getDBConnectionUrl(), NewbTitle.config.getDbUser(), NewbTitle.config.getDbPass());
} catch (ClassNotFoundException | SQLException e) {
XLogger.err("Database connection failed: " + e.getMessage());
return null;
}
}
public static ResultSet query(String sql) {
try {
Connection connection = getConnection();
Statement statement = Objects.requireNonNull(connection).createStatement();
ResultSet res = statement.executeQuery(sql);
statement.close();
connection.close();
return res;
} catch (SQLException e) {
XLogger.err("Database query failed: " + e.getMessage());
return null;
}
}
public static void migrate() {
String sql = "";
// title table
sql += "CREATE TABLE IF NOT EXISTS 'nt_title' (" +
" id SERIAL PRIMARY KEY," +
" title TEXT NOT NULL," +
" description TEXT NOT NULL," +
" enabled BOOLEAN NOT NULL DEFAULT TRUE," +
" created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
" updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" +
");";
// title shop table
sql += "CREATE TABLE IF NOT EXISTS 'nt_title_shop' (" +
" id SERIAL PRIMARY KEY," +
" title_id INTEGER NOT NULL," +
" price INTEGER NOT NULL DEFAULT 0," +
" days INTEGER NOT NULL DEFAULT 0," +
" amount INTEGER NOT NULL DEFAULT -1," +
" sale_end_at TIMESTAMP," +
" created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
" updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
" FOREIGN KEY (title_id) REFERENCES nt_title(id) ON DELETE CASCADE" +
");";
// player coin table
sql += "CREATE TABLE IF NOT EXISTS 'nt_player_coin' (" +
" uuid UUID PRIMARY KEY," +
" coin INTEGER NOT NULL DEFAULT 0," +
" created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
" updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" +
");";
// player title table
sql += "CREATE TABLE IF NOT EXISTS 'nt_player_title' (" +
" id SERIAL PRIMARY KEY," +
" player_uuid UUID NOT NULL," +
" title_id INTEGER NOT NULL," +
" expire_at TIMESTAMP," +
" created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
" updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
" FOREIGN KEY (title_id) REFERENCES nt_title(id) ON DELETE CASCADE" +
");";
// player using title table
sql += "CREATE TABLE IF NOT EXISTS 'nt_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 nt_title(id) ON DELETE CASCADE" +
");";
query(sql);
}
}

View File

@ -11,15 +11,14 @@ public class Notification {
private static final Style e_style = Style.style(TextColor.color(255, 96, 72));
public static void info(Player player, String msg) {
player.sendMessage(Component.text("[LWE] " + msg, i_style));
player.sendMessage(Component.text("[NewbTitle] " + msg, i_style));
}
public static void warn(Player player, String msg) {
player.sendMessage(Component.text("[LWE] " + msg, w_style));
player.sendMessage(Component.text("[NewbTitle] " + msg, w_style));
}
public static void error(Player player, String msg) {
player.sendMessage(Component.text("[LWE] " + msg, e_style));
player.sendMessage(Component.text("[NewbTitle] " + msg, e_style));
}
}

View File

@ -0,0 +1,11 @@
Database:
Host: localhost
Port: 5432
Name: newbtitle
User: postgres
Pass: postgres
Prefix: "["
Suffix: "]"
Debug: false

View File

@ -2,3 +2,11 @@ name: NewbTitle
version: '${project.version}'
main: cn.lunadeer.newbtitle.NewbTitle
api-version: '1.20'
description: 称号插件。
website: https://lunadeer.cn
folia-supported: true
commands:
NewbTitle:
description: 称号插件命令
usage: /nt <cmd>
aliases: [nt]