Compare commits
27 Commits
1.3.1
...
865812c524
Author | SHA1 | Date | |
---|---|---|---|
865812c524 | |||
f3e4becf35 | |||
02836c9086 | |||
e2a8cc236e | |||
86bd28e134 | |||
03b0d62b19 | |||
98300804fe | |||
7285f1b3e2 | |||
6f4e40942c | |||
7462b99ce4 | |||
9bcf8a28dd | |||
e6cb7efe77 | |||
fb75b4d95f | |||
aab082500a | |||
d5077537ba | |||
bcfbaab30c | |||
57f06c3ce2 | |||
8d94816b36 | |||
2a6950231e | |||
548143bee7 | |||
15833af7e8 | |||
4a07209bc2 | |||
e6e66b99b3 | |||
ce79c56d1a | |||
5d6a11d9b0 | |||
fd4f25b3d3 | |||
b1bd35b452 |
@@ -26,9 +26,9 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// 对于 Bukkit 插件
|
// 对于 Bukkit 插件
|
||||||
compileOnly("cn.hamster3.mc.plugin:core-bukkit:1.2.2")
|
compileOnly("cn.hamster3.mc.plugin:core-bukkit:1.3.3")
|
||||||
// 对于 BungeeCord 插件
|
// 对于 BungeeCord 插件
|
||||||
compileOnly("cn.hamster3.mc.plugin:core-bungee:1.2.2")
|
compileOnly("cn.hamster3.mc.plugin:core-bungee:1.3.3")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -54,13 +54,13 @@ dependencies {
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hamster3.mc.plugin</groupId>
|
<groupId>cn.hamster3.mc.plugin</groupId>
|
||||||
<artifactId>core-bukkit</artifactId>
|
<artifactId>core-bukkit</artifactId>
|
||||||
<version>1.2.2</version>
|
<version>1.3.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--对于 BungeeCord 插件-->
|
<!--对于 BungeeCord 插件-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hamster3.mc.plugin</groupId>
|
<groupId>cn.hamster3.mc.plugin</groupId>
|
||||||
<artifactId>core-bungee</artifactId>
|
<artifactId>core-bungee</artifactId>
|
||||||
<version>1.2.2</version>
|
<version>1.3.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -1,21 +1,23 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java-library")
|
||||||
id("maven-publish")
|
id("maven-publish")
|
||||||
id("com.github.johnrengelman.shadow") version "8+"
|
id("com.github.johnrengelman.shadow") version "8+"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "cn.hamster3.mc.plugin"
|
group = "cn.hamster3.mc.plugin"
|
||||||
version = "1.3.1"
|
version = "1.3.3"
|
||||||
|
description = "叁只仓鼠的 Minecraft 插件开发通用工具包"
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply {
|
apply {
|
||||||
plugin("java")
|
plugin("java-library")
|
||||||
plugin("maven-publish")
|
plugin("maven-publish")
|
||||||
plugin("com.github.johnrengelman.shadow")
|
plugin("com.github.johnrengelman.shadow")
|
||||||
}
|
}
|
||||||
|
|
||||||
group = rootProject.group
|
group = rootProject.group
|
||||||
version = rootProject.version
|
version = rootProject.version
|
||||||
|
description = rootProject.description
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://maven.airgame.net/maven-public")
|
maven("https://maven.airgame.net/maven-public")
|
||||||
@@ -44,34 +46,10 @@ subprojects {
|
|||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
}
|
}
|
||||||
processResources {
|
processResources {
|
||||||
val map = mutableMapOf<String, String>()
|
filesMatching("update.yml") {
|
||||||
map["BUILD_ID"] = System.getenv().getOrDefault("BUILD_ID", "DEV")
|
expand(rootProject.properties)
|
||||||
map["BUILD_NUMBER"] = System.getenv().getOrDefault("BUILD_NUMBER", "DEV")
|
|
||||||
map["BUILD_DISPLAY_NAME"] = System.getenv().getOrDefault("BUILD_DISPLAY_NAME", "DEV")
|
|
||||||
map["JOB_URL"] = System.getenv().getOrDefault("JOB_URL", "DEV")
|
|
||||||
map["BUILD_URL"] = System.getenv().getOrDefault("BUILD_URL", "DEV")
|
|
||||||
map["GIT_COMMIT"] = System.getenv().getOrDefault("GIT_COMMIT", "DEV")
|
|
||||||
filesMatching("jenkins.yml") {
|
|
||||||
expand(map)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jar {
|
|
||||||
archiveClassifier = "dev"
|
|
||||||
}
|
|
||||||
shadowJar {
|
|
||||||
archiveClassifier = ""
|
|
||||||
relocate("org.quartz", "cn.hamster3.mc.plugin.core.lib.org.quartz")
|
|
||||||
relocate("org.terracotta.quartz", "cn.hamster3.mc.plugin.core.lib.org.terracotta.quartz")
|
|
||||||
|
|
||||||
relocate("com.zaxxer.hikari", "cn.hamster3.mc.plugin.core.lib.com.zaxxer.hikari")
|
|
||||||
relocate("redis.clients.jedis", "cn.hamster3.mc.plugin.core.lib.redis.clients.jedis")
|
|
||||||
relocate("org.json", "cn.hamster3.mc.plugin.core.lib.org.json")
|
|
||||||
relocate("org.apache.commons.pool2", "cn.hamster3.mc.plugin.core.lib.org.apache.commons.pool2")
|
|
||||||
|
|
||||||
relocate("net.kyori", "cn.hamster3.mc.plugin.core.lib.net.kyori")
|
|
||||||
relocate("de.tr7zw.changeme.nbtapi", "cn.hamster3.mc.plugin.core.lib.de.tr7zw.nbtapi")
|
|
||||||
relocate("de.tr7zw.annotations", "cn.hamster3.mc.plugin.core.lib.de.tr7zw.nbtapi.annotations")
|
|
||||||
}
|
|
||||||
build {
|
build {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
}
|
}
|
||||||
|
@@ -3,36 +3,43 @@
|
|||||||
evaluationDependsOn(":core-common")
|
evaluationDependsOn(":core-common")
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":core-common")) { isTransitive = false }
|
api(project(":core-common")) { isTransitive = false }
|
||||||
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
implementation("de.tr7zw:item-nbt-api:2.12.3-SNAPSHOT")
|
|
||||||
compileOnly("net.milkbowl.vault:VaultAPI:1.7") { isTransitive = false }
|
compileOnly("net.milkbowl.vault:VaultAPI:1.7") { isTransitive = false }
|
||||||
compileOnly("org.black_ixx:playerpoints:3.2.6") { isTransitive = false }
|
compileOnly("org.black_ixx:playerpoints:3.2.6") { isTransitive = false }
|
||||||
compileOnly("me.clip:placeholderapi:2.11.5") { isTransitive = false }
|
compileOnly("me.clip:placeholderapi:2.11.5") { isTransitive = false }
|
||||||
|
|
||||||
implementation("net.kyori:adventure-platform-bukkit:4.3.2") {
|
api("net.kyori:adventure-platform-bukkit:4.3.2") {
|
||||||
exclude(group = "org.jetbrains")
|
exclude(group = "org.jetbrains")
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
}
|
}
|
||||||
implementation("net.kyori:adventure-text-minimessage:4.15.0") {
|
api("net.kyori:adventure-text-minimessage:4.15.0") {
|
||||||
exclude(module = "adventure-api")
|
exclude(module = "adventure-api")
|
||||||
exclude(group = "org.jetbrains")
|
exclude(group = "org.jetbrains")
|
||||||
}
|
}
|
||||||
implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") }
|
|
||||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||||
implementation("redis.clients:jedis:5.1.2") {
|
api("redis.clients:jedis:5.1.2") {
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
exclude(group = "org.slf4j")
|
exclude(group = "org.slf4j")
|
||||||
}
|
}
|
||||||
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
||||||
implementation("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
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")
|
||||||
|
// 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 {
|
tasks {
|
||||||
processResources {
|
processResources {
|
||||||
filesMatching("plugin.yml") {
|
filesMatching("plugin.yml") {
|
||||||
expand(project.properties)
|
expand(rootProject.properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
withType<Jar> {
|
withType<Jar> {
|
||||||
@@ -40,5 +47,7 @@ tasks {
|
|||||||
}
|
}
|
||||||
shadowJar {
|
shadowJar {
|
||||||
destinationDirectory = rootProject.layout.buildDirectory
|
destinationDirectory = rootProject.layout.buildDirectory
|
||||||
|
relocate("de.tr7zw.changeme.nbtapi", "cn.hamster3.mc.plugin.core.lib.de.tr7zw.nbtapi")
|
||||||
|
relocate("de.tr7zw.annotations", "cn.hamster3.mc.plugin.core.lib.de.tr7zw.nbtapi.annotations")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,28 +9,32 @@ import cn.hamster3.mc.plugin.core.bukkit.hook.PointAPI;
|
|||||||
import cn.hamster3.mc.plugin.core.bukkit.hook.VaultAPI;
|
import cn.hamster3.mc.plugin.core.bukkit.hook.VaultAPI;
|
||||||
import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener;
|
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.listener.DebugListener;
|
||||||
import cn.hamster3.mc.plugin.core.bukkit.listener.JenkinsUpdateListener;
|
|
||||||
import cn.hamster3.mc.plugin.core.bukkit.page.handler.PageHandler;
|
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.page.listener.PageListener;
|
||||||
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.util.UpdateCheckUtils;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.InventoryView;
|
import org.bukkit.inventory.InventoryView;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
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.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@SuppressWarnings("CallToPrintStackTrace")
|
|
||||||
public class HamsterCorePlugin extends JavaPlugin {
|
public class HamsterCorePlugin extends JavaPlugin {
|
||||||
@Getter
|
@Getter
|
||||||
private static HamsterCorePlugin instance;
|
private static HamsterCorePlugin instance;
|
||||||
@@ -74,11 +78,11 @@ public class HamsterCorePlugin extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
File configFile = new File(dataFolder, "config.yml");
|
File configFile = new File(dataFolder, "config.yml");
|
||||||
if (!configFile.exists()) {
|
if (!configFile.exists()) {
|
||||||
Files.copy(
|
try (InputStream stream = getResource("config.yml")) {
|
||||||
Objects.requireNonNull(getResource("config.yml")),
|
if (stream != null) {
|
||||||
configFile.toPath(),
|
Files.copy(stream, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
StandardCopyOption.REPLACE_EXISTING
|
}
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
CoreBukkitAPI.init(configFile);
|
CoreBukkitAPI.init(configFile);
|
||||||
logger.info("已初始化 CoreAPI");
|
logger.info("已初始化 CoreAPI");
|
||||||
@@ -108,13 +112,11 @@ public class HamsterCorePlugin extends JavaPlugin {
|
|||||||
logger.info("已注册 CallbackListener");
|
logger.info("已注册 CallbackListener");
|
||||||
Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this);
|
Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this);
|
||||||
logger.info("已注册 DebugListener");
|
logger.info("已注册 DebugListener");
|
||||||
Bukkit.getPluginManager().registerEvents(JenkinsUpdateListener.INSTANCE, this);
|
|
||||||
logger.info("已注册 JenkinsUpdateListener");
|
|
||||||
long time = System.currentTimeMillis() - start;
|
long time = System.currentTimeMillis() - start;
|
||||||
sync(() -> {
|
sync(() -> {
|
||||||
PointAPI.reloadPlayerPointAPIHook();
|
PointAPI.reloadPlayerPointAPIHook();
|
||||||
VaultAPI.reloadVaultHook();
|
VaultAPI.reloadVaultHook();
|
||||||
JenkinsUpdateListener.showUpdate(Bukkit.getConsoleSender());
|
async(this::checkUpdate);
|
||||||
});
|
});
|
||||||
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||||
}
|
}
|
||||||
@@ -143,4 +145,23 @@ public class HamsterCorePlugin extends JavaPlugin {
|
|||||||
long time = System.currentTimeMillis() - start;
|
long time = System.currentTimeMillis() - start;
|
||||||
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkUpdate() {
|
||||||
|
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||||
|
try (InputStream stream = plugin.getResource("plugin.yml")) {
|
||||||
|
if (stream == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
|
YamlConfig config = YamlConfig.load(reader);
|
||||||
|
ConfigSection section = config.getSection("UPDATE_CHECKER");
|
||||||
|
if (section == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
UpdateCheckUtils.checkUpdate(plugin.getName(), section);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,73 +0,0 @@
|
|||||||
package cn.hamster3.mc.plugin.core.bukkit.listener;
|
|
||||||
|
|
||||||
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
|
|
||||||
import cn.hamster3.mc.plugin.core.common.config.YamlConfig;
|
|
||||||
import cn.hamster3.mc.plugin.core.common.util.JenkinsUtils;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class JenkinsUpdateListener implements Listener {
|
|
||||||
public static final JenkinsUpdateListener INSTANCE = new JenkinsUpdateListener();
|
|
||||||
public static HashSet<UUID> SHOWED = new HashSet<>();
|
|
||||||
|
|
||||||
private JenkinsUpdateListener() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showUpdate(@NotNull CommandSender sender) {
|
|
||||||
HamsterCorePlugin.async(() -> {
|
|
||||||
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
|
||||||
InputStream resource = plugin.getResource("jenkins.yml");
|
|
||||||
if (resource == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(resource, StandardCharsets.UTF_8)) {
|
|
||||||
YamlConfig jenkinsConfig = YamlConfig.load(reader);
|
|
||||||
String jobUrl = jenkinsConfig.getString("JOB_URL");
|
|
||||||
if (jobUrl == null || jobUrl.equalsIgnoreCase("DEV")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String buildNumberString = jenkinsConfig.getString("BUILD_NUMBER");
|
|
||||||
if (buildNumberString == null || buildNumberString.equalsIgnoreCase("DEV")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int lastStableBuild = JenkinsUtils.getLastStableBuild(jobUrl, null, null);
|
|
||||||
int buildNumber = Integer.parseInt(buildNumberString);
|
|
||||||
int version = lastStableBuild - buildNumber;
|
|
||||||
if (version <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String pluginName = plugin.getName();
|
|
||||||
sender.sendMessage(String.format(
|
|
||||||
"§a检测到插件 %s 有 %d 个版本更新, 下载链接: §n§l%s", pluginName, version, jobUrl
|
|
||||||
));
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(ignoreCancelled = true)
|
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
|
||||||
Player player = event.getPlayer();
|
|
||||||
if (!player.hasPermission("hamster.core.admin")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!SHOWED.add(player.getUniqueId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
showUpdate(player);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -48,15 +48,14 @@ public class PageManager {
|
|||||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(pageConfigFile);
|
YamlConfiguration config = YamlConfiguration.loadConfiguration(pageConfigFile);
|
||||||
return new PageConfig(plugin, config);
|
return new PageConfig(plugin, config);
|
||||||
}
|
}
|
||||||
try (InputStream resource = plugin.getResource("pages/" + filename)) {
|
try (InputStream stream = plugin.getResource("pages/" + filename)) {
|
||||||
if (resource == null) {
|
if (stream != null) {
|
||||||
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 的 Jar 文件内部未找到 /pages/" + filename + " ");
|
Files.copy(stream, pageConfigFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
}
|
}
|
||||||
Files.copy(resource, pageConfigFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(pageConfigFile);
|
|
||||||
return new PageConfig(plugin, config);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException("为插件 " + pluginName + " 加载页面配置文件 " + filename + " 时出错", e);
|
throw new IllegalArgumentException("为插件 " + pluginName + " 加载页面配置文件 " + filename + " 时出错", e);
|
||||||
}
|
}
|
||||||
|
YamlConfiguration config = YamlConfiguration.loadConfiguration(pageConfigFile);
|
||||||
|
return new PageConfig(plugin, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -312,10 +312,9 @@ public final class CoreBukkitUtils {
|
|||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
plugin.getLogger().info("生成配置文件: " + filename);
|
plugin.getLogger().info("生成配置文件: " + filename);
|
||||||
try (InputStream stream = plugin.getResource(filename)) {
|
try (InputStream stream = plugin.getResource(filename)) {
|
||||||
if (stream == null) {
|
if (stream != null) {
|
||||||
throw new NullPointerException("在插件 " + plugin.getName() + " 的文件内部未找到 " + filename + " ");
|
Files.copy(stream, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
}
|
}
|
||||||
Files.copy(stream, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 内部读取文件 " + filename + " 时发生错误");
|
throw new IllegalArgumentException("在插件 " + plugin.getName() + " 内部读取文件 " + filename + " 时发生错误");
|
||||||
}
|
}
|
||||||
|
@@ -61,11 +61,13 @@ public class MinecraftVersion {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Class<?> getNMSClass(@NotNull String className) throws ClassNotFoundException {
|
public static Class<?> getNMSClass(@NotNull String className) throws ClassNotFoundException {
|
||||||
|
if (Version2 >= 17) {
|
||||||
|
return Class.forName("net.minecraft.server." + className);
|
||||||
|
}
|
||||||
String nmsVersion = getNMSVersion();
|
String nmsVersion = getNMSVersion();
|
||||||
return Class.forName("net.minecraft.server." + nmsVersion + "." + className);
|
return Class.forName("net.minecraft.server." + nmsVersion + "." + className);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Class<?> getNMSClassSilent(@NotNull String className) {
|
public static Class<?> getNMSClassSilent(@NotNull String className) {
|
||||||
String nmsVersion = getNMSVersion();
|
String nmsVersion = getNMSVersion();
|
||||||
|
@@ -9,15 +9,12 @@
|
|||||||
redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
# 数据库链接驱动地址
|
# 数据库链接驱动地址,旧版服务端(低于1.13)请使用:com.mysql.jdbc.Driver
|
||||||
# 除非你知道自己在做什么,否则不建议更改该项
|
|
||||||
# 旧版服务端(低于1.13)请使用:com.mysql.jdbc.Driver
|
|
||||||
driver: "com.mysql.cj.jdbc.Driver"
|
driver: "com.mysql.cj.jdbc.Driver"
|
||||||
# 数据库链接填写格式:
|
# MySQL数据库链接填写格式:
|
||||||
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
|
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
|
||||||
# 除非你知道自己在做什么,否则不建议随意更改参数
|
|
||||||
url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
|
url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
|
||||||
# 如果你不需要做多端跨服,那么请使用 sqlite 作本地数据库
|
# 如果你不需要做多端跨服,那么请使用 sqlite 作本地数据库 ↓
|
||||||
# driver: "org.sqlite.JDBC"
|
# driver: "org.sqlite.JDBC"
|
||||||
# url: "jdbc:sqlite:./plugins/HamsterCore/database.db"
|
# url: "jdbc:sqlite:./plugins/HamsterCore/database.db"
|
||||||
# 用户名
|
# 用户名
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
BUILD_ID: ${BUILD_ID}
|
|
||||||
BUILD_NUMBER: ${BUILD_NUMBER}
|
|
||||||
BUILD_DISPLAY_NAME: ${BUILD_DISPLAY_NAME}
|
|
||||||
JOB_URL: ${JOB_URL}
|
|
||||||
BUILD_URL: ${BUILD_URL}
|
|
||||||
GIT_COMMIT: ${GIT_COMMIT}
|
|
@@ -4,8 +4,15 @@ version: ${version}
|
|||||||
api-version: 1.13
|
api-version: 1.13
|
||||||
|
|
||||||
author: MiniDay
|
author: MiniDay
|
||||||
|
description: ${description}
|
||||||
website: https://git.airgame.net/MiniDay/hamster-core
|
website: https://git.airgame.net/MiniDay/hamster-core
|
||||||
description: 仓鼠核心:叁只仓鼠的 Minecraft 插件开发通用工具包
|
|
||||||
|
UPDATE_CHECKER:
|
||||||
|
VERSION: ${version}
|
||||||
|
CHECK_TYPE: GITEA_RELEASES
|
||||||
|
GIT_BASE_URL: https://git.airgame.net
|
||||||
|
GIT_REPO: MiniDay/hamster-core
|
||||||
|
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-core/
|
||||||
|
|
||||||
load: STARTUP
|
load: STARTUP
|
||||||
|
|
||||||
@@ -14,9 +21,6 @@ softdepend:
|
|||||||
- PlayerPoints
|
- PlayerPoints
|
||||||
- PlaceholderAPI
|
- PlaceholderAPI
|
||||||
|
|
||||||
loadbefore:
|
|
||||||
- HamsterAPI
|
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
hamster-core:
|
hamster-core:
|
||||||
aliases: [ hcore ]
|
aliases: [ hcore ]
|
||||||
|
@@ -3,26 +3,30 @@
|
|||||||
evaluationDependsOn(":core-common")
|
evaluationDependsOn(":core-common")
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":core-common")) { isTransitive = false }
|
api(project(":core-common")) { isTransitive = false }
|
||||||
compileOnly("net.md-5:bungeecord-api:1.20-R0.1")
|
compileOnly("net.md-5:bungeecord-api:1.20-R0.1")
|
||||||
|
|
||||||
implementation("net.kyori:adventure-platform-bungeecord:4.3.2") {
|
api("net.kyori:adventure-platform-bungeecord:4.3.2") {
|
||||||
exclude(group = "org.jetbrains")
|
exclude(group = "org.jetbrains")
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
}
|
}
|
||||||
implementation("net.kyori:adventure-text-minimessage:4.15.0") {
|
api("net.kyori:adventure-text-minimessage:4.15.0") {
|
||||||
exclude(module = "adventure-api")
|
exclude(module = "adventure-api")
|
||||||
exclude(group = "org.jetbrains")
|
exclude(group = "org.jetbrains")
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") }
|
|
||||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||||
implementation("redis.clients:jedis:5.1.2") {
|
api("redis.clients:jedis:5.1.2") {
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
exclude(group = "org.slf4j")
|
exclude(group = "org.slf4j")
|
||||||
}
|
}
|
||||||
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
||||||
implementation("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
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 {
|
tasks {
|
||||||
|
@@ -2,15 +2,13 @@ package cn.hamster3.mc.plugin.core.bungee;
|
|||||||
|
|
||||||
import cn.hamster3.mc.plugin.core.bungee.api.CoreBungeeAPI;
|
import cn.hamster3.mc.plugin.core.bungee.api.CoreBungeeAPI;
|
||||||
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.config.YamlConfig;
|
||||||
import cn.hamster3.mc.plugin.core.common.util.JenkinsUtils;
|
import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -41,11 +39,11 @@ public class HamsterCorePlugin extends Plugin {
|
|||||||
}
|
}
|
||||||
File configFile = new File(dataFolder, "config.yml");
|
File configFile = new File(dataFolder, "config.yml");
|
||||||
if (!configFile.exists()) {
|
if (!configFile.exists()) {
|
||||||
Files.copy(
|
try (InputStream stream = getResourceAsStream("config.yml")) {
|
||||||
getResourceAsStream("config.yml"),
|
if (stream != null) {
|
||||||
configFile.toPath(),
|
Files.copy(stream, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
StandardCopyOption.REPLACE_EXISTING
|
}
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
CoreBungeeAPI.init(configFile);
|
CoreBungeeAPI.init(configFile);
|
||||||
logger.info("已初始化 CoreAPI");
|
logger.info("已初始化 CoreAPI");
|
||||||
@@ -64,9 +62,9 @@ public class HamsterCorePlugin extends Plugin {
|
|||||||
logger.info("仓鼠核心正在启动");
|
logger.info("仓鼠核心正在启动");
|
||||||
audienceProvider = BungeeAudiences.create(this);
|
audienceProvider = BungeeAudiences.create(this);
|
||||||
logger.info("已创建 AudienceProvider");
|
logger.info("已创建 AudienceProvider");
|
||||||
|
CoreAPI.getInstance().getExecutorService().submit(this::checkUpdate);
|
||||||
long time = System.currentTimeMillis() - start;
|
long time = System.currentTimeMillis() - start;
|
||||||
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||||
showUpdate(ProxyServer.getInstance().getConsole());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,36 +83,22 @@ public class HamsterCorePlugin extends Plugin {
|
|||||||
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showUpdate(@NotNull CommandSender sender) {
|
private void checkUpdate() {
|
||||||
ProxyServer.getInstance().getScheduler().runAsync(HamsterCorePlugin.getInstance(), () -> {
|
for (Plugin plugin : ProxyServer.getInstance().getPluginManager().getPlugins()) {
|
||||||
for (Plugin plugin : ProxyServer.getInstance().getPluginManager().getPlugins()) {
|
try (InputStream stream = plugin.getResourceAsStream("bungee.yml")) {
|
||||||
InputStream resource = plugin.getResourceAsStream("jenkins.yml");
|
if (stream == null) {
|
||||||
if (resource == null) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try (InputStreamReader reader = new InputStreamReader(resource, StandardCharsets.UTF_8)) {
|
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
YamlConfig jenkinsConfig = YamlConfig.load(reader);
|
YamlConfig config = YamlConfig.load(reader);
|
||||||
String jobUrl = jenkinsConfig.getString("JOB_URL");
|
ConfigSection section = config.getSection("UPDATE_CHECKER");
|
||||||
if (jobUrl == null || jobUrl.equalsIgnoreCase("DEV")) {
|
if (section == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String buildNumberString = jenkinsConfig.getString("BUILD_NUMBER");
|
UpdateCheckUtils.checkUpdate(plugin.getDescription().getName(), section);
|
||||||
if (buildNumberString == null || buildNumberString.equalsIgnoreCase("DEV")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int lastStableBuild = JenkinsUtils.getLastStableBuild(jobUrl, null, null);
|
|
||||||
int buildNumber = Integer.parseInt(buildNumberString);
|
|
||||||
int version = lastStableBuild - buildNumber;
|
|
||||||
if (version <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String pluginName = plugin.getDescription().getName();
|
|
||||||
sender.sendMessage(TextComponent.fromLegacyText(String.format(
|
|
||||||
"§a检测到插件 %s 落后 %d 个版本更新, 下载链接: §n§l%s", pluginName, version, jobUrl
|
|
||||||
)));
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
}
|
||||||
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ 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 gsonHuman;
|
||||||
|
|
||||||
private CoreBungeeAPI(@NotNull ConfigSection config) {
|
private CoreBungeeAPI(@NotNull ConfigSection config) {
|
||||||
super(config);
|
super(config);
|
||||||
@@ -30,7 +30,7 @@ public final class CoreBungeeAPI extends CoreAPI {
|
|||||||
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
|
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
|
||||||
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
|
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
|
||||||
.create();
|
.create();
|
||||||
humanGson = new GsonBuilder()
|
gsonHuman = new GsonBuilder()
|
||||||
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
|
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
|
||||||
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
|
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
|
||||||
.serializeNulls()
|
.serializeNulls()
|
||||||
@@ -62,7 +62,7 @@ public final class CoreBungeeAPI extends CoreAPI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Gson getGsonHuman() {
|
public @NotNull Gson getGsonHuman() {
|
||||||
return humanGson;
|
return gsonHuman;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -8,6 +8,7 @@ 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;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
@@ -66,11 +67,11 @@ public final class CoreBungeeCordUtils {
|
|||||||
}
|
}
|
||||||
File configFile = new File(plugin.getDataFolder(), filename);
|
File configFile = new File(plugin.getDataFolder(), filename);
|
||||||
try {
|
try {
|
||||||
Files.copy(
|
try (InputStream stream = plugin.getResourceAsStream(filename)) {
|
||||||
plugin.getResourceAsStream(filename),
|
if (stream != null) {
|
||||||
configFile.toPath(),
|
Files.copy(stream, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
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);
|
||||||
|
@@ -3,4 +3,12 @@ main: cn.hamster3.mc.plugin.core.bungee.HamsterCorePlugin
|
|||||||
version: ${version}
|
version: ${version}
|
||||||
|
|
||||||
author: MiniDay
|
author: MiniDay
|
||||||
description: 仓鼠核心:叁只仓鼠的 Minecraft 插件开发通用工具包
|
description: ${description}
|
||||||
|
website: https://git.airgame.net/MiniDay/hamster-core
|
||||||
|
|
||||||
|
UPDATE_CHECKER:
|
||||||
|
VERSION: ${version}
|
||||||
|
CHECK_TYPE: GITEA_RELEASES
|
||||||
|
GIT_BASE_URL: https://git.airgame.net
|
||||||
|
GIT_REPO: MiniDay/hamster-core
|
||||||
|
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-core/
|
||||||
|
@@ -10,11 +10,9 @@ redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
|||||||
|
|
||||||
datasource:
|
datasource:
|
||||||
# 数据库链接驱动地址
|
# 数据库链接驱动地址
|
||||||
# 除非你知道自己在做什么,否则不建议更改该项
|
|
||||||
driver: "com.mysql.cj.jdbc.Driver"
|
driver: "com.mysql.cj.jdbc.Driver"
|
||||||
# 数据库链接填写格式:
|
# MySQL数据库链接填写格式:
|
||||||
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
|
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
|
||||||
# 除非你知道自己在做什么,否则不建议随意更改参数
|
|
||||||
url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
|
url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
|
||||||
# 用户名
|
# 用户名
|
||||||
username: "root"
|
username: "root"
|
||||||
|
@@ -1,6 +0,0 @@
|
|||||||
BUILD_ID: ${BUILD_ID}
|
|
||||||
BUILD_NUMBER: ${BUILD_NUMBER}
|
|
||||||
BUILD_DISPLAY_NAME: ${BUILD_DISPLAY_NAME}
|
|
||||||
JOB_URL: ${JOB_URL}
|
|
||||||
BUILD_URL: ${BUILD_URL}
|
|
||||||
GIT_COMMIT: ${GIT_COMMIT}
|
|
@@ -4,21 +4,30 @@ 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
|
// https://mvnrepository.com/artifact/org.yaml/snakeyaml
|
||||||
compileOnly("org.yaml:snakeyaml:1.30")
|
compileOnly("org.yaml:snakeyaml:1.30")
|
||||||
|
// https://mvnrepository.com/artifact/org.slf4j/slf4j-api
|
||||||
|
compileOnly("org.slf4j:slf4j-api:2.0.12")
|
||||||
|
|
||||||
implementation("net.kyori:adventure-platform-api:4.3.2") { exclude(group = "org.jetbrains") }
|
compileOnlyApi("net.kyori:adventure-platform-api:4.3.2") { exclude(group = "org.jetbrains") }
|
||||||
implementation("net.kyori:adventure-text-serializer-gson:4.13.1") {
|
compileOnlyApi("net.kyori:adventure-text-serializer-gson:4.13.1") {
|
||||||
|
exclude(group = "org.jetbrains")
|
||||||
|
exclude(group = "com.google.code.gson")
|
||||||
|
}
|
||||||
|
compileOnlyApi("net.kyori:adventure-text-serializer-legacy:4.13.1") {
|
||||||
exclude(group = "org.jetbrains")
|
exclude(group = "org.jetbrains")
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
|
|
||||||
compileOnly("com.zaxxer:HikariCP:4.0.3") { isTransitive = false }
|
|
||||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||||
implementation("redis.clients:jedis:5.1.2") {
|
compileOnlyApi("redis.clients:jedis:5.1.2") {
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
exclude(group = "org.slf4j")
|
exclude(group = "org.slf4j")
|
||||||
}
|
}
|
||||||
compileOnly("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
@@ -2,8 +2,8 @@ package cn.hamster3.mc.plugin.core.common.api;
|
|||||||
|
|
||||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
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 cn.hamster3.mc.plugin.core.common.util.CoreUtils;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.platform.AudienceProvider;
|
import net.kyori.adventure.platform.AudienceProvider;
|
||||||
@@ -29,7 +29,7 @@ public abstract class CoreAPI {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private final JedisPool jedisPool;
|
private final JedisPool jedisPool;
|
||||||
/**
|
/**
|
||||||
* HamsterCore 公用数据库连接池
|
* 公用数据库连接池
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -58,27 +58,12 @@ public abstract class CoreAPI {
|
|||||||
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
|
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
|
||||||
}
|
}
|
||||||
getLogger().info("正在创建数据库连接池");
|
getLogger().info("正在创建数据库连接池");
|
||||||
HikariConfig hikariConfig = new HikariConfig();
|
hikariDataSource = (HikariDataSource) CoreUtils.getDataSource(datasourceConfig);
|
||||||
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("数据库连接池创建完成");
|
getLogger().info("数据库连接池创建完成");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 HamsterCore 公用数据库连接池
|
* 获取公用数据库连接池
|
||||||
*
|
*
|
||||||
* @return 公用数据库连接池
|
* @return 公用数据库连接池
|
||||||
*/
|
*/
|
||||||
@@ -88,7 +73,7 @@ public abstract class CoreAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 HamsterCore 公用数据库连接
|
* 获取公用数据库连接
|
||||||
*
|
*
|
||||||
* @return 公用数据库连接
|
* @return 公用数据库连接
|
||||||
* @throws SQLException -
|
* @throws SQLException -
|
||||||
|
@@ -1,12 +1,16 @@
|
|||||||
package cn.hamster3.mc.plugin.core.common.util;
|
package cn.hamster3.mc.plugin.core.common.util;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import net.kyori.adventure.key.Key;
|
import net.kyori.adventure.key.Key;
|
||||||
import net.kyori.adventure.sound.Sound;
|
import net.kyori.adventure.sound.Sound;
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||||
import net.kyori.adventure.title.Title;
|
import net.kyori.adventure.title.Title;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -121,6 +125,26 @@ 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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按照给定的表达式计算
|
* 按照给定的表达式计算
|
||||||
* <p>
|
* <p>
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
package cn.hamster3.mc.plugin.core.common.util;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
public final class JenkinsUtils {
|
|
||||||
private static final JsonParser JSON_PARSER = new JsonParser();
|
|
||||||
|
|
||||||
private JenkinsUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getLastStableBuild(@NotNull String jobUrl, @Nullable String username, @Nullable String apiToken) throws IOException {
|
|
||||||
URL url = new URL(jobUrl + "api/json");
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
connection.setDoInput(true);
|
|
||||||
connection.setRequestMethod("GET");
|
|
||||||
if (username != null && apiToken != null) {
|
|
||||||
String token = username + ":" + apiToken;
|
|
||||||
String base64 = Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8));
|
|
||||||
connection.setRequestProperty("Authorization", "Basic " + base64);
|
|
||||||
}
|
|
||||||
connection.connect();
|
|
||||||
try (InputStream stream = connection.getInputStream()) {
|
|
||||||
try (InputStreamReader reader = new InputStreamReader(stream)) {
|
|
||||||
JsonObject object = JSON_PARSER.parse(reader).getAsJsonObject();
|
|
||||||
JsonObject lastStableBuild = object.getAsJsonObject("lastStableBuild");
|
|
||||||
return lastStableBuild.get("number").getAsInt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,156 @@
|
|||||||
|
package cn.hamster3.mc.plugin.core.common.util;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||||
|
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public final class UpdateCheckUtils {
|
||||||
|
private static final JsonParser JSON_PARSER = new JsonParser();
|
||||||
|
|
||||||
|
private UpdateCheckUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkUpdate(@NotNull String pluginName, @NotNull ConfigSection updateConfig) throws IOException {
|
||||||
|
checkUpdate(pluginName, updateConfig, CoreAPI.getInstance().getAudienceProvider().console());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkUpdate(@NotNull String pluginName, @NotNull ConfigSection updateConfig, @NotNull Audience sender) throws IOException {
|
||||||
|
String version = updateConfig.getString("VERSION", "");
|
||||||
|
String checkType = updateConfig.getString("CHECK_TYPE", "");
|
||||||
|
String baseUrl = updateConfig.getString("GIT_BASE_URL");
|
||||||
|
String gitRepo = updateConfig.getString("GIT_REPO");
|
||||||
|
String downloadUrl = updateConfig.getString("DOWNLOAD_URL");
|
||||||
|
if (baseUrl == null || gitRepo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String gitToken = updateConfig.getString("GIT_TOKEN");
|
||||||
|
String lastRelease = null;
|
||||||
|
switch (checkType) {
|
||||||
|
case "GITEA_RELEASES": {
|
||||||
|
lastRelease = getGiteaLastRelease(baseUrl, gitRepo, gitToken);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "GITLAB_RELEASES": {
|
||||||
|
int projectID = getGitlabProjectID(baseUrl, gitRepo, gitToken);
|
||||||
|
if (projectID < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lastRelease = getGitlabLastRelease(baseUrl, projectID, gitToken);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastRelease == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compareVersion(lastRelease, version) <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sender.sendMessage(LegacyComponentSerializer.legacySection().deserialize(
|
||||||
|
String.format("§a插件 §l%s§a 发布了新版本 %s", pluginName, lastRelease)
|
||||||
|
));
|
||||||
|
if (downloadUrl != null) {
|
||||||
|
sender.sendMessage(LegacyComponentSerializer.legacySection().deserialize("§b下载链接: §n" + downloadUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compareVersion(@NotNull String version1, String version2) {
|
||||||
|
List<Integer> collect1 = Arrays.stream(version1.split("[+-]")[0].split("\\."))
|
||||||
|
.map(Integer::parseInt).collect(Collectors.toList());
|
||||||
|
List<Integer> collect2 = Arrays.stream(version2.split("[+-]")[0].split("\\."))
|
||||||
|
.map(Integer::parseInt).collect(Collectors.toList());
|
||||||
|
int max = Math.max(collect1.size(), collect2.size());
|
||||||
|
for (int i = 0; i < max; i++) {
|
||||||
|
int v1 = i < collect1.size() ? collect1.get(i) : 0;
|
||||||
|
int v2 = i < collect2.size() ? collect2.get(i) : 0;
|
||||||
|
if (v1 > v2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (v1 < v2) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getGiteaLastRelease(@NotNull String baseUrl, @NotNull String repo, @Nullable String token) throws IOException {
|
||||||
|
URL url = new URL(baseUrl + "/api/v1/repos/" + repo + "/releases?limit=10");
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
if (token != null) {
|
||||||
|
connection.setRequestProperty("Authorization", "token " + token);
|
||||||
|
}
|
||||||
|
connection.connect();
|
||||||
|
try (InputStream stream = connection.getInputStream()) {
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
|
JsonArray array = JSON_PARSER.parse(reader).getAsJsonArray();
|
||||||
|
for (JsonElement element : array) {
|
||||||
|
JsonObject object = element.getAsJsonObject();
|
||||||
|
//noinspection SpellCheckingInspection
|
||||||
|
if (object.get("prerelease").getAsBoolean()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return object.get("name").getAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getGitlabProjectID(@NotNull String baseUrl, @NotNull String repo, @Nullable String token) throws IOException {
|
||||||
|
URL url = new URL(baseUrl + "/api/v4/projects?search=" + repo);
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
if (token != null) {
|
||||||
|
connection.setRequestProperty("PRIVATE-TOKEN", token);
|
||||||
|
}
|
||||||
|
connection.connect();
|
||||||
|
try (InputStream stream = connection.getInputStream()) {
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
|
JsonArray array = JSON_PARSER.parse(reader).getAsJsonArray();
|
||||||
|
for (JsonElement element : array) {
|
||||||
|
JsonObject object = element.getAsJsonObject();
|
||||||
|
return object.get("id").getAsInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getGitlabLastRelease(@NotNull String baseUrl, int repo, @Nullable String token) throws IOException {
|
||||||
|
URL url = new URL(baseUrl + "/api/v4/projects/" + repo + "/releases/permalink/latest");
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setDoInput(true);
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
if (token != null) {
|
||||||
|
connection.setRequestProperty("PRIVATE-TOKEN", token);
|
||||||
|
}
|
||||||
|
connection.connect();
|
||||||
|
try (InputStream stream = connection.getInputStream()) {
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
|
JsonObject object = JSON_PARSER.parse(reader).getAsJsonObject();
|
||||||
|
return object.get("name").getAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
core-velocity/build.gradle.kts
Normal file
59
core-velocity/build.gradle.kts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
@file:Suppress("VulnerableLibrariesLocal")
|
||||||
|
|
||||||
|
evaluationDependsOn(":core-common")
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api(project(":core-common")) { isTransitive = false }
|
||||||
|
compileOnly("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
|
||||||
|
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") {
|
||||||
|
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") {
|
||||||
|
java {
|
||||||
|
srcDir("src/main/templates")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val templateSource = file("src/main/templates")
|
||||||
|
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
|
||||||
|
val generateTemplates = tasks.register<Copy>("generateTemplates") {
|
||||||
|
from(templateSource)
|
||||||
|
into(templateDest)
|
||||||
|
expand(rootProject.properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main.get().java.srcDir(generateTemplates.map { it.outputs })
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
withType<Jar> {
|
||||||
|
archiveBaseName = "HamsterCore-Velocity"
|
||||||
|
}
|
||||||
|
shadowJar {
|
||||||
|
destinationDirectory = rootProject.layout.buildDirectory
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,124 @@
|
|||||||
|
package cn.hamster3.mc.plugin.core.velocity;
|
||||||
|
|
||||||
|
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 com.google.inject.Inject;
|
||||||
|
import com.velocitypowered.api.event.PostOrder;
|
||||||
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
|
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
|
@Plugin(
|
||||||
|
id = "hamster-core",
|
||||||
|
name = "HamsterCore",
|
||||||
|
version = BuildConstants.VERSION,
|
||||||
|
description = BuildConstants.DESCRIPTION,
|
||||||
|
authors = {"MiniDay"}
|
||||||
|
)
|
||||||
|
public class HamsterCorePlugin {
|
||||||
|
@Getter
|
||||||
|
private static HamsterCorePlugin instance;
|
||||||
|
@Getter
|
||||||
|
private final java.util.logging.Logger logger;
|
||||||
|
@Getter
|
||||||
|
private final Logger slf4jLogger;
|
||||||
|
@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;
|
||||||
|
this.proxyServer = proxyServer;
|
||||||
|
dataFolder = dataPath.toFile();
|
||||||
|
instance = this;
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
if (dataFolder.mkdir()) {
|
||||||
|
slf4jLogger.info("已生成插件存档文件夹");
|
||||||
|
}
|
||||||
|
File configFile = new File(dataFolder, "config.yml");
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
try (InputStream stream = HamsterCorePlugin.class.getResourceAsStream("/config.yml")) {
|
||||||
|
if (stream != null) {
|
||||||
|
Files.copy(stream, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CoreVelocityAPI.init(configFile);
|
||||||
|
slf4jLogger.info("已初始化 CoreAPI");
|
||||||
|
} catch (Exception e) {
|
||||||
|
slf4jLogger.error("初始化 CoreAPI 出错", e);
|
||||||
|
}
|
||||||
|
long time = System.currentTimeMillis() - start;
|
||||||
|
slf4jLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe(order = PostOrder.FIRST)
|
||||||
|
public void onProxyInitialization(ProxyInitializeEvent event) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
slf4jLogger.info("仓鼠核心正在启动");
|
||||||
|
CoreAPI.getInstance().getExecutorService().submit(this::checkUpdate);
|
||||||
|
long time = System.currentTimeMillis() - start;
|
||||||
|
slf4jLogger.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("已关闭数据库连接池");
|
||||||
|
}
|
||||||
|
CoreAPI.getInstance().getExecutorService().shutdownNow();
|
||||||
|
slf4jLogger.info("已关闭 ExecutorService 线程池");
|
||||||
|
CoreAPI.getInstance().getScheduledService().shutdownNow();
|
||||||
|
slf4jLogger.info("已关闭 ScheduledExecutorService 线程池");
|
||||||
|
long time = System.currentTimeMillis() - start;
|
||||||
|
slf4jLogger.info("仓鼠核心关闭完成,总计耗时 " + time + " ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUpdate() {
|
||||||
|
for (PluginContainer plugin : proxyServer.getPluginManager().getPlugins()) {
|
||||||
|
String pluginName = plugin.getDescription().getName().orElse(null);
|
||||||
|
if (pluginName == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Object pluginObject = plugin.getInstance().orElse(null);
|
||||||
|
if (pluginObject == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (InputStream stream = pluginObject.getClass().getResourceAsStream("/update.yml")) {
|
||||||
|
if (stream == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||||
|
YamlConfig config = YamlConfig.load(reader);
|
||||||
|
UpdateCheckUtils.checkUpdate(pluginName, config);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,73 @@
|
|||||||
|
package cn.hamster3.mc.plugin.core.velocity.api;
|
||||||
|
|
||||||
|
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.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 com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import net.kyori.adventure.platform.AudienceProvider;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
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 {
|
||||||
|
@NotNull
|
||||||
|
private final Gson gson;
|
||||||
|
@NotNull
|
||||||
|
private final Gson gsonHuman;
|
||||||
|
|
||||||
|
public CoreVelocityAPI(@NotNull ConfigSection config) {
|
||||||
|
super(config);
|
||||||
|
gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
|
||||||
|
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
|
||||||
|
.create();
|
||||||
|
gsonHuman = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Component.class, ComponentTypeAdapter.INSTANCE)
|
||||||
|
.registerTypeAdapter(DisplayMessage.class, MessageTypeAdapter.INSTANCE)
|
||||||
|
.serializeNulls()
|
||||||
|
.setPrettyPrinting()
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CoreVelocityAPI getInstance() {
|
||||||
|
return (CoreVelocityAPI) instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(@NotNull File configFile) throws IOException {
|
||||||
|
if (instance != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
YamlConfig config = YamlConfig.load(configFile);
|
||||||
|
instance = new CoreVelocityAPI(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull AudienceProvider getAudienceProvider() {
|
||||||
|
return AudienceProviderImpl.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Logger getLogger() {
|
||||||
|
return HamsterCorePlugin.getInstance().getLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Gson getGson() {
|
||||||
|
return gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Gson getGsonHuman() {
|
||||||
|
return gsonHuman;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,79 @@
|
|||||||
|
package cn.hamster3.mc.plugin.core.velocity.impl;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.core.velocity.HamsterCorePlugin;
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.platform.AudienceProvider;
|
||||||
|
import net.kyori.adventure.text.flattener.ComponentFlattener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class AudienceProviderImpl implements AudienceProvider {
|
||||||
|
public static final AudienceProviderImpl INSTANCE = new AudienceProviderImpl();
|
||||||
|
|
||||||
|
private AudienceProviderImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience all() {
|
||||||
|
return Audience.audience(console(), players());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience console() {
|
||||||
|
return HamsterCorePlugin.getInstance().getProxyServer().getConsoleCommandSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience players() {
|
||||||
|
return Audience.audience(HamsterCorePlugin.getInstance().getProxyServer().getAllPlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience player(@NotNull UUID playerId) {
|
||||||
|
Player player = HamsterCorePlugin.getInstance().getProxyServer().getPlayer(playerId).orElse(null);
|
||||||
|
if (player == null) {
|
||||||
|
return Audience.empty();
|
||||||
|
}
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience permission(@NotNull String permission) {
|
||||||
|
return Audience.audience(
|
||||||
|
HamsterCorePlugin.getInstance().getProxyServer().getAllPlayers()
|
||||||
|
.stream()
|
||||||
|
.filter(player -> player.hasPermission(permission))
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience world(@NotNull Key world) {
|
||||||
|
return Audience.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Audience server(@NotNull String serverName) {
|
||||||
|
return Audience.audience(
|
||||||
|
HamsterCorePlugin.getInstance().getProxyServer().getAllPlayers()
|
||||||
|
.stream()
|
||||||
|
.filter(player -> player.getCurrentServer()
|
||||||
|
.map(o -> o.getServerInfo().getName().equals(serverName))
|
||||||
|
.orElse(false)
|
||||||
|
).toList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ComponentFlattener flattener() {
|
||||||
|
return ComponentFlattener.basic();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
41
core-velocity/src/main/resources/config.yml
Normal file
41
core-velocity/src/main/resources/config.yml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# redis 连接配置
|
||||||
|
# 完整格式如下:
|
||||||
|
# redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值
|
||||||
|
# 若没有设置 redis 用户名,但设置了密码,则可以使用以下格式:
|
||||||
|
# redis://:密码@localhost:6379?clientName=HamsterCore
|
||||||
|
# 若没有设置 redis 用户名,也没有设置密码,则可以使用以下格式:
|
||||||
|
# redis://localhost:6379?clientName=HamsterCore
|
||||||
|
# 若不设置数据库,则默认使用 0
|
||||||
|
redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
||||||
|
|
||||||
|
datasource:
|
||||||
|
# 数据库链接驱动地址
|
||||||
|
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"
|
||||||
|
# 用户名
|
||||||
|
username: "root"
|
||||||
|
# 密码
|
||||||
|
password: "Root123.."
|
||||||
|
# 最小闲置链接数
|
||||||
|
# 推荐值:1~3
|
||||||
|
minimum-idle: 0
|
||||||
|
# 最大链接数
|
||||||
|
# 推荐值:不低于5
|
||||||
|
maximum-pool-size: 5
|
||||||
|
# 保持连接池可用的间隔
|
||||||
|
# 除非你的服务器数据库连接经常断开,否则不建议启用该选项
|
||||||
|
# 单位:毫秒
|
||||||
|
# 默认值为0(禁用)
|
||||||
|
keep-alive-time: 0
|
||||||
|
# 连接闲置回收时间
|
||||||
|
# 单位:毫秒
|
||||||
|
# 推荐值:600000(10分钟)
|
||||||
|
idle-timeout: 600000
|
||||||
|
# 链接最长存活时间
|
||||||
|
# 单位:毫秒
|
||||||
|
max-lifetime: 1800000
|
||||||
|
# 验证连接存活的超时时间
|
||||||
|
# 单位:毫秒
|
||||||
|
validation-timeout: 5000
|
5
core-velocity/src/main/resources/update.yml
Normal file
5
core-velocity/src/main/resources/update.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
VERSION: ${version}
|
||||||
|
CHECK_TYPE: GITEA_RELEASES
|
||||||
|
GIT_BASE_URL: https://git.airgame.net
|
||||||
|
GIT_REPO: MiniDay/hamster-core
|
||||||
|
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-core/
|
@@ -0,0 +1,8 @@
|
|||||||
|
package cn.hamster3.mc.plugin.core.velocity;
|
||||||
|
|
||||||
|
// The constants are replaced before compilation
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class BuildConstants {
|
||||||
|
public static final String VERSION = "${version}";
|
||||||
|
public static final String DESCRIPTION = "${description}";
|
||||||
|
}
|
@@ -9,3 +9,4 @@ rootProject.name = "hamster-core"
|
|||||||
include("core-common")
|
include("core-common")
|
||||||
include("core-bukkit")
|
include("core-bukkit")
|
||||||
include("core-bungee")
|
include("core-bungee")
|
||||||
|
include("core-velocity")
|
||||||
|
Reference in New Issue
Block a user