perf: 精简代码

This commit is contained in:
2024-03-12 19:40:43 +08:00
parent 7a8bb22f74
commit ffc2ecc2ee
17 changed files with 401 additions and 223 deletions

View File

@@ -5,7 +5,7 @@ plugins {
} }
group = "cn.hamster3.mc.plugin" group = "cn.hamster3.mc.plugin"
version = "1.2.3" version = "1.2.4"
subprojects { subprojects {
apply { apply {

View File

@@ -4,7 +4,7 @@ dependencies {
implementation(project(":core-common")) { implementation(project(":core-common")) {
isTransitive = false isTransitive = false
} }
compileOnly("org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT") compileOnly("org.spigotmc:spigot-api:1.20.4-R0.1-SNAPSHOT")
implementation("de.tr7zw:item-nbt-api:2.12.3-SNAPSHOT") implementation("de.tr7zw:item-nbt-api:2.12.3-SNAPSHOT")
compileOnly("net.milkbowl.vault:VaultAPI:1.7") { compileOnly("net.milkbowl.vault:VaultAPI:1.7") {

View File

@@ -23,6 +23,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.logging.Logger; import java.util.logging.Logger;
@SuppressWarnings("CallToPrintStackTrace") @SuppressWarnings("CallToPrintStackTrace")
@@ -56,17 +57,19 @@ public class HamsterCorePlugin extends JavaPlugin {
@Override @Override
public void onLoad() { public void onLoad() {
instance = this;
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Logger logger = getLogger(); Logger logger = getLogger();
logger.info("仓鼠核心正在初始化"); logger.info("仓鼠核心正在初始化");
logger.info("Minecraft 版本: " + MinecraftVersion.getMCVersion()); logger.info("Minecraft 版本: " + MinecraftVersion.getMCVersion());
logger.info("nms 版本: " + MinecraftVersion.getNMSVersion()); logger.info("NMS 版本: " + MinecraftVersion.getNMSVersion());
instance = this;
saveDefaultConfig();
reloadConfig();
logger.info("已读取配置文件");
try { try {
CoreBukkitAPI.init(); File dataFolder = getDataFolder();
if (dataFolder.mkdir()) {
logger.info("已生成插件存档文件夹");
}
File file = new File(dataFolder, "config.yml");
CoreBukkitAPI.init(file);
logger.info("已初始化 CoreAPI"); logger.info("已初始化 CoreAPI");
} catch (Exception e) { } catch (Exception e) {
logger.warning("初始化 CoreAPI 出错"); logger.warning("初始化 CoreAPI 出错");
@@ -108,7 +111,7 @@ public class HamsterCorePlugin extends JavaPlugin {
Logger logger = getLogger(); Logger logger = getLogger();
CoreAPI.getInstance().getRedisClient().close(); CoreAPI.getInstance().getRedisClient().close();
logger.info("已关闭 Redis 连接池"); logger.info("已关闭 Redis 连接池");
CoreBukkitAPI.getInstance().getDataSource().close(); CoreAPI.getInstance().getHikariDataSource().close();
logger.info("已关闭数据库连接池"); logger.info("已关闭数据库连接池");
CoreAPI.getInstance().getExecutorService().shutdownNow(); CoreAPI.getInstance().getExecutorService().shutdownNow();
logger.info("已关闭 ExecutorService 线程池"); logger.info("已关闭 ExecutorService 线程池");

View File

@@ -5,35 +5,32 @@ 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.impl.PotionEffectAdapter;
import cn.hamster3.mc.plugin.core.bukkit.util.MinecraftVersion; 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.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.data.DisplayMessage; import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
import cn.hamster3.mc.plugin.core.common.impl.ComponentTypeAdapter; import cn.hamster3.mc.plugin.core.common.impl.ComponentTypeAdapter;
import cn.hamster3.mc.plugin.core.common.impl.MessageTypeAdapter; import cn.hamster3.mc.plugin.core.common.impl.MessageTypeAdapter;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper;
import io.lettuce.core.RedisClient;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class CoreBukkitAPI extends CoreAPI { public final class CoreBukkitAPI extends CoreAPI {
@NotNull @NotNull
private final Gson gson; private final Gson gson;
@NotNull @NotNull
private final Gson humanGson; private final Gson humanGson;
@NotNull
private final RedisClient redisClient;
@NotNull
private final HikariDataSource datasource;
private CoreBukkitAPI() { private CoreBukkitAPI(@NotNull ConfigSection config) {
super(config);
gson = new GsonBuilder() gson = new GsonBuilder()
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE) .registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE) .registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
@@ -45,67 +42,28 @@ public final class CoreBukkitAPI extends CoreAPI {
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE) .registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE) .registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
.registerTypeAdapter(ItemStack.class, ItemStackAdapter.INSTANCE) .registerTypeAdapter(ItemStack.class, ItemStackAdapter.INSTANCE)
.registerTypeAdapter(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), ItemStackAdapter.INSTANCE) .registerTypeAdapter(MinecraftVersion.getCraftBukkitClassSilent("inventory.CraftItemStack"), ItemStackAdapter.INSTANCE)
.registerTypeAdapter(PotionEffect.class, PotionEffectAdapter.INSTANCE) .registerTypeAdapter(PotionEffect.class, PotionEffectAdapter.INSTANCE)
.serializeNulls() .serializeNulls()
.setPrettyPrinting() .setPrettyPrinting()
.create(); .create();
HamsterCorePlugin plugin = HamsterCorePlugin.getInstance();
FileConfiguration config = plugin.getConfig();
HamsterCorePlugin.getInstance().getLogger().info("正在创建 redis 客户端");
redisClient = RedisClient.create(config.getString("redis-url"));
HamsterCorePlugin.getInstance().getLogger().info("redis 客户端创建完成");
ConfigurationSection datasourceConfig = config.getConfigurationSection("datasource");
if (datasourceConfig == null) {
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
}
HamsterCorePlugin.getInstance().getLogger().info("正在创建数据库连接池");
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);
}
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("HamsterCore-Pool");
datasource = new HikariDataSource(hikariConfig);
HamsterCorePlugin.getInstance().getLogger().info("数据库连接池创建完成");
} }
public static CoreBukkitAPI getInstance() { public static CoreBukkitAPI getInstance() {
return (CoreBukkitAPI) instance; return (CoreBukkitAPI) instance;
} }
public static void init() { public static void init(@NotNull File configFile) throws IOException {
if (instance != null) { if (instance != null) {
return; return;
} }
instance = new CoreBukkitAPI(); YamlConfig config = YamlConfig.load(configFile);
instance = new CoreBukkitAPI(config);
} }
@Override @Override
public @NotNull BukkitAudiences getAudienceProvider() { public @NotNull Logger getLogger() {
return HamsterCorePlugin.getInstance().getAudienceProvider(); return HamsterCorePlugin.getInstance().getLogger();
}
@Override
public @NotNull HikariDataSource getDataSource() {
return datasource;
}
@Override
public @NotNull RedisClient getRedisClient() {
return redisClient;
} }
@Override @Override
@@ -117,4 +75,9 @@ public final class CoreBukkitAPI extends CoreAPI {
public @NotNull Gson getHumanGson() { public @NotNull Gson getHumanGson() {
return humanGson; return humanGson;
} }
@Override
public @NotNull BukkitAudiences getAudienceProvider() {
return HamsterCorePlugin.getInstance().getAudienceProvider();
}
} }

View File

@@ -74,7 +74,7 @@ public enum CoreMessage {
public static void init(@NotNull Plugin plugin) { public static void init(@NotNull Plugin plugin) {
File dataFolder = plugin.getDataFolder(); File dataFolder = plugin.getDataFolder();
if (dataFolder.mkdirs()) { if (dataFolder.mkdirs()) {
plugin.getLogger().info("已生成插件存档文件夹 " + dataFolder.getName()); plugin.getLogger().info("已生成插件存档文件夹");
} }
File file = new File(dataFolder, "messages.yml"); File file = new File(dataFolder, "messages.yml");
YamlConfiguration config = new YamlConfiguration(); YamlConfiguration config = new YamlConfiguration();

View File

@@ -307,7 +307,7 @@ public final class CoreBukkitUtils {
File file = new File(plugin.getDataFolder(), filename); File file = new File(plugin.getDataFolder(), filename);
File parentFile = file.getParentFile(); File parentFile = file.getParentFile();
if (parentFile.mkdirs()) { if (parentFile.mkdirs()) {
plugin.getLogger().info("已生成插件存档文件夹 " + parentFile.getName()); plugin.getLogger().info("已生成插件存档文件夹");
} }
if (!file.exists()) { if (!file.exists()) {
plugin.getLogger().info("生成配置文件: " + filename); plugin.getLogger().info("生成配置文件: " + filename);
@@ -367,6 +367,7 @@ public final class CoreBukkitUtils {
} }
@NotNull @NotNull
@SuppressWarnings("deprecation")
public static JsonObject serializePotionEffect(@NotNull PotionEffect effect) { public static JsonObject serializePotionEffect(@NotNull PotionEffect effect) {
JsonObject object = new JsonObject(); JsonObject object = new JsonObject();
object.addProperty("type", effect.getType().getName()); object.addProperty("type", effect.getType().getName());
@@ -376,6 +377,7 @@ public final class CoreBukkitUtils {
} }
@NotNull @NotNull
@SuppressWarnings("deprecation")
public static PotionEffect deserializePotionEffect(@NotNull JsonObject object) { public static PotionEffect deserializePotionEffect(@NotNull JsonObject object) {
//noinspection ConstantConditions //noinspection ConstantConditions
return new PotionEffect( return new PotionEffect(

View File

@@ -22,7 +22,7 @@ public class MinecraftVersion {
} }
/** /**
* 与当前服务端运行的 mc 版本号对比 * 与当前服务端运行的 Minecraft 版本号对比
* <p> * <p>
* 1: 当前版本高于输入版本号 * 1: 当前版本高于输入版本号
* <p> * <p>

View File

@@ -6,6 +6,9 @@ import lombok.Getter;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences; import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.logging.Logger; import java.util.logging.Logger;
@SuppressWarnings("CallToPrintStackTrace") @SuppressWarnings("CallToPrintStackTrace")
@@ -17,12 +20,24 @@ public class HamsterCorePlugin extends Plugin {
@Override @Override
public void onLoad() { public void onLoad() {
long start = System.currentTimeMillis();
instance = this; instance = this;
long start = System.currentTimeMillis();
Logger logger = getLogger(); Logger logger = getLogger();
logger.info("仓鼠核心正在初始化"); logger.info("仓鼠核心正在初始化");
try { try {
CoreBungeeAPI.init(); File dataFolder = getDataFolder();
if (dataFolder.mkdir()) {
logger.info("已生成插件存档文件夹");
}
File configFile = new File(dataFolder, "config.yml");
if (!configFile.exists()) {
Files.copy(
getResourceAsStream("config.yml"),
configFile.toPath(),
StandardCopyOption.REPLACE_EXISTING
);
}
CoreBungeeAPI.init(configFile);
logger.info("已初始化 CoreAPI"); logger.info("已初始化 CoreAPI");
} catch (Exception e) { } catch (Exception e) {
logger.warning("初始化 CoreAPI 出错"); logger.warning("初始化 CoreAPI 出错");
@@ -49,7 +64,7 @@ public class HamsterCorePlugin extends Plugin {
Logger logger = getLogger(); Logger logger = getLogger();
CoreAPI.getInstance().getRedisClient().close(); CoreAPI.getInstance().getRedisClient().close();
logger.info("已关闭 Redis 连接池"); logger.info("已关闭 Redis 连接池");
CoreBungeeAPI.getInstance().getDataSource().close(); CoreAPI.getInstance().getHikariDataSource().close();
logger.info("已关闭数据库连接池"); logger.info("已关闭数据库连接池");
CoreAPI.getInstance().getExecutorService().shutdownNow(); CoreAPI.getInstance().getExecutorService().shutdownNow();
logger.info("已关闭 ExecutorService 线程池"); logger.info("已关闭 ExecutorService 线程池");

View File

@@ -1,33 +1,31 @@
package cn.hamster3.mc.plugin.core.bungee.api; package cn.hamster3.mc.plugin.core.bungee.api;
import cn.hamster3.mc.plugin.core.bungee.HamsterCorePlugin; import cn.hamster3.mc.plugin.core.bungee.HamsterCorePlugin;
import cn.hamster3.mc.plugin.core.bungee.util.CoreBungeeCordUtils;
import cn.hamster3.mc.plugin.core.common.api.CoreAPI; 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.data.DisplayMessage; import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
import cn.hamster3.mc.plugin.core.common.impl.ComponentTypeAdapter; import cn.hamster3.mc.plugin.core.common.impl.ComponentTypeAdapter;
import cn.hamster3.mc.plugin.core.common.impl.MessageTypeAdapter; import cn.hamster3.mc.plugin.core.common.impl.MessageTypeAdapter;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.lettuce.core.RedisClient;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences; import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.md_5.bungee.config.Configuration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class CoreBungeeAPI extends CoreAPI { public final class CoreBungeeAPI extends CoreAPI {
@NotNull @NotNull
private final Gson gson; private final Gson gson;
@NotNull @NotNull
private final Gson humanGson; private final Gson humanGson;
@NotNull
private final RedisClient redisClient;
@NotNull
private final HikariDataSource datasource;
private CoreBungeeAPI() { private CoreBungeeAPI(@NotNull ConfigSection config) {
super(config);
gson = new GsonBuilder() gson = new GsonBuilder()
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE) .registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE) .registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
@@ -38,62 +36,23 @@ public final class CoreBungeeAPI extends CoreAPI {
.serializeNulls() .serializeNulls()
.setPrettyPrinting() .setPrettyPrinting()
.create(); .create();
HamsterCorePlugin plugin = HamsterCorePlugin.getInstance();
Configuration config = CoreBungeeCordUtils.getPluginConfig(plugin);
HamsterCorePlugin.getInstance().getLogger().info("正在创建 redis 客户端");
redisClient = RedisClient.create(config.getString("redis-url"));
HamsterCorePlugin.getInstance().getLogger().info("redis 客户端创建完成");
Configuration datasourceConfig = config.getSection("datasource");
if (datasourceConfig == null) {
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
}
HamsterCorePlugin.getInstance().getLogger().info("正在创建数据库连接池");
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);
}
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("HamsterCore-Pool");
datasource = new HikariDataSource(hikariConfig);
HamsterCorePlugin.getInstance().getLogger().info("数据库连接池创建完成");
} }
public static CoreBungeeAPI getInstance() { public static CoreBungeeAPI getInstance() {
return (CoreBungeeAPI) instance; return (CoreBungeeAPI) instance;
} }
public static void init() { public static void init(@NotNull File configFile) throws IOException {
if (instance != null) { if (instance != null) {
return; return;
} }
instance = new CoreBungeeAPI(); YamlConfig config = YamlConfig.load(configFile);
instance = new CoreBungeeAPI(config);
} }
@Override @Override
public @NotNull BungeeAudiences getAudienceProvider() { public @NotNull Logger getLogger() {
return HamsterCorePlugin.getInstance().getAudienceProvider(); return HamsterCorePlugin.getInstance().getLogger();
}
@Override
public @NotNull HikariDataSource getDataSource() {
return datasource;
}
@Override
public @NotNull RedisClient getRedisClient() {
return redisClient;
} }
@Override @Override
@@ -105,4 +64,9 @@ public final class CoreBungeeAPI extends CoreAPI {
public @NotNull Gson getHumanGson() { public @NotNull Gson getHumanGson() {
return humanGson; return humanGson;
} }
@Override
public @NotNull BungeeAudiences getAudienceProvider() {
return HamsterCorePlugin.getInstance().getAudienceProvider();
}
} }

View File

@@ -8,8 +8,8 @@ import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class CoreBungeeCordUtils { public final class CoreBungeeCordUtils {
@@ -32,7 +32,7 @@ public final class CoreBungeeCordUtils {
public static Configuration getPluginConfig(@NotNull Plugin plugin) { public static Configuration getPluginConfig(@NotNull Plugin plugin) {
File configFile = new File(plugin.getDataFolder(), "config.yml"); File configFile = new File(plugin.getDataFolder(), "config.yml");
if (!configFile.exists()) { if (!configFile.exists()) {
return saveDefaultConfig(plugin); return saveConfig(plugin);
} }
try { try {
return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
@@ -45,7 +45,7 @@ public final class CoreBungeeCordUtils {
public static Configuration getPluginConfig(@NotNull Plugin plugin, @NotNull String filename) { public static Configuration getPluginConfig(@NotNull Plugin plugin, @NotNull String filename) {
File configFile = new File(plugin.getDataFolder(), filename); File configFile = new File(plugin.getDataFolder(), filename);
if (!configFile.exists()) { if (!configFile.exists()) {
return saveDefaultConfig(plugin, filename); return saveConfig(plugin, filename);
} }
try { try {
return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
@@ -55,29 +55,22 @@ public final class CoreBungeeCordUtils {
} }
@NotNull @NotNull
public static Configuration saveDefaultConfig(@NotNull Plugin plugin) { public static Configuration saveConfig(@NotNull Plugin plugin) {
if (plugin.getDataFolder().mkdir()) { return saveConfig(plugin, "config.yml");
plugin.getLogger().info("已生成插件存档文件夹");
}
File configFile = new File(plugin.getDataFolder(), "config.yml");
try {
InputStream in = plugin.getResourceAsStream("config.yml");
Files.copy(in, configFile.toPath());
return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
@NotNull @NotNull
public static Configuration saveDefaultConfig(@NotNull Plugin plugin, @NotNull String filename) { public static Configuration saveConfig(@NotNull Plugin plugin, @NotNull String filename) {
if (plugin.getDataFolder().mkdir()) { if (plugin.getDataFolder().mkdir()) {
plugin.getLogger().info("已生成插件存档文件夹"); plugin.getLogger().info("已生成插件存档文件夹");
} }
File configFile = new File(plugin.getDataFolder(), filename); File configFile = new File(plugin.getDataFolder(), filename);
try { try {
InputStream in = plugin.getResourceAsStream(filename); Files.copy(
Files.copy(in, configFile.toPath()); plugin.getResourceAsStream(filename),
configFile.toPath(),
StandardCopyOption.REPLACE_EXISTING
);
return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); return ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View File

@@ -2,6 +2,8 @@
dependencies { dependencies {
compileOnly("com.google.code.gson:gson:2.8.0") compileOnly("com.google.code.gson:gson:2.8.0")
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
compileOnly("org.yaml:snakeyaml:1.19")
implementation("net.kyori:adventure-platform-api:4.3.2") { implementation("net.kyori:adventure-platform-api:4.3.2") {
exclude(group = "org.jetbrains") exclude(group = "org.jetbrains")
@@ -11,6 +13,9 @@ dependencies {
exclude(group = "com.google.code.gson") exclude(group = "com.google.code.gson")
} }
// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
compileOnly("com.zaxxer:HikariCP:5.1.0") { isTransitive = false }
// https://mvnrepository.com/artifact/io.lettuce/lettuce-core // https://mvnrepository.com/artifact/io.lettuce/lettuce-core
implementation("io.lettuce:lettuce-core:6.3.1.RELEASE") { implementation("io.lettuce:lettuce-core:6.3.1.RELEASE") {
exclude(group = "io.netty") exclude(group = "io.netty")

View File

@@ -1,7 +1,10 @@
package cn.hamster3.mc.plugin.core.common.api; 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.thread.NamedThreadFactory;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.lettuce.core.RedisClient; import io.lettuce.core.RedisClient;
import lombok.Getter; import lombok.Getter;
import net.kyori.adventure.platform.AudienceProvider; import net.kyori.adventure.platform.AudienceProvider;
@@ -13,11 +16,24 @@ import java.sql.SQLException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public abstract class CoreAPI { public abstract class CoreAPI {
@Getter @Getter
protected static CoreAPI instance; protected static CoreAPI instance;
/**
* lettuce redis 客户端
*/
@Getter
@NotNull
private final RedisClient redisClient;
/**
* HamsterCore 公用数据库连接池
*/
@Getter
@NotNull
private final HikariDataSource hikariDataSource;
/** /**
* 异步线程池 * 异步线程池
*/ */
@@ -29,13 +45,37 @@ public abstract class CoreAPI {
@Getter @Getter
private final ScheduledExecutorService scheduledService; private final ScheduledExecutorService scheduledService;
public CoreAPI() { public CoreAPI(@NotNull ConfigSection config) {
executorService = Executors.newCachedThreadPool(new NamedThreadFactory("HamsterCore - Executor")); executorService = Executors.newCachedThreadPool(new NamedThreadFactory("HamsterCore - Executor"));
scheduledService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("HamsterCore - Scheduler")); scheduledService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("HamsterCore - Scheduler"));
}
@NotNull getLogger().info("正在创建 redis 客户端");
public abstract AudienceProvider getAudienceProvider(); redisClient = RedisClient.create(config.getString("redis-url"));
getLogger().info("redis 客户端创建完成");
ConfigSection datasourceConfig = config.getSection("datasource");
if (datasourceConfig == null) {
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
}
getLogger().info("正在创建数据库连接池");
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);
}
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("HamsterCore-Pool");
hikariDataSource = new HikariDataSource(hikariConfig);
getLogger().info("数据库连接池创建完成");
}
/** /**
* 获取 HamsterCore 公用数据库连接池 * 获取 HamsterCore 公用数据库连接池
@@ -43,7 +83,9 @@ public abstract class CoreAPI {
* @return 公用数据库连接池 * @return 公用数据库连接池
*/ */
@NotNull @NotNull
public abstract DataSource getDataSource(); public DataSource getDataSource() {
return hikariDataSource;
}
/** /**
* 获取 HamsterCore 公用数据库连接 * 获取 HamsterCore 公用数据库连接
@@ -56,11 +98,8 @@ public abstract class CoreAPI {
return getDataSource().getConnection(); return getDataSource().getConnection();
} }
/**
* @return lettuce redis 客户端
*/
@NotNull @NotNull
public abstract RedisClient getRedisClient(); public abstract Logger getLogger();
/** /**
* @return GSON 工具 * @return GSON 工具
@@ -73,4 +112,7 @@ public abstract class CoreAPI {
*/ */
@NotNull @NotNull
public abstract Gson getHumanGson(); public abstract Gson getHumanGson();
@NotNull
public abstract AudienceProvider getAudienceProvider();
} }

View File

@@ -0,0 +1,170 @@
package cn.hamster3.mc.plugin.core.common.config;
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;
@SuppressWarnings({"unused", "unchecked"})
@Getter
public class ConfigSection {
@NotNull
protected final Map<String, Object> map;
public ConfigSection() {
this(new HashMap<>());
}
public ConfigSection(@NotNull Map<String, Object> map) {
this.map = map;
}
public boolean hasKey(@NotNull String key) {
return map.containsKey(key);
}
@Nullable
public ConfigSection getSection(@NotNull String key) {
Object o = map.get(key);
if (o instanceof Map) {
return new ConfigSection((Map<String, Object>) o);
}
return null;
}
@NotNull
public ConfigSection getSectionOrCreate(@NotNull String key) {
Object o = map.get(key);
if (o instanceof Map) {
return new ConfigSection((Map<String, Object>) o);
}
ConfigSection section = new ConfigSection();
map.put(key, section.map);
return section;
}
@Nullable
public String getString(@NotNull String key) {
Object o = map.get(key);
if (o == null) {
return null;
}
return o.toString();
}
@NotNull
public String getString(@NotNull String key, @NotNull String defaultValue) {
Object o = map.get(key);
if (o == null) {
return defaultValue;
}
return o.toString();
}
public List<String> getStringList(@NotNull String key) {
Object o = map.get(key);
if (o instanceof List) {
return (List<String>) o;
}
ArrayList<String> list = new ArrayList<>();
map.put(key, list);
return list;
}
public boolean getBoolean(@NotNull String key) {
String string = getString(key);
if (string == null) {
return false;
}
return Boolean.parseBoolean(string);
}
public boolean getBoolean(@NotNull String key, boolean defaultValue) {
String string = getString(key);
if (string == null) {
return defaultValue;
}
return Boolean.parseBoolean(string);
}
public int getInt(@NotNull String key) {
String string = getString(key);
if (string == null) {
return 0;
}
return Integer.parseInt(string);
}
public int getInt(@NotNull String key, int defaultValue) {
String string = getString(key);
if (string == null) {
return defaultValue;
}
return Integer.parseInt(string);
}
public float getFloat(@NotNull String key) {
String string = getString(key);
if (string == null) {
return 0;
}
return Float.parseFloat(string);
}
public float getFloat(@NotNull String key, float defaultValue) {
String string = getString(key);
if (string == null) {
return defaultValue;
}
return Float.parseFloat(string);
}
public double getDouble(@NotNull String key) {
String string = getString(key);
if (string == null) {
return 0;
}
return Double.parseDouble(string);
}
public double getDouble(@NotNull String key, double defaultValue) {
String string = getString(key);
if (string == null) {
return defaultValue;
}
return Double.parseDouble(string);
}
public long getLong(@NotNull String key) {
String string = getString(key);
if (string == null) {
return 0L;
}
return Long.parseLong(string);
}
public long getLong(@NotNull String key, long defaultValue) {
String string = getString(key);
if (string == null) {
return defaultValue;
}
return Long.parseLong(string);
}
public void set(@NotNull String key, @Nullable Object value) {
if (value == null) {
map.remove(key);
return;
}
if (value instanceof ConfigSection) {
ConfigSection section = (ConfigSection) value;
map.put(key, section.map);
return;
}
map.put(key, value);
}
}

View File

@@ -0,0 +1,38 @@
package cn.hamster3.mc.plugin.core.common.config;
import org.jetbrains.annotations.NotNull;
import org.yaml.snakeyaml.Yaml;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@SuppressWarnings("unused")
public class YamlConfig extends ConfigSection {
public static final Yaml YAML_LOADER = new Yaml();
public YamlConfig() {
super();
}
public YamlConfig(@NotNull Map<String, Object> map) {
super(map);
}
public static YamlConfig load(@NotNull File file) throws IOException {
try (FileInputStream stream = new FileInputStream(file)) {
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
Map<String, Object> load = YAML_LOADER.load(reader);
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);
}
}
}
}

View File

@@ -1,11 +1,13 @@
package cn.hamster3.mc.plugin.core.common.thread; package cn.hamster3.mc.plugin.core.common.thread;
import cn.hamster3.mc.plugin.core.common.api.CoreAPI; import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
import lombok.Data;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@SuppressWarnings("unused") @Data
@SuppressWarnings({"unused", "CallToPrintStackTrace"})
public abstract class CountdownThread implements Runnable { public abstract class CountdownThread implements Runnable {
private final long interval; private final long interval;
private final long totalTicks; private final long totalTicks;
@@ -59,27 +61,4 @@ public abstract class CountdownThread implements Runnable {
future.cancel(false); future.cancel(false);
} }
public long getInterval() {
return interval;
}
public long getTotalTicks() {
return totalTicks;
}
public int getNowTicks() {
return nowTicks;
}
public void setNowTicks(int nowTicks) {
this.nowTicks = nowTicks;
}
public ScheduledFuture<?> getFuture() {
return future;
}
public void setFuture(ScheduledFuture<?> future) {
this.future = future;
}
} }

View File

@@ -1,5 +1,7 @@
package cn.hamster3.mc.plugin.core.common.util; package cn.hamster3.mc.plugin.core.common.util;
import org.jetbrains.annotations.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.Collections; import java.util.Collections;
@@ -14,17 +16,17 @@ import java.util.Stack;
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class Calculator { public final class Calculator {
/**
* 这个单例线程不安全,如果要在异步线程使用,请自行新建一个实例
*/
public static final Calculator INSTANCE = new Calculator(); public static final Calculator INSTANCE = new Calculator();
// 默认除法运算精度 // 默认除法运算精度
private static final int DEF_DIV_SCALE = 16; private static final int DEF_DIV_SCALE = 16;
private final Stack<String> postfixStack = new Stack<>();// 后缀式栈 private final Stack<String> postfixStack = new Stack<>();// 后缀式栈
private final Stack<Character> opStack = new Stack<>();// 运算符栈 private final Stack<Character> operateStack = new Stack<>();// 运算符栈
private final int[] operaPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符ASCII码-40做索引的运算符优先级 private final int[] operaPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符ASCII码-40做索引的运算符优先级
private Calculator() {
}
/** /**
* 按照给定的表达式计算 * 按照给定的表达式计算
* *
@@ -62,7 +64,7 @@ public final class Calculator {
* @param expression 表达式 * @param expression 表达式
*/ */
private void prepare(String expression) { private void prepare(String expression) {
opStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低 operateStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低
char[] arr = expression.toCharArray(); char[] arr = expression.toCharArray();
int currentIndex = 0;// 当前字符的位置 int currentIndex = 0;// 当前字符的位置
int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值 int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
@@ -73,18 +75,18 @@ public final class Calculator {
if (count > 0) { if (count > 0) {
postfixStack.push(new String(arr, currentIndex, count));// 取两个运算符之间的数字 postfixStack.push(new String(arr, currentIndex, count));// 取两个运算符之间的数字
} }
peekOp = opStack.peek(); peekOp = operateStack.peek();
if (currentOp == ')') {// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号 if (currentOp == ')') {// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
while (opStack.peek() != '(') { while (operateStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop())); postfixStack.push(String.valueOf(operateStack.pop()));
} }
opStack.pop(); operateStack.pop();
} else { } else {
while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) { while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
postfixStack.push(String.valueOf(opStack.pop())); postfixStack.push(String.valueOf(operateStack.pop()));
peekOp = opStack.peek(); peekOp = operateStack.peek();
} }
opStack.push(currentOp); operateStack.push(currentOp);
} }
count = 0; count = 0;
currentIndex = i + 1; currentIndex = i + 1;
@@ -96,8 +98,8 @@ public final class Calculator {
postfixStack.push(new String(arr, currentIndex, count)); postfixStack.push(new String(arr, currentIndex, count));
} }
while (opStack.peek() != ',') { while (operateStack.peek() != ',') {
postfixStack.push(String.valueOf(opStack.pop()));// 将操作符栈中的剩余的元素添加到后缀式栈中 postfixStack.push(String.valueOf(operateStack.pop()));// 将操作符栈中的剩余的元素添加到后缀式栈中
} }
} }
@@ -114,36 +116,36 @@ public final class Calculator {
/** /**
* 利用ASCII码-40做下标去算术符号优先级 * 利用ASCII码-40做下标去算术符号优先级
* *
* @param cur 字符1 * @param char1 字符1
* @param peek 字符2 * @param char2 字符2
* @return 如果是peek优先级高于cur返回true默认都是peek优先级要低 * @return 如果是peek优先级高于cur返回true默认都是peek优先级要低
*/ */
private boolean compare(char cur, char peek) { private boolean compare(char char1, char char2) {
return operaPriority[(peek) - 40] >= operaPriority[(cur) - 40]; return operaPriority[(char2) - 40] >= operaPriority[(char1) - 40];
} }
/** /**
* 按照给定的算术运算符做计算 * 按照给定的算术运算符做计算
* *
* @param firstValue 第一个值 * @param value1 第一个值
* @param secondValue 第二个值 * @param value2 第二个值
* @param currentOp 算数运算符 * @param operate 算数运算符
* @return 运算结果 * @return 运算结果
*/ */
private String calculate(String firstValue, String secondValue, char currentOp) { private String calculate(@NotNull String value1, @NotNull String value2, char operate) {
String result = ""; String result = "";
switch (currentOp) { switch (operate) {
case '+': case '+':
result = String.valueOf(add(firstValue, secondValue)); result = String.valueOf(add(value1, value2));
break; break;
case '-': case '-':
result = String.valueOf(sub(firstValue, secondValue)); result = String.valueOf(sub(value1, value2));
break; break;
case '*': case '*':
result = String.valueOf(mul(firstValue, secondValue)); result = String.valueOf(mul(value1, value2));
break; break;
case '/': case '/':
result = String.valueOf(div(firstValue, secondValue)); result = String.valueOf(div(value1, value2));
break; break;
} }
return result; return result;
@@ -152,52 +154,52 @@ public final class Calculator {
/** /**
* 提供精确的加法运算。 * 提供精确的加法运算。
* *
* @param v1 被加数 * @param value1 被加数
* @param v2 加数 * @param value2 加数
* @return 两个参数的和 * @return 两个参数的和
*/ */
private double add(String v1, String v2) { private double add(@NotNull String value1, @NotNull String value2) {
BigDecimal b1 = new BigDecimal(v1); BigDecimal b1 = new BigDecimal(value1);
BigDecimal b2 = new BigDecimal(v2); BigDecimal b2 = new BigDecimal(value2);
return b1.add(b2).doubleValue(); return b1.add(b2).doubleValue();
} }
/** /**
* 提供精确的减法运算。 * 提供精确的减法运算。
* *
* @param v1 被减数 * @param value1 被减数
* @param v2 减数 * @param value2 减数
* @return 两个参数的差 * @return 两个参数的差
*/ */
private double sub(String v1, String v2) { private double sub(@NotNull String value1, @NotNull String value2) {
BigDecimal b1 = new BigDecimal(v1); BigDecimal b1 = new BigDecimal(value1);
BigDecimal b2 = new BigDecimal(v2); BigDecimal b2 = new BigDecimal(value2);
return b1.subtract(b2).doubleValue(); return b1.subtract(b2).doubleValue();
} }
/** /**
* 提供精确的乘法运算。 * 提供精确的乘法运算。
* *
* @param v1 被乘数 * @param value1 被乘数
* @param v2 乘数 * @param value2 乘数
* @return 两个参数的积 * @return 两个参数的积
*/ */
private double mul(String v1, String v2) { private double mul(@NotNull String value1, @NotNull String value2) {
BigDecimal b1 = new BigDecimal(v1); BigDecimal b1 = new BigDecimal(value1);
BigDecimal b2 = new BigDecimal(v2); BigDecimal b2 = new BigDecimal(value2);
return b1.multiply(b2).doubleValue(); return b1.multiply(b2).doubleValue();
} }
/** /**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位以后的数字四舍五入。 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位以后的数字四舍五入。
* *
* @param v1 被除数 * @param value1 被除数
* @param v2 除数 * @param value2 除数
* @return 两个参数的商 * @return 两个参数的商
*/ */
private double div(String v1, String v2) { private double div(@NotNull String value1, @NotNull String value2) {
BigDecimal b1 = new BigDecimal(v1); BigDecimal b1 = new BigDecimal(value1);
BigDecimal b2 = new BigDecimal(v2); BigDecimal b2 = new BigDecimal(value2);
return b1.divide(b2, DEF_DIV_SCALE, RoundingMode.HALF_UP).doubleValue(); return b1.divide(b2, DEF_DIV_SCALE, RoundingMode.HALF_UP).doubleValue();
} }
} }

View File

@@ -148,6 +148,8 @@ public final class CoreUtils {
/** /**
* 按照给定的表达式计算 * 按照给定的表达式计算
* <p>
* 如果要在异步线程使用,请自行新建一个 Calculator 实例
* *
* @param expression 要计算的表达式例如:5+12*(3+5)/7 * @param expression 要计算的表达式例如:5+12*(3+5)/7
* @return 计算结果 * @return 计算结果