diff --git a/README.md b/README.md index f1cb78a..716d0a1 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ repositories { dependencies { // 对于 Bukkit 插件 - compileOnly("cn.hamster3.mc.plugin:core-bukkit:1.3.3") + compileOnly("cn.hamster3.mc.plugin:core-bukkit:1.3.4-SNAPSHOT") // 对于 BungeeCord 插件 - compileOnly("cn.hamster3.mc.plugin:core-bungee:1.3.3") + compileOnly("cn.hamster3.mc.plugin:core-bungee:1.3.4-SNAPSHOT") } ``` @@ -54,13 +54,13 @@ dependencies { cn.hamster3.mc.plugin core-bukkit - 1.3.3 + 1.3.4-SNAPSHOT cn.hamster3.mc.plugin core-bungee - 1.3.3 + 1.3.4-SNAPSHOT diff --git a/build.gradle.kts b/build.gradle.kts index e4a617a..7774ec3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "cn.hamster3.mc.plugin" -version = "1.3.3" +version = "1.3.4-SNAPSHOT" description = "叁只仓鼠的 Minecraft 插件开发通用工具包" subprojects { @@ -38,6 +38,11 @@ subprojects { } tasks { + processResources { + filesMatching("update.yml") { + expand(rootProject.properties) + } + } withType { options.encoding = "UTF-8" } @@ -45,11 +50,6 @@ subprojects { from(rootProject.file("LICENSE")) duplicatesStrategy = DuplicatesStrategy.EXCLUDE } - processResources { - filesMatching("update.yml") { - expand(rootProject.properties) - } - } build { dependsOn(shadowJar) } diff --git a/core-bukkit/build.gradle.kts b/core-bukkit/build.gradle.kts index c8e8219..557a5e1 100644 --- a/core-bukkit/build.gradle.kts +++ b/core-bukkit/build.gradle.kts @@ -19,21 +19,15 @@ dependencies { exclude(group = "org.jetbrains") } // https://mvnrepository.com/artifact/redis.clients/jedis - api("redis.clients:jedis:5.1.2") { + api("redis.clients:jedis:5.1.4") { exclude(group = "com.google.code.gson") exclude(group = "org.slf4j") } - // https://mvnrepository.com/artifact/org.quartz-scheduler/quartz - api("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false } - // https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail - api("com.sun.mail:jakarta.mail:2.0.1") // https://www.spigotmc.org/resources/nbt-api.7939/ - implementation("de.tr7zw:item-nbt-api:2.12.2") + implementation("de.tr7zw:item-nbt-api:2.13.2") // https://mvnrepository.com/artifact/com.zaxxer/HikariCP implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") } - // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8 - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.23") { exclude(group = "org.jetbrains") } } tasks { diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java index 6047a14..b7e8e3e 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/HamsterCorePlugin.java @@ -11,11 +11,14 @@ import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener; import cn.hamster3.mc.plugin.core.bukkit.listener.DebugListener; import cn.hamster3.mc.plugin.core.bukkit.page.handler.PageHandler; import cn.hamster3.mc.plugin.core.bukkit.page.listener.PageListener; +import cn.hamster3.mc.plugin.core.bukkit.util.BukkitSimpleLogger; import cn.hamster3.mc.plugin.core.bukkit.util.MinecraftVersion; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.config.YamlConfig; import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils; +import com.zaxxer.hikari.HikariDataSource; +import de.tr7zw.changeme.nbtapi.NBT; import lombok.Getter; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.Bukkit; @@ -33,12 +36,13 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; -import java.util.logging.Logger; public class HamsterCorePlugin extends JavaPlugin { @Getter private static HamsterCorePlugin instance; @Getter + private static BukkitSimpleLogger simpleLogger; + @Getter private BukkitAudiences audienceProvider; /** @@ -66,15 +70,15 @@ public class HamsterCorePlugin extends JavaPlugin { @Override public void onLoad() { instance = this; + simpleLogger = new BukkitSimpleLogger(getInstance()); long start = System.currentTimeMillis(); - Logger logger = getLogger(); - logger.info("仓鼠核心正在初始化"); - logger.info("Minecraft 版本: " + MinecraftVersion.getMCVersion()); - logger.info("NMS 版本: " + MinecraftVersion.getNMSVersion()); + simpleLogger.info("仓鼠核心正在初始化"); + simpleLogger.info("Minecraft 版本: " + MinecraftVersion.getMCVersion()); + simpleLogger.info("NMS 版本: " + MinecraftVersion.getNMSVersion()); try { File dataFolder = getDataFolder(); if (dataFolder.mkdir()) { - logger.info("已生成插件存档文件夹"); + simpleLogger.info("已生成插件存档文件夹"); } File configFile = new File(dataFolder, "config.yml"); if (!configFile.exists()) { @@ -85,54 +89,59 @@ public class HamsterCorePlugin extends JavaPlugin { } } CoreBukkitAPI.init(configFile); - logger.info("已初始化 CoreAPI"); + simpleLogger.info("已初始化 CoreAPI"); } catch (Exception e) { - logger.warning("初始化 CoreAPI 出错"); - e.printStackTrace(); + simpleLogger.error(e, "初始化 CoreAPI 出错"); } CoreMessage.init(this); - logger.info("已初始化语言文本"); + simpleLogger.info("已初始化语言文本"); long time = System.currentTimeMillis() - start; - logger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms"); } @Override public void onEnable() { long start = System.currentTimeMillis(); - Logger logger = getLogger(); - logger.info("仓鼠核心正在启动"); + simpleLogger.info("仓鼠核心正在启动"); + NBT.preloadApi(); audienceProvider = BukkitAudiences.create(this); - logger.info("已创建 AudienceProvider"); + simpleLogger.info("已创建 AudienceProvider"); CoreCommand.INSTANCE.register(); LoreCommand.INSTANCE.register(); NBTCommand.INSTANCE.register(); Bukkit.getPluginManager().registerEvents(PageListener.INSTANCE, this); - logger.info("已注册 PageListener"); + simpleLogger.info("已注册 PageListener"); Bukkit.getPluginManager().registerEvents(CallbackListener.INSTANCE, this); - logger.info("已注册 CallbackListener"); + simpleLogger.info("已注册 CallbackListener"); Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this); - logger.info("已注册 DebugListener"); + simpleLogger.info("已注册 DebugListener"); + simpleLogger.info("Redis 启用状态: %b", CoreAPI.getInstance().isEnableRedis()); + simpleLogger.info("Database 启用状态: %b", CoreAPI.getInstance().isEnableDatabase()); + simpleLogger.info("已注册 DebugListener"); long time = System.currentTimeMillis() - start; sync(() -> { PointAPI.reloadPlayerPointAPIHook(); VaultAPI.reloadVaultHook(); async(this::checkUpdate); }); - logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); } @Override public void onDisable() { long start = System.currentTimeMillis(); - Logger logger = getLogger(); - CoreAPI.getInstance().getJedisPool().close(); - logger.info("已关闭 Redis 连接池"); - CoreAPI.getInstance().getHikariDataSource().close(); - logger.info("已关闭数据库连接池"); + if (CoreAPI.getInstance().isEnableRedis()) { + CoreAPI.getInstance().getJedisPool().close(); + simpleLogger.info("已关闭 Redis 连接池"); + } + if (CoreAPI.getInstance().isEnableDatabase()) { + ((HikariDataSource) CoreAPI.getInstance().getDataSource()).close(); + simpleLogger.info("已关闭数据库连接池"); + } CoreAPI.getInstance().getExecutorService().shutdownNow(); - logger.info("已关闭 ExecutorService 线程池"); + simpleLogger.info("已关闭 ExecutorService 线程池"); CoreAPI.getInstance().getScheduledService().shutdownNow(); - logger.info("已关闭 ScheduledExecutorService 线程池"); + simpleLogger.info("已关闭 ScheduledExecutorService 线程池"); for (Player player : Bukkit.getOnlinePlayers()) { InventoryView view = player.getOpenInventory(); Inventory inventory = view.getTopInventory(); @@ -141,9 +150,9 @@ public class HamsterCorePlugin extends JavaPlugin { } player.closeInventory(); } - logger.info("已关闭所有玩家的界面"); + simpleLogger.info("已关闭所有玩家的界面"); long time = System.currentTimeMillis() - start; - logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); } private void checkUpdate() { diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/api/CoreBukkitAPI.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/api/CoreBukkitAPI.java index af17474..645bcc9 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/api/CoreBukkitAPI.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/api/CoreBukkitAPI.java @@ -3,6 +3,7 @@ package cn.hamster3.mc.plugin.core.bukkit.api; import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin; import cn.hamster3.mc.plugin.core.bukkit.impl.ItemStackAdapter; import cn.hamster3.mc.plugin.core.bukkit.impl.PotionEffectAdapter; +import cn.hamster3.mc.plugin.core.bukkit.util.BukkitSimpleLogger; import cn.hamster3.mc.plugin.core.bukkit.util.MinecraftVersion; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; @@ -20,7 +21,6 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.util.logging.Logger; @SuppressWarnings("unused") public final class CoreBukkitAPI extends CoreAPI { @@ -62,8 +62,8 @@ public final class CoreBukkitAPI extends CoreAPI { } @Override - public @NotNull Logger getLogger() { - return HamsterCorePlugin.getInstance().getLogger(); + public @NotNull BukkitSimpleLogger getLogger() { + return HamsterCorePlugin.getSimpleLogger(); } @Override diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ChildCommand.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ChildCommand.java index 8f5a958..2f196b4 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ChildCommand.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ChildCommand.java @@ -11,6 +11,10 @@ public abstract class ChildCommand implements TabExecutor { @NotNull public abstract String getUsage(); + public int getArgumentCount() { + return 0; + } + @NotNull public abstract String getDescription(); diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ParentCommand.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ParentCommand.java index 5764792..d75eeb8 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ParentCommand.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/ParentCommand.java @@ -14,10 +14,10 @@ import java.util.stream.Collectors; @SuppressWarnings("unused") public abstract class ParentCommand extends ChildCommand { @NotNull - private final List childCommands; + private final Map childCommands; public ParentCommand() { - childCommands = new ArrayList<>(); + childCommands = new LinkedHashMap<>(); } @NotNull @@ -33,8 +33,8 @@ public abstract class ParentCommand extends ChildCommand { } @NotNull - public List getChildCommands() { - return childCommands; + public Collection getChildCommands() { + return childCommands.values(); } @NotNull @@ -78,7 +78,7 @@ public abstract class ParentCommand extends ChildCommand { @NotNull public List getEndChildCommands() { ArrayList list = new ArrayList<>(); - for (ChildCommand command : childCommands) { + for (ChildCommand command : getChildCommands()) { if (command instanceof ParentCommand) { list.addAll(((ParentCommand) command).getEndChildCommands()); } else { @@ -89,13 +89,16 @@ public abstract class ParentCommand extends ChildCommand { } public void addChildCommand(@NotNull ChildCommand command) { - childCommands.add(command); + if (childCommands.containsKey(command.getName())) { + throw new IllegalArgumentException("command " + command.getName() + " already exists!"); + } + childCommands.put(command.getName(), command); } @NotNull public Map getCommandHelp(CommandSender sender) { - HashMap map = new HashMap<>(); - for (ChildCommand child : childCommands) { + Map map = new LinkedHashMap<>(); + for (ChildCommand child : getChildCommands()) { if (!child.hasPermission(sender)) { continue; } @@ -111,14 +114,12 @@ public abstract class ParentCommand extends ChildCommand { public void sendHelp(@NotNull CommandSender sender) { sender.sendMessage("§e==================== [ " + getName() + " 使用帮助] ===================="); - Map helpMap = getCommandHelp(sender); - int maxLength = helpMap.keySet().stream() + Map map = getCommandHelp(sender); + int maxLength = map.keySet().stream() .map(String::length) .max(Integer::compareTo) .orElse(-1); - ArrayList> list = new ArrayList<>(helpMap.entrySet()); - list.sort(Map.Entry.comparingByKey()); - for (Map.Entry entry : list) { + for (Map.Entry entry : map.entrySet()) { sender.sendMessage(String.format("§a%-" + maxLength + "s - %s", entry.getKey(), entry.getValue())); } } @@ -133,7 +134,7 @@ public abstract class ParentCommand extends ChildCommand { sendHelp(sender); return true; } - for (ChildCommand childCommand : childCommands) { + for (ChildCommand childCommand : getChildCommands()) { if (!childCommand.getName().equalsIgnoreCase(args[0])) { continue; } @@ -141,6 +142,10 @@ public abstract class ParentCommand extends ChildCommand { CoreMessage.COMMAND_NOT_HAS_PERMISSION.show(sender); return true; } + if (args.length - 1 < getArgumentCount()) { + sender.sendMessage(getUsage() + " " + childCommand.getUsage()); + return true; + } return childCommand.onCommand(sender, command, label, Arrays.copyOfRange(args, 1, args.length)); } CoreMessage.COMMAND_NOT_FOUND.show(sender); @@ -150,18 +155,18 @@ public abstract class ParentCommand extends ChildCommand { @Override public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { if (args.length == 0) { - return childCommands.stream() + return getChildCommands().stream() .filter(o -> o.hasPermission(sender)) .map(ChildCommand::getName) .collect(Collectors.toList()); } - for (ChildCommand child : childCommands) { + for (ChildCommand child : getChildCommands()) { if (args[0].equalsIgnoreCase(child.getName())) { return child.onTabComplete(sender, command, alias, Arrays.copyOfRange(args, 1, args.length)); } } args[0] = args[0].toLowerCase(); - return childCommands.stream() + return getChildCommands().stream() .filter(o -> o.hasPermission(sender)) .map(ChildCommand::getName) .filter(o -> o.toLowerCase().startsWith(args[0].toLowerCase())) diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/core/sub/YamlCommand.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/core/sub/YamlCommand.java index e8a9ad9..2694777 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/core/sub/YamlCommand.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/core/sub/YamlCommand.java @@ -78,13 +78,13 @@ public class YamlCommand extends ChildCommand { config.set("test-item", stack); File dataFolder = new File(HamsterCorePlugin.getInstance().getDataFolder(), "yaml"); if (dataFolder.mkdirs()) { - HamsterCorePlugin.getInstance().getLogger().info("创建 yaml 存档文件夹"); + HamsterCorePlugin.getSimpleLogger().info("创建 yaml 存档文件夹"); } File saveFile = new File(dataFolder, sender.getName() + "_" + System.currentTimeMillis() + ".yml"); try { config.save(saveFile); } catch (IOException e) { - e.printStackTrace(); + HamsterCorePlugin.getSimpleLogger().error(e); } sender.sendMessage("§a信息已保存至文件 " + saveFile.getAbsolutePath()); return true; diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/nbt/NBTCommand.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/nbt/NBTCommand.java index 995a14f..826f93a 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/nbt/NBTCommand.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/command/nbt/NBTCommand.java @@ -5,6 +5,9 @@ import cn.hamster3.mc.plugin.core.bukkit.command.ParentCommand; import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage; import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils; import de.tr7zw.changeme.nbtapi.*; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTList; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -62,13 +65,12 @@ public class NBTCommand extends ParentCommand { sender.sendMessage("§c你的手持物品为空"); return true; } - NBTItem nbtItem = new NBTItem(stack); - sendNBTCompound(nbtItem, sender, 0); + ReadWriteNBT readWriteNBT = NBT.itemStackToNBT(stack); + sendNBTCompound(readWriteNBT, sender, 0); return true; } - @SuppressWarnings("ForLoopReplaceableByForEach") - private void sendNBTCompound(NBTCompound compound, CommandSender sender, int level) { + private void sendNBTCompound(ReadWriteNBT compound, CommandSender sender, int level) { StringBuilder prefixBuilder = new StringBuilder(); for (int i = 0; i < level; i++) { prefixBuilder.append(" "); @@ -78,31 +80,31 @@ public class NBTCommand extends ParentCommand { NBTType type = compound.getType(key); switch (type) { case NBTTagByte: { - sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getByte(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getByte(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagShort: { - sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getShort(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getShort(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagInt: { - sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getInteger(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getInteger(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagLong: { - sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getLong(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getLong(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagFloat: { - sender.sendMessage(String.format("%s- %s:%f §e§l[%s]", space, key, compound.getFloat(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%f §e§l[%s]", space, key, compound.getFloat(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagDouble: { - sender.sendMessage(String.format("%s- %s:%f §e§l[%s]", space, key, compound.getDouble(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%f §e§l[%s]", space, key, compound.getDouble(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagString: { - sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, compound.getString(key), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, compound.getString(key), NBT_TYPE_NAME.get(type))); break; } case NBTTagCompound: { @@ -112,20 +114,20 @@ public class NBTCommand extends ParentCommand { } case NBTTagByteArray: { byte[] array = compound.getByteArray(key); - sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type))); break; } case NBTTagIntArray: { int[] array = compound.getIntArray(key); - sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type))); if (array != null && array.length == 4) { - sender.sendMessage(String.format("%s- %s:%s §e§l[uuid]", space, key, compound.getUUID(key))); + sender.sendMessage(String.format("%s- %s=%s §e§l[uuid]", space, key, compound.getUUID(key))); } break; } case NBTTagLongArray: { long[] array = compound.getLongArray(key); - sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type))); + sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type))); break; } case NBTTagList: { @@ -137,7 +139,7 @@ public class NBTCommand extends ParentCommand { String listSpace = space + " "; switch (listType) { case NBTTagString: { - NBTList list = compound.getStringList(key); + ReadWriteNBTList list = compound.getStringList(key); for (String string : list) { sender.sendMessage(String.format("%s- %s", listSpace, string)); } @@ -145,7 +147,7 @@ public class NBTCommand extends ParentCommand { } case NBTTagIntArray: { boolean all4Length = true; - NBTList list = compound.getIntArrayList(key); + ReadWriteNBTList list = compound.getIntArrayList(key); for (int[] intArray : list) { if (intArray.length != 4) { all4Length = false; @@ -153,7 +155,7 @@ public class NBTCommand extends ParentCommand { } } if (all4Length) { - NBTList uuidList = compound.getUUIDList(key); + ReadWriteNBTList uuidList = compound.getUUIDList(key); for (int i = 0; i < list.size(); i++) { int[] intArray = list.get(i); UUID uuid = uuidList.get(i); @@ -169,37 +171,37 @@ public class NBTCommand extends ParentCommand { break; } case NBTTagInt: { - NBTList list = compound.getIntegerList(key); + ReadWriteNBTList list = compound.getIntegerList(key); for (Integer value : list) { sender.sendMessage(String.format("%s- %d", listSpace, value)); } break; } case NBTTagLong: { - NBTList list = compound.getLongList(key); + ReadWriteNBTList list = compound.getLongList(key); for (Long value : list) { sender.sendMessage(String.format("%s- %d", listSpace, value)); } break; } case NBTTagFloat: { - NBTList list = compound.getFloatList(key); + ReadWriteNBTList list = compound.getFloatList(key); for (Float value : list) { sender.sendMessage(String.format("%s- %f", listSpace, value)); } break; } case NBTTagDouble: { - NBTList list = compound.getDoubleList(key); + ReadWriteNBTList list = compound.getDoubleList(key); for (Double value : list) { sender.sendMessage(String.format("%s- %f", listSpace, value)); } break; } case NBTTagCompound: { - NBTCompoundList compoundList = compound.getCompoundList(key); + ReadWriteNBTCompoundList compoundList = compound.getCompoundList(key); for (int i = 0; i < compoundList.size(); i++) { - NBTListCompound listCompound = compoundList.get(i); + ReadWriteNBT listCompound = compoundList.get(i); sendNBTCompound(listCompound, sender, level + 1); } } diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/constant/CoreMessage.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/constant/CoreMessage.java index 8337548..2879851 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/constant/CoreMessage.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/constant/CoreMessage.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; +import java.util.logging.Level; @Getter public enum CoreMessage { @@ -70,7 +71,6 @@ public enum CoreMessage { this.message = new DisplayMessage().setMessage(message); } - @SuppressWarnings("CallToPrintStackTrace") public static void init(@NotNull Plugin plugin) { File dataFolder = plugin.getDataFolder(); if (dataFolder.mkdirs()) { @@ -82,8 +82,7 @@ public enum CoreMessage { try { config.load(file); } catch (Exception e) { - plugin.getLogger().warning("加载消息配置文件时出现了一个异常:"); - e.printStackTrace(); + plugin.getLogger().log(Level.WARNING, "加载消息配置文件时出现了一个异常:", e); } } for (CoreMessage value : values()) { @@ -96,15 +95,13 @@ public enum CoreMessage { try { value.message = CoreBukkitUtils.loadDisplayMessage(section); } catch (Exception e) { - plugin.getLogger().warning("加载消息设置 " + value.name() + " 时遇到了一个异常: "); - e.printStackTrace(); + plugin.getLogger().log(Level.WARNING, "加载消息设置 " + value.name() + " 时遇到了一个异常: ", e); } } try { config.save(file); } catch (IOException e) { - plugin.getLogger().warning("保存消息配置文件时出现了一个异常:"); - e.printStackTrace(); + plugin.getLogger().log(Level.WARNING, "保存消息配置文件时出现了一个异常:", e); } } diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/EconomyAPI.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/EconomyAPI.java index 37a790e..6600a35 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/EconomyAPI.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/EconomyAPI.java @@ -20,7 +20,7 @@ public class EconomyAPI { * @return true代表安装了,false代表未安装 */ public static boolean isSetupEconomy() { - return VaultAPI.isSetupVault() && VaultAPI.getEconomy() != null; + return VaultAPI.isVaultEnabled() && VaultAPI.getEconomy() != null; } /** diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/PointAPI.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/PointAPI.java index 55c78b2..b2e44e7 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/PointAPI.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/PointAPI.java @@ -1,6 +1,7 @@ package cn.hamster3.mc.plugin.core.bukkit.hook; import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin; +import lombok.Getter; import org.black_ixx.playerpoints.PlayerPoints; import org.black_ixx.playerpoints.PlayerPointsAPI; import org.bukkit.Bukkit; @@ -14,6 +15,7 @@ import java.util.UUID; */ @SuppressWarnings("unused") public class PointAPI { + @Getter private static PlayerPointsAPI playerPointsAPI; private PointAPI() { @@ -25,20 +27,10 @@ public class PointAPI { public static void reloadPlayerPointAPIHook() { Plugin plugin = Bukkit.getPluginManager().getPlugin("PlayerPoints"); if (plugin == null) { - HamsterCorePlugin.getInstance().getLogger().warning("未检测到 PlayerPointAPI 插件"); return; } playerPointsAPI = ((PlayerPoints) plugin).getAPI(); - HamsterCorePlugin.getInstance().getLogger().info("PlayerPointAPI 挂接成功"); - } - - /** - * 获取 PlayerPointsAPI 实例 - * - * @return PlayerPointsAPI 实例 - */ - public static PlayerPointsAPI getPlayerPointsAPI() { - return playerPointsAPI; + HamsterCorePlugin.getSimpleLogger().info("已挂接 PlayerPointAPI"); } /** diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/VaultAPI.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/VaultAPI.java index 0c7c12f..6f08685 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/VaultAPI.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/hook/VaultAPI.java @@ -1,22 +1,27 @@ package cn.hamster3.mc.plugin.core.bukkit.hook; import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin; +import cn.hamster3.mc.plugin.core.bukkit.util.BukkitSimpleLogger; +import lombok.Getter; import net.milkbowl.vault.chat.Chat; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.plugin.RegisteredServiceProvider; -import java.util.logging.Logger; - /** * Vault API */ +@Getter @SuppressWarnings("unused") public class VaultAPI { + @Getter private static boolean vaultEnabled; + @Getter private static Chat chat; + @Getter private static Economy economy; + @Getter private static Permission permission; private VaultAPI() { @@ -27,74 +32,27 @@ public class VaultAPI { economy = null; permission = null; vaultEnabled = Bukkit.getPluginManager().isPluginEnabled("Vault"); - Logger logger = HamsterCorePlugin.getInstance().getLogger(); + BukkitSimpleLogger logger = HamsterCorePlugin.getSimpleLogger(); if (!vaultEnabled) { - logger.warning("未检测到 Vault 插件"); return; } - logger.info("已连接 Vault"); - + logger.info("检测到服务器已安装 Vault 插件"); RegisteredServiceProvider chatProvider = Bukkit.getServer().getServicesManager().getRegistration(Chat.class); - if (chatProvider != null) { chat = chatProvider.getProvider(); logger.info("聊天系统挂接成功"); - } else { - logger.warning("未检测到聊天系统"); } - RegisteredServiceProvider economyProvider = Bukkit.getServer().getServicesManager().getRegistration(Economy.class); if (economyProvider != null) { economy = economyProvider.getProvider(); logger.info("经济系统挂接成功"); - } else { - logger.warning("未检测到经济系统"); } - RegisteredServiceProvider permissionProvider = Bukkit.getServer().getServicesManager().getRegistration(Permission.class); if (permissionProvider != null) { permission = permissionProvider.getProvider(); logger.info("权限系统挂接成功"); - } else { - logger.warning("未检测到权限插件"); } logger.info("已完成 VaultAPI 挂载"); } - /** - * 返回服务器是否安装了 Vault 插件 - * - * @return true 代表服务器已安装 - */ - public static boolean isSetupVault() { - return vaultEnabled; - } - - /** - * 返回 Vault 的 Chat 前置系统 - * - * @return Chat 系统 - */ - public static Chat getChat() { - return chat; - } - - /** - * 返回 Vault 的 Economy 前置系统 - * - * @return Economy 系统 - */ - public static Economy getEconomy() { - return economy; - } - - /** - * 返回 Vault 的 Permission 前置系统 - * - * @return Permission 系统 - */ - public static Permission getPermission() { - return permission; - } - -} +} \ No newline at end of file diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/ButtonGroup.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/ButtonGroup.java index 07e59dc..d77ad06 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/ButtonGroup.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/ButtonGroup.java @@ -188,8 +188,8 @@ public class ButtonGroup { @Override public String toString() { return "ButtonGroup{" + - "name='" + name + '\'' + - ", buttonNameMap=" + buttonNameMap + - '}'; + "name='" + name + '\'' + + ", buttonNameMap=" + buttonNameMap + + '}'; } } diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/PageConfig.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/PageConfig.java index 928f599..9ca0df9 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/PageConfig.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/PageConfig.java @@ -98,8 +98,7 @@ public class PageConfig implements InventoryHolder { try { buttonSounds.put(key, Sound.valueOf(soundName)); } catch (Exception e) { - HamsterCorePlugin.getInstance().getLogger().warning("初始化 PageConfig 时遇到了一个异常:"); - e.printStackTrace(); + HamsterCorePlugin.getSimpleLogger().error(e, "初始化 PageConfig 时遇到了一个异常: "); } } } @@ -197,10 +196,10 @@ public class PageConfig implements InventoryHolder { @Override public String toString() { return "PageConfig{" + - ", title='" + title + '\'' + - ", graphic=" + graphic + - ", buttonMap=" + buttons + - ", buttonGroups=" + buttonGroups + - '}'; + ", title='" + title + '\'' + + ", graphic=" + graphic + + ", buttonMap=" + buttons + + ", buttonGroups=" + buttonGroups + + '}'; } } diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/listener/PageListener.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/listener/PageListener.java index e0a82bc..493be4b 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/listener/PageListener.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/page/listener/PageListener.java @@ -39,8 +39,7 @@ public class PageListener implements Listener { try { pageHandler.onClick(event); } catch (Exception e) { - HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onClick(event) 时遇到了一个异常: ", pageHandler.getClass().getName())); - e.printStackTrace(); + HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onClick(event) 时遇到了一个异常: ", pageHandler.getClass().getName()); } if (event.isCancelled()) { return; @@ -55,31 +54,29 @@ public class PageListener implements Listener { try { pageHandler.onClickInside(event); } catch (Exception e) { - HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onClickInside(event) 时遇到了一个异常: ", pageHandler.getClass().getName())); - e.printStackTrace(); + HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onClickInside(event) 时遇到了一个异常: ", pageHandler.getClass().getName()); } try { pageHandler.onClickInside(event.getClick(), event.getAction(), index); } catch (Exception e) { - HamsterCorePlugin.getInstance().getLogger().warning(String.format( + HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onClickInside(%s, %s, %d) 时遇到了一个异常: ", pageHandler.getClass().getName(), event.getClick().name(), event.getAction().name(), index - )); - e.printStackTrace(); + ); } try { pageHandler.onPlayButtonSound(event.getClick(), event.getAction(), index); } catch (Exception e) { - HamsterCorePlugin.getInstance().getLogger().warning(String.format( + HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onPlayButtonSound(%s, %s, %d) 时遇到了一个异常: ", pageHandler.getClass().getName(), event.getClick().name(), event.getAction().name(), index - )); + ); } } @@ -93,8 +90,7 @@ public class PageListener implements Listener { try { pageHandler.onDrag(event); } catch (Exception e) { - HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onDrag(event) 时遇到了一个异常: ", pageHandler.getClass().getName())); - e.printStackTrace(); + HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onDrag(event) 时遇到了一个异常: ", pageHandler.getClass().getName()); } if (event.isCancelled()) { return; diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/BukkitSimpleLogger.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/BukkitSimpleLogger.java new file mode 100644 index 0000000..fd0db59 --- /dev/null +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/BukkitSimpleLogger.java @@ -0,0 +1,38 @@ +package cn.hamster3.mc.plugin.core.bukkit.util; + +import cn.hamster3.mc.plugin.core.common.util.SimpleLogger; +import lombok.Getter; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.logging.Level; +import java.util.logging.Logger; + +@Getter +@SuppressWarnings("unused") +public class BukkitSimpleLogger extends SimpleLogger { + @NotNull + private final Plugin plugin; + @NotNull + private final Logger logger; + + public BukkitSimpleLogger(@NotNull Plugin plugin) { + this.plugin = plugin; + logger = plugin.getLogger(); + } + + @Override + public void log(@NotNull Level level, @NotNull String msg) { + logger.log(level, msg); + } + + @Override + public void log(@NotNull Level level, @NotNull Throwable throwable) { + logger.log(level, "", throwable); + } + + @Override + public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg) { + logger.log(level, msg, throwable); + } +} diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/CoreBukkitUtils.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/CoreBukkitUtils.java index 1d659a7..d36edcf 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/CoreBukkitUtils.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/CoreBukkitUtils.java @@ -3,10 +3,10 @@ package cn.hamster3.mc.plugin.core.bukkit.util; import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener; import cn.hamster3.mc.plugin.core.common.data.DisplayMessage; import com.google.gson.JsonObject; -import de.tr7zw.changeme.nbtapi.NBTContainer; -import de.tr7zw.changeme.nbtapi.NBTItem; +import de.tr7zw.changeme.nbtapi.NBT; import me.clip.placeholderapi.PlaceholderAPI; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.title.Title; import org.bukkit.Bukkit; @@ -241,23 +241,45 @@ public final class CoreBukkitUtils { @NotNull public static DisplayMessage loadDisplayMessage(@NotNull ConfigurationSection config) { DisplayMessage displayMessage = new DisplayMessage(); - String message = config.getString("message"); - if (message != null) { - displayMessage.setMessage(LegacyComponentSerializer.legacySection().deserialize(message)); + String miniMessage = config.getString("mini-message"); + if (miniMessage != null) { + displayMessage.setMessage(MiniMessage.miniMessage().deserialize(miniMessage)); + } else { + String message = config.getString("message"); + if (message != null) { + displayMessage.setMessage(LegacyComponentSerializer.legacySection().deserialize(message)); + } } - String actionbar = config.getString("actionbar"); - if (actionbar != null) { - displayMessage.setActionbar(LegacyComponentSerializer.legacySection().deserialize(actionbar)); + String miniActionbar = config.getString("mini-actionbar"); + if (miniActionbar != null) { + displayMessage.setActionbar(MiniMessage.miniMessage().deserialize(miniActionbar)); + } else { + String actionbar = config.getString("actionbar"); + if (actionbar != null) { + displayMessage.setActionbar(LegacyComponentSerializer.legacySection().deserialize(actionbar)); + } } - String title = config.getString("title"); - String subtitle = config.getString("subtitle"); - if (title != null || subtitle != null) { + String miniTitle = config.getString("mini-title"); + String miniSubtitle = config.getString("mini-subtitle"); + if (miniTitle != null || miniSubtitle != null) { displayMessage.setTitle( - title, subtitle, + MiniMessage.miniMessage().deserialize(miniTitle == null ? "" : miniTitle), + MiniMessage.miniMessage().deserialize(miniSubtitle == null ? "" : miniSubtitle), config.getInt("fade-in", 10), config.getInt("stay", 70), config.getInt("fade-out", 20) ); + } else { + String title = config.getString("title"); + String subtitle = config.getString("subtitle"); + if (title != null || subtitle != null) { + displayMessage.setTitle( + title, subtitle, + config.getInt("fade-in", 10), + config.getInt("stay", 70), + config.getInt("fade-out", 20) + ); + } } String sound = config.getString("sound"); if (sound != null) { @@ -330,7 +352,7 @@ public final class CoreBukkitUtils { */ @NotNull public static String serializeItemStack(@NotNull ItemStack stack) { - return NBTItem.convertItemtoNBT(stack).toString(); + return NBT.itemStackToNBT(stack).toString(); } /** @@ -341,7 +363,7 @@ public final class CoreBukkitUtils { */ @Nullable public static ItemStack deserializeItemStack(@NotNull String string) { - return NBTItem.convertNBTtoItem(new NBTContainer(string)); + return NBT.itemStackFromNBT(NBT.parseNBT(string)); } /** diff --git a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/MinecraftVersion.java b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/MinecraftVersion.java index 3b70e19..34a99fa 100644 --- a/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/MinecraftVersion.java +++ b/core-bukkit/src/main/java/cn/hamster3/mc/plugin/core/bukkit/util/MinecraftVersion.java @@ -7,18 +7,18 @@ import org.jetbrains.annotations.NotNull; @SuppressWarnings("unused") public class MinecraftVersion { @Getter - public static final int Version1; + public static final int version1; @Getter - public static final int Version2; + public static final int version2; @Getter - public static final int Version3; + public static final int version3; static { String version = getMCVersion(); String[] split = version.split("\\."); - Version1 = Integer.parseInt(split[0]); - Version2 = Integer.parseInt(split[1]); - Version3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0; + version1 = Integer.parseInt(split[0]); + version2 = Integer.parseInt(split[1]); + version3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0; } /** @@ -35,18 +35,18 @@ public class MinecraftVersion { */ public static int compareTo(@NotNull String version) { String[] split = version.split("\\."); - int version1 = Integer.parseInt(split[0]); - int version2 = Integer.parseInt(split[1]); - int version3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0; - int compare = Integer.compare(Version1, version1); + int compareVersion1 = Integer.parseInt(split[0]); + int compareVersion2 = Integer.parseInt(split[1]); + int compareVersion3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0; + int compare = Integer.compare(compareVersion1, MinecraftVersion.version1); if (compare != 0) { return compare; } - compare = Integer.compare(Version2, version2); + compare = Integer.compare(compareVersion2, MinecraftVersion.version2); if (compare != 0) { return compare; } - return Integer.compare(Version3, version3); + return Integer.compare(compareVersion3, MinecraftVersion.version3); } @NotNull @@ -61,8 +61,10 @@ public class MinecraftVersion { @NotNull public static Class getNMSClass(@NotNull String className) throws ClassNotFoundException { - if (Version2 >= 17) { - return Class.forName("net.minecraft.server." + className); + if (version1 >= 1) { + if (version2 >= 17) { + return Class.forName("net.minecraft.server." + className); + } } String nmsVersion = getNMSVersion(); return Class.forName("net.minecraft.server." + nmsVersion + "." + className); @@ -70,9 +72,8 @@ public class MinecraftVersion { @NotNull public static Class getNMSClassSilent(@NotNull String className) { - String nmsVersion = getNMSVersion(); try { - return Class.forName("net.minecraft.server." + nmsVersion + "." + className); + return getNMSClass(className); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } @@ -80,15 +81,22 @@ public class MinecraftVersion { @NotNull public static Class getCraftBukkitClass(@NotNull String className) throws ClassNotFoundException { + if (version1 >= 1) { + if (version2 >= 21) { + return Class.forName("org.bukkit.craftbukkit." + className); + } + if (version2 == 20 && version3 >= 6) { + return Class.forName("org.bukkit.craftbukkit." + className); + } + } String nmsVersion = getNMSVersion(); return Class.forName("org.bukkit.craftbukkit." + nmsVersion + "." + className); } @NotNull public static Class getCraftBukkitClassSilent(@NotNull String className) { - String nmsVersion = getNMSVersion(); try { - return Class.forName("org.bukkit.craftbukkit." + nmsVersion + "." + className); + return getCraftBukkitClass(className); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } diff --git a/core-bukkit/src/main/resources/config.yml b/core-bukkit/src/main/resources/config.yml index 0babd79..6963a3f 100644 --- a/core-bukkit/src/main/resources/config.yml +++ b/core-bukkit/src/main/resources/config.yml @@ -1,3 +1,6 @@ +# 是否启用 redis 连接池功能 +enable-redis: false + # redis 连接配置 # 完整格式如下: # redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值 @@ -8,15 +11,16 @@ # 若不设置数据库,则默认使用 0 redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s" +# 是否启用数据库连接池功能 +enable-database: false + +# 数据库连接池配置 datasource: # 数据库链接驱动地址,旧版服务端(低于1.13)请使用:com.mysql.jdbc.Driver driver: "com.mysql.cj.jdbc.Driver" # MySQL数据库链接填写格式: # jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数 url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true" - # 如果你不需要做多端跨服,那么请使用 sqlite 作本地数据库 ↓ - # driver: "org.sqlite.JDBC" - # url: "jdbc:sqlite:./plugins/HamsterCore/database.db" # 用户名 username: "root" # 密码 diff --git a/core-bungee/build.gradle.kts b/core-bungee/build.gradle.kts index a1d582c..c6d5a2f 100644 --- a/core-bungee/build.gradle.kts +++ b/core-bungee/build.gradle.kts @@ -15,18 +15,12 @@ dependencies { exclude(group = "org.jetbrains") } // https://mvnrepository.com/artifact/redis.clients/jedis - api("redis.clients:jedis:5.1.2") { + api("redis.clients:jedis:5.1.4") { exclude(group = "com.google.code.gson") exclude(group = "org.slf4j") } - // https://mvnrepository.com/artifact/org.quartz-scheduler/quartz - api("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false } - // https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail - api("com.sun.mail:jakarta.mail:2.0.1") implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") } - // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8 - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.23") { exclude(group = "org.jetbrains") } } tasks { diff --git a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java index 9af906f..75b2a8a 100644 --- a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java +++ b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/HamsterCorePlugin.java @@ -1,10 +1,12 @@ package cn.hamster3.mc.plugin.core.bungee; import cn.hamster3.mc.plugin.core.bungee.api.CoreBungeeAPI; +import cn.hamster3.mc.plugin.core.bungee.util.BungeeSimpleLogger; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.config.YamlConfig; import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils; +import com.zaxxer.hikari.HikariDataSource; import lombok.Getter; import net.kyori.adventure.platform.bungeecord.BungeeAudiences; import net.md_5.bungee.api.ProxyServer; @@ -17,25 +19,25 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; -import java.util.logging.Logger; -@SuppressWarnings("CallToPrintStackTrace") public class HamsterCorePlugin extends Plugin { @Getter private static HamsterCorePlugin instance; @Getter + private static BungeeSimpleLogger simpleLogger; + @Getter private BungeeAudiences audienceProvider; @Override public void onLoad() { instance = this; + simpleLogger = new BungeeSimpleLogger(this); long start = System.currentTimeMillis(); - Logger logger = getLogger(); - logger.info("仓鼠核心正在初始化"); + simpleLogger.info("仓鼠核心正在初始化"); try { File dataFolder = getDataFolder(); if (dataFolder.mkdir()) { - logger.info("已生成插件存档文件夹"); + simpleLogger.info("已生成插件存档文件夹"); } File configFile = new File(dataFolder, "config.yml"); if (!configFile.exists()) { @@ -46,41 +48,42 @@ public class HamsterCorePlugin extends Plugin { } } CoreBungeeAPI.init(configFile); - logger.info("已初始化 CoreAPI"); + simpleLogger.info("已初始化 CoreAPI"); } catch (Exception e) { - logger.warning("初始化 CoreAPI 出错"); - e.printStackTrace(); + simpleLogger.error(e, "初始化 CoreAPI 出错"); } long time = System.currentTimeMillis() - start; - logger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms"); } @Override public void onEnable() { long start = System.currentTimeMillis(); - Logger logger = getLogger(); - logger.info("仓鼠核心正在启动"); + simpleLogger.info("仓鼠核心正在启动"); audienceProvider = BungeeAudiences.create(this); - logger.info("已创建 AudienceProvider"); + simpleLogger.info("已创建 AudienceProvider"); CoreAPI.getInstance().getExecutorService().submit(this::checkUpdate); long time = System.currentTimeMillis() - start; - logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); } @Override public void onDisable() { long start = System.currentTimeMillis(); - Logger logger = getLogger(); - CoreAPI.getInstance().getJedisPool().close(); - logger.info("已关闭 Redis 连接池"); - CoreAPI.getInstance().getHikariDataSource().close(); - logger.info("已关闭数据库连接池"); + if (CoreAPI.getInstance().isEnableRedis()) { + CoreAPI.getInstance().getJedisPool().close(); + simpleLogger.info("已关闭 Redis 连接池"); + } + if (CoreAPI.getInstance().isEnableDatabase()) { + ((HikariDataSource) CoreAPI.getInstance().getDataSource()).close(); + simpleLogger.info("已关闭数据库连接池"); + } CoreAPI.getInstance().getExecutorService().shutdownNow(); - logger.info("已关闭 ExecutorService 线程池"); + simpleLogger.info("已关闭 ExecutorService 线程池"); CoreAPI.getInstance().getScheduledService().shutdownNow(); - logger.info("已关闭 ScheduledExecutorService 线程池"); + simpleLogger.info("已关闭 ScheduledExecutorService 线程池"); long time = System.currentTimeMillis() - start; - logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); } private void checkUpdate() { diff --git a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/api/CoreBungeeAPI.java b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/api/CoreBungeeAPI.java index 147bad5..d811d9f 100644 --- a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/api/CoreBungeeAPI.java +++ b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/api/CoreBungeeAPI.java @@ -1,6 +1,7 @@ package cn.hamster3.mc.plugin.core.bungee.api; import cn.hamster3.mc.plugin.core.bungee.HamsterCorePlugin; +import cn.hamster3.mc.plugin.core.bungee.util.BungeeSimpleLogger; import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.config.YamlConfig; @@ -15,7 +16,6 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.util.logging.Logger; @SuppressWarnings("unused") public final class CoreBungeeAPI extends CoreAPI { @@ -51,8 +51,8 @@ public final class CoreBungeeAPI extends CoreAPI { } @Override - public @NotNull Logger getLogger() { - return HamsterCorePlugin.getInstance().getLogger(); + public @NotNull BungeeSimpleLogger getLogger() { + return HamsterCorePlugin.getSimpleLogger(); } @Override diff --git a/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/util/BungeeSimpleLogger.java b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/util/BungeeSimpleLogger.java new file mode 100644 index 0000000..8d18a42 --- /dev/null +++ b/core-bungee/src/main/java/cn/hamster3/mc/plugin/core/bungee/util/BungeeSimpleLogger.java @@ -0,0 +1,38 @@ +package cn.hamster3.mc.plugin.core.bungee.util; + +import cn.hamster3.mc.plugin.core.common.util.SimpleLogger; +import lombok.Getter; +import net.md_5.bungee.api.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.logging.Level; +import java.util.logging.Logger; + +@Getter +@SuppressWarnings("unused") +public class BungeeSimpleLogger extends SimpleLogger { + @NotNull + private final Plugin plugin; + @NotNull + private final Logger logger; + + public BungeeSimpleLogger(@NotNull Plugin plugin) { + this.plugin = plugin; + logger = plugin.getLogger(); + } + + @Override + public void log(@NotNull Level level, @NotNull String msg) { + logger.log(level, msg); + } + + @Override + public void log(@NotNull Level level, @NotNull Throwable throwable) { + logger.log(level, "", throwable); + } + + @Override + public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg) { + logger.log(level, msg, throwable); + } +} diff --git a/core-bungee/src/main/resources/config.yml b/core-bungee/src/main/resources/config.yml index da86f90..03c8c3f 100644 --- a/core-bungee/src/main/resources/config.yml +++ b/core-bungee/src/main/resources/config.yml @@ -1,3 +1,6 @@ +# 是否启用 redis 连接池功能 +enable-redis: false + # redis 连接配置 # 完整格式如下: # redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值 @@ -8,6 +11,10 @@ # 若不设置数据库,则默认使用 0 redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s" +# 是否启用数据库连接池功能 +enable-database: false + +# 数据库连接池配置 datasource: # 数据库链接驱动地址 driver: "com.mysql.cj.jdbc.Driver" @@ -22,8 +29,8 @@ datasource: # 推荐值:1~3 minimum-idle: 0 # 最大链接数 - # 推荐值:不低于5 - maximum-pool-size: 5 + # 推荐值:不低于3 + maximum-pool-size: 3 # 保持连接池可用的间隔 # 除非你的服务器数据库连接经常断开,否则不建议启用该选项 # 单位:毫秒 diff --git a/core-common/build.gradle.kts b/core-common/build.gradle.kts index 79b5365..c605abc 100644 --- a/core-common/build.gradle.kts +++ b/core-common/build.gradle.kts @@ -18,13 +18,10 @@ dependencies { } // https://mvnrepository.com/artifact/redis.clients/jedis - compileOnlyApi("redis.clients:jedis:5.1.2") { + compileOnlyApi("redis.clients:jedis:5.1.4") { exclude(group = "com.google.code.gson") exclude(group = "org.slf4j") } - compileOnlyApi("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false } - // https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail - compileOnlyApi("com.sun.mail:jakarta.mail:2.0.1") // https://mvnrepository.com/artifact/com.zaxxer/HikariCP compileOnly("com.zaxxer:HikariCP:4.0.3") { isTransitive = false } diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/api/CoreAPI.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/api/CoreAPI.java index 83dbeec..6676b08 100644 --- a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/api/CoreAPI.java +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/api/CoreAPI.java @@ -3,11 +3,13 @@ package cn.hamster3.mc.plugin.core.common.api; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; import cn.hamster3.mc.plugin.core.common.thread.NamedThreadFactory; import cn.hamster3.mc.plugin.core.common.util.CoreUtils; +import cn.hamster3.mc.plugin.core.common.util.SimpleLogger; import com.google.gson.Gson; import com.zaxxer.hikari.HikariDataSource; import lombok.Getter; import net.kyori.adventure.platform.AudienceProvider; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import redis.clients.jedis.JedisPool; import javax.sql.DataSource; @@ -16,50 +18,62 @@ import java.sql.SQLException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.logging.Logger; +@Getter @SuppressWarnings("unused") public abstract class CoreAPI { @Getter protected static CoreAPI instance; - /** - * Redis 连接池 - */ - @Getter - @NotNull - private final JedisPool jedisPool; - /** - * 公用数据库连接池 - */ - @Getter - @NotNull - private final HikariDataSource hikariDataSource; + private final boolean enableRedis; + private final boolean enableDatabase; /** * 异步线程池 */ - @Getter + @NotNull private final ExecutorService executorService; /** * 调度器线程池 */ - @Getter + @NotNull private final ScheduledExecutorService scheduledService; + /** + * 公用 Redis 连接池 + */ + @Nullable + private JedisPool jedisPool; + /** + * 公用数据库连接池 + */ + @Nullable + private HikariDataSource hikariDataSource; public CoreAPI(@NotNull ConfigSection config) { + SimpleLogger logger = getLogger(); executorService = Executors.newCachedThreadPool(new NamedThreadFactory("HamsterCore - Executor")); scheduledService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("HamsterCore - Scheduler")); + logger.info("已创建线程池"); - getLogger().info("正在创建 Redis 连接池"); - jedisPool = new JedisPool(config.getString("redis-url")); - getLogger().info("Redis 连接池创建完成"); - - ConfigSection datasourceConfig = config.getSection("datasource"); - if (datasourceConfig == null) { - throw new IllegalArgumentException("配置文件中未找到 datasource 节点"); + enableRedis = config.getBoolean("enable-redis", true); + if (enableRedis) { + logger.info("正在创建 Redis 连接池"); + jedisPool = new JedisPool(config.getString("redis-url")); + logger.info("Redis 连接池创建完成"); + } else { + logger.info("未启用 Redis 功能"); + } + + enableDatabase = config.getBoolean("enable-database", true); + if (enableDatabase) { + ConfigSection datasourceConfig = config.getSection("datasource"); + if (datasourceConfig == null) { + throw new IllegalArgumentException("配置文件中未找到 datasource 节点"); + } + logger.info("正在创建数据库连接池"); + hikariDataSource = (HikariDataSource) CoreUtils.getDataSource(datasourceConfig); + logger.info("数据库连接池创建完成"); + } else { + logger.info("未启用数据库功能"); } - getLogger().info("正在创建数据库连接池"); - hikariDataSource = (HikariDataSource) CoreUtils.getDataSource(datasourceConfig); - getLogger().info("数据库连接池创建完成"); } /** @@ -69,7 +83,10 @@ public abstract class CoreAPI { */ @NotNull public DataSource getDataSource() { - return hikariDataSource; + if (hikariDataSource != null) { + return hikariDataSource; + } + throw new IllegalStateException("仓鼠核心未启用数据库功能"); } /** @@ -84,7 +101,15 @@ public abstract class CoreAPI { } @NotNull - public abstract Logger getLogger(); + public JedisPool getJedisPool() { + if (jedisPool != null) { + return jedisPool; + } + throw new IllegalStateException("仓鼠核心未启用 Redis 功能"); + } + + @NotNull + public abstract SimpleLogger getLogger(); /** * @return GSON 工具 diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/ConfigSection.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/ConfigSection.java index 4b6bb40..5c94ac8 100644 --- a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/ConfigSection.java +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/ConfigSection.java @@ -4,10 +4,9 @@ import lombok.Getter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; @SuppressWarnings({"unused", "unchecked"}) @Getter @@ -27,6 +26,15 @@ public class ConfigSection { return map.containsKey(key); } + public Set getKeys() { + return map.keySet(); + } + + @Nullable + public Object get(@NotNull String key) { + return map.get(key); + } + @Nullable public ConfigSection getSection(@NotNull String key) { Object o = map.get(key); @@ -65,16 +73,6 @@ public class ConfigSection { return o.toString(); } - public List getStringList(@NotNull String key) { - Object o = map.get(key); - if (o instanceof List) { - return (List) o; - } - ArrayList list = new ArrayList<>(); - map.put(key, list); - return list; - } - public boolean getBoolean(@NotNull String key) { String string = getString(key); if (string == null) { @@ -155,6 +153,45 @@ public class ConfigSection { return Long.parseLong(string); } + public List getList(@NotNull String key, Function function) { + ArrayList list = new ArrayList<>(); + Object object = map.get(key); + if (object instanceof List) { + List mapList = (List) object; + for (Object o : mapList) { + T result = function.apply(o); + list.add(result); + } + } + return list; + } + + public List getStringList(@NotNull String key) { + return getList(key, Object::toString); + } + + public List getIntegerList(@NotNull String key) { + return getList(key, o -> Integer.parseInt(o.toString())); + } + + public List toList(BiFunction function) { + ArrayList list = new ArrayList<>(); + for (String key : getKeys()) { + T result = function.apply(this, key); + list.add(result); + } + return list; + } + + public Map toMap(BiFunction function) { + HashMap map = new HashMap<>(); + for (String key : getKeys()) { + T result = function.apply(this, key); + map.put(key, result); + } + return map; + } + public void set(@NotNull String key, @Nullable Object value) { if (value == null) { map.remove(key); diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java index a8724ab..c658ac8 100644 --- a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/config/YamlConfig.java @@ -5,9 +5,12 @@ import org.yaml.snakeyaml.Yaml; import java.io.*; import java.nio.charset.StandardCharsets; -import java.util.Map; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Consumer; -@SuppressWarnings({"unused", "VulnerableCodeUsages"}) +@SuppressWarnings("unused") public class YamlConfig extends ConfigSection { public static final Yaml YAML_LOADER = new Yaml(); @@ -19,11 +22,56 @@ public class YamlConfig extends ConfigSection { super(map); } + public static List loadFolder(@NotNull File file) throws IOException { + if (file.isDirectory()) { + ArrayList list = new ArrayList<>(); + for (File subFile : Objects.requireNonNull(file.listFiles())) { + list.addAll(loadFolder(subFile)); + } + return list; + } + if (file.isFile() && file.getName().endsWith(".yml")) { + return Collections.singletonList(load(file)); + } + return Collections.emptyList(); + } + + public static List loadFolder(@NotNull File file, @NotNull Consumer exceptionHandler) { + if (file.isDirectory()) { + ArrayList list = new ArrayList<>(); + for (File subFile : Objects.requireNonNull(file.listFiles())) { + list.addAll(loadFolder(subFile, exceptionHandler)); + } + return list; + } + if (file.isFile() && file.getName().endsWith(".yml")) { + try { + YamlConfig load = load(file); + return Collections.singletonList(load); + } catch (IOException e) { + exceptionHandler.accept(e); + } + } + return Collections.emptyList(); + } + + public static YamlConfig load(@NotNull Path path) { + try { + return load(Files.newInputStream(path)); + } catch (IOException e) { + return new YamlConfig(); + } + } + public static YamlConfig load(@NotNull File file) throws IOException { try (FileInputStream stream = new FileInputStream(file)) { - try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { - return load(reader); - } + return load(stream); + } + } + + public static YamlConfig load(@NotNull InputStream stream) throws IOException { + try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) { + return load(reader); } } @@ -32,11 +80,25 @@ public class YamlConfig extends ConfigSection { return new YamlConfig(load); } - public void save(@NotNull File file) throws IOException { - try (FileOutputStream stream = new FileOutputStream(file)) { - try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) { - YAML_LOADER.dump(map, writer); - } + public void save(@NotNull Path path) throws IOException { + try (OutputStream stream = Files.newOutputStream(path)) { + save(stream); } } + + public void save(@NotNull File file) throws IOException { + try (FileOutputStream stream = new FileOutputStream(file)) { + save(stream); + } + } + + public void save(@NotNull OutputStream stream) throws IOException { + try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) { + save(writer); + } + } + + public void save(@NotNull Writer writer) { + YAML_LOADER.dump(map, writer); + } } diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/CoreUtils.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/CoreUtils.java index 7897f39..67c26ad 100644 --- a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/CoreUtils.java +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/CoreUtils.java @@ -1,6 +1,7 @@ package cn.hamster3.mc.plugin.core.common.util; import cn.hamster3.mc.plugin.core.common.config.ConfigSection; +import cn.hamster3.mc.plugin.core.common.config.YamlConfig; import com.google.gson.JsonObject; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -8,42 +9,42 @@ import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.title.Title; +import net.kyori.adventure.translation.TranslationRegistry; import org.jetbrains.annotations.NotNull; import javax.sql.DataSource; import java.io.File; import java.io.IOException; -import java.nio.file.Files; +import java.text.MessageFormat; import java.time.Duration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; @SuppressWarnings("unused") public final class CoreUtils { private CoreUtils() { } - public static void zipCompressionFolder(@NotNull File folder, @NotNull File zipFile) throws IOException { - try (ZipOutputStream stream = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) { - putFileToZipStream(stream, "", folder); + @NotNull + public static DataSource getDataSource(@NotNull ConfigSection datasourceConfig) { + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setDriverClassName(datasourceConfig.getString("driver")); + hikariConfig.setJdbcUrl(datasourceConfig.getString("url")); + hikariConfig.setUsername(datasourceConfig.getString("username")); + hikariConfig.setPassword(datasourceConfig.getString("password")); + hikariConfig.setMaximumPoolSize(datasourceConfig.getInt("maximum-pool-size", 3)); + hikariConfig.setMinimumIdle(datasourceConfig.getInt("minimum-idle", 1)); + long keepAliveTime = datasourceConfig.getLong("keep-alive-time", 0); + if (keepAliveTime > 5000) { + hikariConfig.setKeepaliveTime(keepAliveTime); } - } - - public static void putFileToZipStream(@NotNull ZipOutputStream stream, @NotNull String path, @NotNull File file) throws IOException { - if (file.isDirectory()) { - File[] files = file.listFiles(); - if (files == null) { - throw new IOException(); - } - for (File subFile : files) { - putFileToZipStream(stream, path + file.getName() + "/", subFile); - } - return; - } - ZipEntry entry = new ZipEntry(path + file.getName()); - stream.putNextEntry(entry); - stream.write(Files.readAllBytes(file.toPath())); - stream.closeEntry(); + hikariConfig.setIdleTimeout(datasourceConfig.getLong("idle-timeout", 10 * 60 * 1000)); + hikariConfig.setMaxLifetime(datasourceConfig.getLong("max-lifetime", 30 * 60 * 1000)); + hikariConfig.setValidationTimeout(datasourceConfig.getLong("validation-timeout", 5000)); + hikariConfig.setPoolName(datasourceConfig.getString("name", "HamsterCore-Pool")); + return new HikariDataSource(hikariConfig); } /** @@ -125,24 +126,30 @@ public final class CoreUtils { ); } - @NotNull - public static DataSource getDataSource(@NotNull ConfigSection datasourceConfig) { - HikariConfig hikariConfig = new HikariConfig(); - hikariConfig.setDriverClassName(datasourceConfig.getString("driver")); - hikariConfig.setJdbcUrl(datasourceConfig.getString("url")); - hikariConfig.setUsername(datasourceConfig.getString("username")); - hikariConfig.setPassword(datasourceConfig.getString("password")); - hikariConfig.setMaximumPoolSize(datasourceConfig.getInt("maximum-pool-size", 3)); - hikariConfig.setMinimumIdle(datasourceConfig.getInt("minimum-idle", 1)); - long keepAliveTime = datasourceConfig.getLong("keep-alive-time", 0); - if (keepAliveTime > 5000) { - hikariConfig.setKeepaliveTime(keepAliveTime); + public static void loadTranslation(@NotNull TranslationRegistry registry, @NotNull File folder) throws IOException { + for (File subFile : Objects.requireNonNull(folder.listFiles())) { + String filename = subFile.getName().split("\\.")[0]; + String[] args = filename.split("_"); + Locale locale = new Locale.Builder().setLanguage(args[0]).setRegion(args[1]).build(); + YamlConfig config = YamlConfig.load(subFile); + Map map = loadTranslation(locale, config, ""); + registry.registerAll(locale, map); } - hikariConfig.setIdleTimeout(datasourceConfig.getLong("idle-timeout", 10 * 60 * 1000)); - hikariConfig.setMaxLifetime(datasourceConfig.getLong("max-lifetime", 30 * 60 * 1000)); - hikariConfig.setValidationTimeout(datasourceConfig.getLong("validation-timeout", 5000)); - hikariConfig.setPoolName(datasourceConfig.getString("name", "HamsterCore-Pool")); - return new HikariDataSource(hikariConfig); + } + + public static Map loadTranslation(@NotNull Locale locale, @NotNull ConfigSection config, @NotNull String prefix) { + HashMap result = new HashMap<>(); + for (Map.Entry entry : config.getMap().entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof String) { + String string = (String) value; + result.put(prefix + key, new MessageFormat(string, locale)); + } else if (value instanceof Map) { + loadTranslation(locale, config.getSectionOrCreate(key), "$prefix$key."); + } + } + return result; } /** diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/SimpleLogger.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/SimpleLogger.java new file mode 100644 index 0000000..dad249e --- /dev/null +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/SimpleLogger.java @@ -0,0 +1,94 @@ +package cn.hamster3.mc.plugin.core.common.util; + +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.logging.Level; + +@Getter +@SuppressWarnings("unused") +public abstract class SimpleLogger { + public abstract void log(@NotNull Level level, @NotNull String msg); + + public abstract void log(@NotNull Level level, @NotNull Throwable throwable); + + public abstract void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg); + + public void log(@NotNull Level level, @NotNull String msg, @NotNull Object... args) { + try { + log(level, String.format(msg, args)); + } catch (Exception e) { + log(Level.WARNING, "输出日志 " + msg + Arrays.toString(args) + " 时遇到一个异常", e); + } + } + + public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) { + try { + log(level, throwable, String.format(msg, args)); + } catch (Exception e) { + log(Level.WARNING, "输出日志 " + msg + Arrays.toString(args) + " 时遇到一个异常", e); + log(Level.WARNING, "异常参数: ", e); + } + } + + public void info(@NotNull String msg) { + log(Level.INFO, msg); + } + + public void info(@NotNull String msg, @NotNull Object... args) { + log(Level.INFO, msg, args); + } + + public void info(@NotNull Throwable throwable) { + log(Level.INFO, throwable); + } + + public void info(@NotNull Throwable throwable, @NotNull String msg) { + log(Level.INFO, throwable, msg); + } + + public void info(@NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) { + log(Level.INFO, throwable, msg, args); + } + + public void warn(@NotNull String msg) { + log(Level.WARNING, msg); + } + + public void warn(@NotNull String msg, @NotNull Object... args) { + log(Level.WARNING, msg, args); + } + + public void warn(@NotNull Throwable throwable) { + log(Level.WARNING, throwable); + } + + public void warn(@NotNull Throwable throwable, @NotNull String msg) { + log(Level.WARNING, throwable, msg); + } + + public void warn(@NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) { + log(Level.WARNING, throwable, msg, args); + } + + public void error(@NotNull String msg) { + log(Level.SEVERE, msg); + } + + public void error(@NotNull String msg, @NotNull Object... args) { + log(Level.SEVERE, msg, args); + } + + public void error(@NotNull Throwable throwable) { + log(Level.SEVERE, throwable); + } + + public void error(@NotNull Throwable throwable, @NotNull String msg) { + log(Level.SEVERE, throwable, msg); + } + + public void error(@NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) { + log(Level.SEVERE, throwable, msg, args); + } +} diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/CompletableTask.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/CompletableTask.java new file mode 100644 index 0000000..61f4c73 --- /dev/null +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/CompletableTask.java @@ -0,0 +1,146 @@ +package cn.hamster3.mc.plugin.core.common.util.async; + +import cn.hamster3.mc.plugin.core.common.api.CoreAPI; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +@SuppressWarnings({"unused", "CallToPrintStackTrace"}) +public class CompletableTask { + @NotNull + private final List> onSuccess; + @NotNull + private final List> onFailed; + @NotNull + private State state; + private T value; + private Throwable throwable; + + public CompletableTask() { + state = State.WAITING; + onSuccess = new ArrayList<>(); + onFailed = new ArrayList<>(); + } + + @NotNull + public static CompletableTask runAsync(@NotNull RunTask runTask) { + CompletableTask task = new CompletableTask<>(); + CoreAPI.getInstance().getExecutorService().submit(() -> { + try { + runTask.run(); + task.success(null); + } catch (Exception e) { + task.failed(e); + } + }); + return task; + } + + @NotNull + public static CompletableTask supplyAsync(@NotNull SupplyTask supplyTask) { + CompletableTask task = new CompletableTask<>(); + CoreAPI.getInstance().getExecutorService().submit(() -> { + try { + T call = supplyTask.call(); + task.success(call); + } catch (Exception e) { + task.failed(e); + } + }); + return task; + } + + public void success(@Nullable T value) { + if (state != State.WAITING) { + throw new IllegalStateException(); + } + this.value = value; + state = State.SUCCESS; + synchronized (this) { + notifyAll(); + } + for (Consumer success : onSuccess) { + try { + success.accept(value); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void failed(@Nullable Throwable throwable) { + if (state != State.WAITING) { + throw new IllegalStateException(); + } + this.value = null; + state = State.FAILED; + this.throwable = throwable; + synchronized (this) { + notifyAll(); + } + for (Consumer consumer : onFailed) { + try { + consumer.accept(throwable); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + @NotNull + public CompletableTask onSuccess(@NotNull Consumer consumer) { + if (state == State.SUCCESS) { + try { + consumer.accept(value); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + onSuccess.add(consumer); + } + return this; + } + + @NotNull + public CompletableTask onFailed(@NotNull Consumer consumer) { + if (state == State.FAILED) { + try { + consumer.accept(throwable); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + onFailed.add(consumer); + } + return this; + } + + public T get() throws InterruptedException { + if (state == State.WAITING) { + synchronized (this) { + wait(); + } + } + if (state == State.SUCCESS) { + return value; + } + return null; + } + + public T join() { + try { + return get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public enum State { + WAITING, + SUCCESS, + FAILED + } +} diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/RunTask.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/RunTask.java new file mode 100644 index 0000000..59fd43c --- /dev/null +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/RunTask.java @@ -0,0 +1,5 @@ +package cn.hamster3.mc.plugin.core.common.util.async; + +public interface RunTask { + void run() throws Exception; +} diff --git a/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/SupplyTask.java b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/SupplyTask.java new file mode 100644 index 0000000..e8cba53 --- /dev/null +++ b/core-common/src/main/java/cn/hamster3/mc/plugin/core/common/util/async/SupplyTask.java @@ -0,0 +1,5 @@ +package cn.hamster3.mc.plugin.core.common.util.async; + +public interface SupplyTask { + T call() throws Exception; +} diff --git a/core-velocity/build.gradle.kts b/core-velocity/build.gradle.kts index c25c43e..b63587b 100644 --- a/core-velocity/build.gradle.kts +++ b/core-velocity/build.gradle.kts @@ -8,23 +8,18 @@ dependencies { annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT") compileOnlyApi("net.kyori:adventure-platform-api:4.3.2") { isTransitive = false } + // https://mvnrepository.com/artifact/redis.clients/jedis - api("redis.clients:jedis:5.1.2") { + api("redis.clients:jedis:5.1.4") { exclude(group = "com.google.code.gson") exclude(group = "org.slf4j") } - // https://mvnrepository.com/artifact/org.quartz-scheduler/quartz - api("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false } - // https://mvnrepository.com/artifact/com.sun.mail/jakarta.mail - api("com.sun.mail:jakarta.mail:2.0.1") // https://mvnrepository.com/artifact/com.zaxxer/HikariCP implementation("com.zaxxer:HikariCP:5.1.0") { isTransitive = false } // https://mvnrepository.com/artifact/com.mysql/mysql-connector-j runtimeOnly("com.mysql:mysql-connector-j:8.3.0") - // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib - runtimeOnly("org.jetbrains.kotlin:kotlin-stdlib:1.9.23") { exclude(group = "org.jetbrains") } } sourceSets.create("templates") { diff --git a/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/HamsterCorePlugin.java b/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/HamsterCorePlugin.java index 98a3342..de2b8df 100644 --- a/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/HamsterCorePlugin.java +++ b/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/HamsterCorePlugin.java @@ -4,6 +4,7 @@ import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.config.YamlConfig; import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils; import cn.hamster3.mc.plugin.core.velocity.api.CoreVelocityAPI; +import cn.hamster3.mc.plugin.core.velocity.util.VelocitySimpleLogger; import com.google.inject.Inject; import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; @@ -36,25 +37,22 @@ public class HamsterCorePlugin { @Getter private static HamsterCorePlugin instance; @Getter - private final java.util.logging.Logger logger; - @Getter - private final Logger slf4jLogger; + private final VelocitySimpleLogger simpleLogger; @Getter private final ProxyServer proxyServer; @Getter private final File dataFolder; @Inject - public HamsterCorePlugin(Logger slf4jLogger, ProxyServer proxyServer, @DataDirectory Path dataPath) { - logger = java.util.logging.Logger.getLogger("hamster-core"); - this.slf4jLogger = slf4jLogger; + public HamsterCorePlugin(Logger logger, ProxyServer proxyServer, @DataDirectory Path dataPath) { + this.simpleLogger = new VelocitySimpleLogger(logger); this.proxyServer = proxyServer; dataFolder = dataPath.toFile(); instance = this; long start = System.currentTimeMillis(); try { if (dataFolder.mkdir()) { - slf4jLogger.info("已生成插件存档文件夹"); + simpleLogger.info("已生成插件存档文件夹"); } File configFile = new File(dataFolder, "config.yml"); if (!configFile.exists()) { @@ -65,38 +63,40 @@ public class HamsterCorePlugin { } } CoreVelocityAPI.init(configFile); - slf4jLogger.info("已初始化 CoreAPI"); + simpleLogger.info("已初始化 CoreAPI"); } catch (Exception e) { - slf4jLogger.error("初始化 CoreAPI 出错", e); + simpleLogger.error(e, "初始化 CoreAPI 出错"); } long time = System.currentTimeMillis() - start; - slf4jLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms"); } @Subscribe(order = PostOrder.FIRST) public void onProxyInitialization(ProxyInitializeEvent event) { long start = System.currentTimeMillis(); - slf4jLogger.info("仓鼠核心正在启动"); + simpleLogger.info("仓鼠核心正在启动"); CoreAPI.getInstance().getExecutorService().submit(this::checkUpdate); long time = System.currentTimeMillis() - start; - slf4jLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms"); } @Subscribe(order = PostOrder.LAST) public void onProxyShutdown(ProxyShutdownEvent event) { long start = System.currentTimeMillis(); - CoreAPI.getInstance().getJedisPool().close(); - slf4jLogger.info("已关闭 Redis 连接池"); - if (CoreAPI.getInstance().getDataSource() instanceof HikariDataSource dataSource) { - dataSource.close(); - slf4jLogger.info("已关闭数据库连接池"); + if (CoreAPI.getInstance().isEnableRedis()) { + CoreAPI.getInstance().getJedisPool().close(); + simpleLogger.info("已关闭 Redis 连接池"); + } + if (CoreAPI.getInstance().isEnableDatabase()) { + ((HikariDataSource) CoreAPI.getInstance().getDataSource()).close(); + simpleLogger.info("已关闭数据库连接池"); } CoreAPI.getInstance().getExecutorService().shutdownNow(); - slf4jLogger.info("已关闭 ExecutorService 线程池"); + simpleLogger.info("已关闭 ExecutorService 线程池"); CoreAPI.getInstance().getScheduledService().shutdownNow(); - slf4jLogger.info("已关闭 ScheduledExecutorService 线程池"); + simpleLogger.info("已关闭 ScheduledExecutorService 线程池"); long time = System.currentTimeMillis() - start; - slf4jLogger.info("仓鼠核心关闭完成,总计耗时 " + time + " ms"); + simpleLogger.info("仓鼠核心已关闭,总计耗时 " + time + " ms"); } private void checkUpdate() { diff --git a/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/api/CoreVelocityAPI.java b/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/api/CoreVelocityAPI.java index d28eab8..02274a9 100644 --- a/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/api/CoreVelocityAPI.java +++ b/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/api/CoreVelocityAPI.java @@ -8,6 +8,7 @@ import cn.hamster3.mc.plugin.core.common.impl.ComponentTypeAdapter; import cn.hamster3.mc.plugin.core.common.impl.MessageTypeAdapter; import cn.hamster3.mc.plugin.core.velocity.HamsterCorePlugin; import cn.hamster3.mc.plugin.core.velocity.impl.AudienceProviderImpl; +import cn.hamster3.mc.plugin.core.velocity.util.VelocitySimpleLogger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import net.kyori.adventure.platform.AudienceProvider; @@ -16,7 +17,6 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; -import java.util.logging.Logger; @SuppressWarnings("unused") public final class CoreVelocityAPI extends CoreAPI { @@ -57,8 +57,8 @@ public final class CoreVelocityAPI extends CoreAPI { } @Override - public @NotNull Logger getLogger() { - return HamsterCorePlugin.getInstance().getLogger(); + public @NotNull VelocitySimpleLogger getLogger() { + return HamsterCorePlugin.getInstance().getSimpleLogger(); } @Override diff --git a/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/util/VelocitySimpleLogger.java b/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/util/VelocitySimpleLogger.java new file mode 100644 index 0000000..8f0810e --- /dev/null +++ b/core-velocity/src/main/java/cn/hamster3/mc/plugin/core/velocity/util/VelocitySimpleLogger.java @@ -0,0 +1,57 @@ +package cn.hamster3.mc.plugin.core.velocity.util; + +import cn.hamster3.mc.plugin.core.common.util.SimpleLogger; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; + +import java.util.logging.Level; + +@Getter +public class VelocitySimpleLogger extends SimpleLogger { + @NotNull + private final Logger logger; + + public VelocitySimpleLogger(@NotNull Logger logger) { + this.logger = logger; + } + + @Override + public void log(@NotNull Level level, @NotNull String msg) { + if (level == Level.INFO) { + logger.info(msg); + } else if (level == Level.WARNING) { + logger.warn(msg); + } else if (level == Level.SEVERE) { + logger.error(msg); + } else { + logger.trace(msg); + } + } + + @Override + public void log(@NotNull Level level, @NotNull Throwable throwable) { + if (level == Level.INFO) { + logger.info("", throwable); + } else if (level == Level.WARNING) { + logger.warn("", throwable); + } else if (level == Level.SEVERE) { + logger.error("", throwable); + } else { + logger.trace("", throwable); + } + } + + @Override + public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg) { + if (level == Level.INFO) { + logger.info(msg, throwable); + } else if (level == Level.WARNING) { + logger.warn(msg, throwable); + } else if (level == Level.SEVERE) { + logger.error(msg, throwable); + } else { + logger.trace(msg, throwable); + } + } +} diff --git a/core-velocity/src/main/resources/config.yml b/core-velocity/src/main/resources/config.yml index da86f90..03c8c3f 100644 --- a/core-velocity/src/main/resources/config.yml +++ b/core-velocity/src/main/resources/config.yml @@ -1,3 +1,6 @@ +# 是否启用 redis 连接池功能 +enable-redis: false + # redis 连接配置 # 完整格式如下: # redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值 @@ -8,6 +11,10 @@ # 若不设置数据库,则默认使用 0 redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s" +# 是否启用数据库连接池功能 +enable-database: false + +# 数据库连接池配置 datasource: # 数据库链接驱动地址 driver: "com.mysql.cj.jdbc.Driver" @@ -22,8 +29,8 @@ datasource: # 推荐值:1~3 minimum-idle: 0 # 最大链接数 - # 推荐值:不低于5 - maximum-pool-size: 5 + # 推荐值:不低于3 + maximum-pool-size: 3 # 保持连接池可用的间隔 # 除非你的服务器数据库连接经常断开,否则不建议启用该选项 # 单位:毫秒 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e411586..c893b36 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists