Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
0b8614fec9 | |||
b9be8e4b0b | |||
594bdf15b6 | |||
d16602a06d | |||
ad216ef89b | |||
68747f76bb | |||
1c83615b7e | |||
1648a56453 | |||
0f942a7687 | |||
942239be91 | |||
b393ab96ea | |||
cb736bbbf1 | |||
c30e468635 | |||
571dd34bbd | |||
a4638be898 | |||
e03ad98272 | |||
fbd6608864 | |||
85e9130575 | |||
b17ad022d3 | |||
85ce774752 | |||
05b83dd248 | |||
3955f352c6 | |||
00d582a5ea | |||
6beabf4ec4 | |||
608a6ef289 | |||
a75853187c | |||
2263a74a77 | |||
be756b0a56 | |||
be25334cc7 | |||
b6e6641041 | |||
a0ae6ec550 | |||
738b566a2d | |||
271328ef6f | |||
865812c524 | |||
f3e4becf35 | |||
02836c9086 | |||
e2a8cc236e | |||
86bd28e134 | |||
03b0d62b19 | |||
98300804fe | |||
7285f1b3e2 | |||
6f4e40942c | |||
7462b99ce4 | |||
9bcf8a28dd | |||
e6cb7efe77 | |||
fb75b4d95f |
28
.gitea/workflows/main.yaml
Normal file
28
.gitea/workflows/main.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Publish Project
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: temurin
|
||||
cache: gradle
|
||||
- name: Build Project
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_MAVEN_AIRGAME_USERNAME: ${{ secrets.MAVEN_AIRGAME_USERNAME }}
|
||||
ORG_GRADLE_PROJECT_MAVEN_AIRGAME_PASSWORD: ${{ secrets.MAVEN_AIRGAME_PASSWORD }}
|
||||
run: chmod +x gradlew && ./gradlew build publish --console plain --no-daemon
|
||||
- name: Publish to Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: build/*.jar
|
18
README.md
18
README.md
@@ -9,8 +9,6 @@
|
||||
3. 命令行窗口中执行`./gradlew clean build`
|
||||
4. 构建成品在 `build` 文件夹
|
||||
|
||||
也可访问我的[Jenkins网站](https://jenkins.airgame.net/job/opensource/job/hamster-core/)获取最新版
|
||||
|
||||
# 开发
|
||||
|
||||
## 添加依赖
|
||||
@@ -26,9 +24,9 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
// 对于 Bukkit 插件
|
||||
compileOnly("cn.hamster3.mc.plugin:core-bukkit:1.3.2")
|
||||
compileOnly("cn.hamster3.mc.plugin:core-bukkit:1.4.2")
|
||||
// 对于 BungeeCord 插件
|
||||
compileOnly("cn.hamster3.mc.plugin:core-bungee:1.3.2")
|
||||
compileOnly("cn.hamster3.mc.plugin:core-bungee:1.4.2")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -54,13 +52,13 @@ dependencies {
|
||||
<dependency>
|
||||
<groupId>cn.hamster3.mc.plugin</groupId>
|
||||
<artifactId>core-bukkit</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.2</version>
|
||||
</dependency>
|
||||
<!--对于 BungeeCord 插件-->
|
||||
<dependency>
|
||||
<groupId>cn.hamster3.mc.plugin</groupId>
|
||||
<artifactId>core-bungee</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -74,10 +72,4 @@ dependencies {
|
||||
- 使用方法为:`CoreAPI.getInstance().xxx()`
|
||||
- 部分通用的工具代码在 `cn.hamster3.mc.plugin.core.common.util` 包中
|
||||
- 部分Bukkit的工具代码在 `cn.hamster3.mc.plugin.core.bukkit.util` 包中
|
||||
- 部分BungeeCord的工具代码在 `cn.hamster3.mc.plugin.core.bungee.util` 包中
|
||||
|
||||
# 已知问题
|
||||
|
||||
部分 Windows 服务器在启动时偶尔会遇到 Redis 链接失败的问题
|
||||
如果服务器启动时遇到报错 `Caused by: java.io.IOException: Unable to establish loopback connection`
|
||||
可以通过在启动脚本中添加 `-Djava.net.preferIPv4Stack=true` 参数解决
|
||||
- 部分BungeeCord的工具代码在 `cn.hamster3.mc.plugin.core.bungee.util` 包中
|
@@ -1,21 +1,23 @@
|
||||
plugins {
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("com.github.johnrengelman.shadow") version "8+"
|
||||
id("com.gradleup.shadow") version "8.3.6"
|
||||
}
|
||||
|
||||
group = "cn.hamster3.mc.plugin"
|
||||
version = "1.3.2"
|
||||
version = "1.4.2"
|
||||
description = "叁只仓鼠的 Minecraft 插件开发通用工具包"
|
||||
|
||||
subprojects {
|
||||
apply {
|
||||
plugin("java-library")
|
||||
plugin("maven-publish")
|
||||
plugin("com.github.johnrengelman.shadow")
|
||||
plugin("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
description = rootProject.description
|
||||
|
||||
repositories {
|
||||
maven("https://maven.airgame.net/maven-public")
|
||||
@@ -36,6 +38,11 @@ subprojects {
|
||||
}
|
||||
|
||||
tasks {
|
||||
processResources {
|
||||
filesMatching("update.yml") {
|
||||
expand(rootProject.properties)
|
||||
}
|
||||
}
|
||||
withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
@@ -43,11 +50,6 @@ subprojects {
|
||||
from(rootProject.file("LICENSE"))
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
processResources {
|
||||
filesMatching("update.yml") {
|
||||
expand(rootProject.properties)
|
||||
}
|
||||
}
|
||||
build {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
@@ -62,10 +64,9 @@ subprojects {
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://maven.airgame.net/public")
|
||||
|
||||
credentials {
|
||||
username = rootProject.properties.getOrDefault("maven_username", "").toString()
|
||||
password = rootProject.properties.getOrDefault("maven_password", "").toString()
|
||||
username = findProperty("MAVEN_AIRGAME_USERNAME")?.toString() ?: ""
|
||||
password = findProperty("MAVEN_AIRGAME_PASSWORD")?.toString() ?: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,9 @@
|
||||
@file:Suppress("VulnerableLibrariesLocal")
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
evaluationDependsOn(":core-common")
|
||||
evaluationDependsOn(":core-relocate-lettuce")
|
||||
|
||||
val shade = configurations.create("shade")
|
||||
val shadeJava8 = configurations.create("shadeJava8")
|
||||
|
||||
dependencies {
|
||||
api(project(":core-common")) { isTransitive = false }
|
||||
@@ -15,33 +13,31 @@ dependencies {
|
||||
compileOnly("org.black_ixx:playerpoints:3.2.6") { isTransitive = false }
|
||||
compileOnly("me.clip:placeholderapi:2.11.5") { isTransitive = false }
|
||||
|
||||
// https://www.spigotmc.org/resources/nbt-api.7939/
|
||||
implementation("de.tr7zw:item-nbt-api:2.15.1")
|
||||
|
||||
api("net.kyori:adventure-platform-bukkit:4.3.2") {
|
||||
exclude(group = "org.jetbrains")
|
||||
exclude(group = "com.google.code.gson")
|
||||
exclude(group = "io.netty")
|
||||
}
|
||||
api("net.kyori:adventure-text-minimessage:4.15.0") {
|
||||
exclude(module = "adventure-api")
|
||||
exclude(group = "org.jetbrains")
|
||||
exclude(group = "io.netty")
|
||||
}
|
||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||
api("redis.clients:jedis:5.1.2") {
|
||||
|
||||
implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") }
|
||||
api("redis.clients:jedis:5.1.4") {
|
||||
exclude(group = "com.google.code.gson")
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
||||
api("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
||||
|
||||
// https://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
|
||||
shade("org.jetbrains.kotlin:kotlin-stdlib:1.9.23") { exclude(group = "org.jetbrains") }
|
||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8
|
||||
shadeJava8("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.23") { exclude(group = "org.jetbrains") }
|
||||
compileOnlyApi("io.lettuce:lettuce-core:6.7.1.RELEASE") {
|
||||
exclude(group = "org.slf4j")
|
||||
exclude(group = "io.netty")
|
||||
}
|
||||
shade(project(":core-relocate-lettuce"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
processResources {
|
||||
filesMatching("plugin.yml") {
|
||||
@@ -52,23 +48,11 @@ tasks {
|
||||
archiveBaseName = "HamsterCore-Bukkit"
|
||||
}
|
||||
shadowJar {
|
||||
from(shade.map { if (it.isDirectory) it else zipTree(it) })
|
||||
dependsOn(":core-relocate-lettuce:shadowJar")
|
||||
val task = project(":core-relocate-lettuce").tasks.shadowJar.get()
|
||||
from(task.outputs.files.map { if (it.isDirectory) it else zipTree(it) })
|
||||
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")
|
||||
}
|
||||
val shadowJava8 = register<ShadowJar>("shadowJava8") {
|
||||
dependsOn(":core-common:build")
|
||||
archiveClassifier = "Java8"
|
||||
from(project.configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
|
||||
from(processResources.get().outputs)
|
||||
from(jar.get().outputs)
|
||||
from(shadeJava8.map { if (it.isDirectory) it else zipTree(it) })
|
||||
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")
|
||||
}
|
||||
build {
|
||||
dependsOn(shadowJava8)
|
||||
}
|
||||
}
|
||||
|
@@ -11,10 +11,14 @@ import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.listener.DebugListener;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.page.handler.PageHandler;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.page.listener.PageListener;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.util.BukkitSimpleLogger;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.util.MinecraftVersion;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
import cn.hamster3.mc.plugin.core.common.config.YamlConfig;
|
||||
import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -27,19 +31,18 @@ import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@SuppressWarnings("CallToPrintStackTrace")
|
||||
public class HamsterCorePlugin extends JavaPlugin {
|
||||
@Getter
|
||||
private static HamsterCorePlugin instance;
|
||||
@Getter
|
||||
private static BukkitSimpleLogger simpleLogger;
|
||||
@Getter
|
||||
private BukkitAudiences audienceProvider;
|
||||
|
||||
/**
|
||||
@@ -67,15 +70,15 @@ public class HamsterCorePlugin extends JavaPlugin {
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
simpleLogger = new BukkitSimpleLogger(getInstance());
|
||||
long start = System.currentTimeMillis();
|
||||
Logger logger = getLogger();
|
||||
logger.info("仓鼠核心正在初始化");
|
||||
logger.info("Minecraft 版本: " + MinecraftVersion.getMCVersion());
|
||||
logger.info("NMS 版本: " + MinecraftVersion.getNMSVersion());
|
||||
simpleLogger.info("仓鼠核心正在初始化");
|
||||
simpleLogger.info("Minecraft 版本: " + MinecraftVersion.getMCVersion());
|
||||
simpleLogger.info("NMS 版本: " + MinecraftVersion.getNMSVersion());
|
||||
try {
|
||||
File dataFolder = getDataFolder();
|
||||
if (dataFolder.mkdir()) {
|
||||
logger.info("已生成插件存档文件夹");
|
||||
simpleLogger.info("已生成插件存档文件夹");
|
||||
}
|
||||
File configFile = new File(dataFolder, "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
@@ -86,68 +89,62 @@ public class HamsterCorePlugin extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
CoreBukkitAPI.init(configFile);
|
||||
logger.info("已初始化 CoreAPI");
|
||||
simpleLogger.info("已初始化 CoreAPI");
|
||||
} catch (Exception e) {
|
||||
logger.warning("初始化 CoreAPI 出错");
|
||||
e.printStackTrace();
|
||||
simpleLogger.error(e, "初始化 CoreAPI 出错");
|
||||
}
|
||||
CoreMessage.init(this);
|
||||
logger.info("已初始化语言文本");
|
||||
simpleLogger.info("已初始化语言文本");
|
||||
long time = System.currentTimeMillis() - start;
|
||||
logger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms");
|
||||
simpleLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
long start = System.currentTimeMillis();
|
||||
Logger logger = getLogger();
|
||||
logger.info("仓鼠核心正在启动");
|
||||
simpleLogger.info("仓鼠核心正在启动");
|
||||
NBT.preloadApi();
|
||||
audienceProvider = BukkitAudiences.create(this);
|
||||
logger.info("已创建 AudienceProvider");
|
||||
simpleLogger.info("已创建 AudienceProvider");
|
||||
CoreCommand.INSTANCE.register();
|
||||
LoreCommand.INSTANCE.register();
|
||||
NBTCommand.INSTANCE.register();
|
||||
Bukkit.getPluginManager().registerEvents(PageListener.INSTANCE, this);
|
||||
logger.info("已注册 PageListener");
|
||||
simpleLogger.info("已注册 PageListener");
|
||||
Bukkit.getPluginManager().registerEvents(CallbackListener.INSTANCE, this);
|
||||
logger.info("已注册 CallbackListener");
|
||||
simpleLogger.info("已注册 CallbackListener");
|
||||
Bukkit.getPluginManager().registerEvents(DebugListener.INSTANCE, this);
|
||||
logger.info("已注册 DebugListener");
|
||||
simpleLogger.info("已注册 DebugListener");
|
||||
simpleLogger.info("Redis 启用状态: %b", CoreAPI.getInstance().isEnableRedis());
|
||||
simpleLogger.info("Database 启用状态: %b", CoreAPI.getInstance().isEnableDatabase());
|
||||
simpleLogger.info("已注册 DebugListener");
|
||||
long time = System.currentTimeMillis() - start;
|
||||
sync(() -> {
|
||||
PointAPI.reloadPlayerPointAPIHook();
|
||||
VaultAPI.reloadVaultHook();
|
||||
async(() -> {
|
||||
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||
try (InputStream stream = plugin.getResource("update.yml")) {
|
||||
if (stream == null) {
|
||||
continue;
|
||||
}
|
||||
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||
YamlConfig config = YamlConfig.load(reader);
|
||||
UpdateCheckUtils.showUpdate(plugin.getName(), config, Bukkit.getConsoleSender()::sendMessage);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async(this::checkUpdate);
|
||||
});
|
||||
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||
simpleLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
long start = System.currentTimeMillis();
|
||||
Logger logger = getLogger();
|
||||
CoreAPI.getInstance().getJedisPool().close();
|
||||
logger.info("已关闭 Redis 连接池");
|
||||
CoreAPI.getInstance().getHikariDataSource().close();
|
||||
logger.info("已关闭数据库连接池");
|
||||
audienceProvider.close();
|
||||
simpleLogger.info("已关闭 AudienceProvider.");
|
||||
if (CoreAPI.getInstance().isEnableRedis()) {
|
||||
CoreAPI.getInstance().getJedisPool().close();
|
||||
CoreAPI.getInstance().getRedisClient().close();
|
||||
simpleLogger.info("已关闭 Redis 连接池");
|
||||
}
|
||||
if (CoreAPI.getInstance().isEnableDatabase()) {
|
||||
((HikariDataSource) CoreAPI.getInstance().getDataSource()).close();
|
||||
simpleLogger.info("已关闭数据库连接池");
|
||||
}
|
||||
CoreAPI.getInstance().getExecutorService().shutdownNow();
|
||||
logger.info("已关闭 ExecutorService 线程池");
|
||||
simpleLogger.info("已关闭 ExecutorService 线程池");
|
||||
CoreAPI.getInstance().getScheduledService().shutdownNow();
|
||||
logger.info("已关闭 ScheduledExecutorService 线程池");
|
||||
simpleLogger.info("已关闭 ScheduledExecutorService 线程池");
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
InventoryView view = player.getOpenInventory();
|
||||
Inventory inventory = view.getTopInventory();
|
||||
@@ -156,8 +153,27 @@ public class HamsterCorePlugin extends JavaPlugin {
|
||||
}
|
||||
player.closeInventory();
|
||||
}
|
||||
logger.info("已关闭所有玩家的界面");
|
||||
simpleLogger.info("已关闭所有玩家的界面");
|
||||
long time = System.currentTimeMillis() - start;
|
||||
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
||||
simpleLogger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
private void checkUpdate() {
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package cn.hamster3.mc.plugin.core.bukkit.api;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.impl.ItemStackAdapter;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.impl.PotionEffectAdapter;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.util.BukkitSimpleLogger;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.util.MinecraftVersion;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
@@ -20,7 +21,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class CoreBukkitAPI extends CoreAPI {
|
||||
@@ -62,8 +62,8 @@ public final class CoreBukkitAPI extends CoreAPI {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Logger getLogger() {
|
||||
return HamsterCorePlugin.getInstance().getLogger();
|
||||
public @NotNull BukkitSimpleLogger getLogger() {
|
||||
return HamsterCorePlugin.getSimpleLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -11,6 +11,10 @@ public abstract class ChildCommand implements TabExecutor {
|
||||
@NotNull
|
||||
public abstract String getUsage();
|
||||
|
||||
public int getArgumentCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract String getDescription();
|
||||
|
||||
|
@@ -14,10 +14,10 @@ import java.util.stream.Collectors;
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class ParentCommand extends ChildCommand {
|
||||
@NotNull
|
||||
private final List<ChildCommand> childCommands;
|
||||
private final Map<String, ChildCommand> childCommands;
|
||||
|
||||
public ParentCommand() {
|
||||
childCommands = new ArrayList<>();
|
||||
childCommands = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -33,8 +33,8 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ChildCommand> getChildCommands() {
|
||||
return childCommands;
|
||||
public Collection<ChildCommand> getChildCommands() {
|
||||
return childCommands.values();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -78,7 +78,7 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
@NotNull
|
||||
public List<ChildCommand> getEndChildCommands() {
|
||||
ArrayList<ChildCommand> list = new ArrayList<>();
|
||||
for (ChildCommand command : childCommands) {
|
||||
for (ChildCommand command : getChildCommands()) {
|
||||
if (command instanceof ParentCommand) {
|
||||
list.addAll(((ParentCommand) command).getEndChildCommands());
|
||||
} else {
|
||||
@@ -89,13 +89,16 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
}
|
||||
|
||||
public void addChildCommand(@NotNull ChildCommand command) {
|
||||
childCommands.add(command);
|
||||
if (childCommands.containsKey(command.getName())) {
|
||||
throw new IllegalArgumentException("command " + command.getName() + " already exists!");
|
||||
}
|
||||
childCommands.put(command.getName(), command);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, String> getCommandHelp(CommandSender sender) {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
for (ChildCommand child : childCommands) {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
for (ChildCommand child : getChildCommands()) {
|
||||
if (!child.hasPermission(sender)) {
|
||||
continue;
|
||||
}
|
||||
@@ -110,17 +113,13 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
}
|
||||
|
||||
public void sendHelp(@NotNull CommandSender sender) {
|
||||
sender.sendMessage("§e==================== [ " + getName() + " 使用帮助] ====================");
|
||||
Map<String, String> helpMap = getCommandHelp(sender);
|
||||
int maxLength = helpMap.keySet().stream()
|
||||
.map(String::length)
|
||||
.max(Integer::compareTo)
|
||||
.orElse(-1);
|
||||
ArrayList<Map.Entry<String, String>> list = new ArrayList<>(helpMap.entrySet());
|
||||
list.sort(Map.Entry.comparingByKey());
|
||||
for (Map.Entry<String, String> entry : list) {
|
||||
sender.sendMessage(String.format("§a%-" + maxLength + "s - %s", entry.getKey(), entry.getValue()));
|
||||
sender.sendMessage("§2§l<<< 命令 [" + getUsage() + "] 帮助 >>>");
|
||||
Map<String, String> map = getCommandHelp(sender);
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
sender.sendMessage(" §3" + entry.getKey());
|
||||
sender.sendMessage(" §7" + entry.getValue());
|
||||
}
|
||||
sender.sendMessage("§2§l<<< 由插件 " + getPlugin().getName() + "-" + getPlugin().getDescription().getVersion() + " 提供 >>>");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,7 +132,7 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
sendHelp(sender);
|
||||
return true;
|
||||
}
|
||||
for (ChildCommand childCommand : childCommands) {
|
||||
for (ChildCommand childCommand : getChildCommands()) {
|
||||
if (!childCommand.getName().equalsIgnoreCase(args[0])) {
|
||||
continue;
|
||||
}
|
||||
@@ -141,6 +140,10 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
CoreMessage.COMMAND_NOT_HAS_PERMISSION.show(sender);
|
||||
return true;
|
||||
}
|
||||
if (args.length - 1 < childCommand.getArgumentCount()) {
|
||||
sender.sendMessage(getUsage() + " " + childCommand.getUsage());
|
||||
return true;
|
||||
}
|
||||
return childCommand.onCommand(sender, command, label, Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
CoreMessage.COMMAND_NOT_FOUND.show(sender);
|
||||
@@ -150,18 +153,18 @@ public abstract class ParentCommand extends ChildCommand {
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
|
||||
if (args.length == 0) {
|
||||
return childCommands.stream()
|
||||
return getChildCommands().stream()
|
||||
.filter(o -> o.hasPermission(sender))
|
||||
.map(ChildCommand::getName)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
for (ChildCommand child : childCommands) {
|
||||
for (ChildCommand child : getChildCommands()) {
|
||||
if (args[0].equalsIgnoreCase(child.getName())) {
|
||||
return child.onTabComplete(sender, command, alias, Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
}
|
||||
args[0] = args[0].toLowerCase();
|
||||
return childCommands.stream()
|
||||
return getChildCommands().stream()
|
||||
.filter(o -> o.hasPermission(sender))
|
||||
.map(ChildCommand::getName)
|
||||
.filter(o -> o.toLowerCase().startsWith(args[0].toLowerCase()))
|
||||
|
@@ -69,9 +69,9 @@ public class InfoModeCommand extends ChildCommand {
|
||||
}
|
||||
|
||||
if (DebugListener.INFO_MODE_PLAYERS.contains(uuid)) {
|
||||
CoreMessage.COMMAND_DEBUG_INFO_MODE_OFF.show(player);
|
||||
} else {
|
||||
CoreMessage.COMMAND_DEBUG_INFO_MODE_ON.show(player);
|
||||
} else {
|
||||
CoreMessage.COMMAND_DEBUG_INFO_MODE_OFF.show(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -78,13 +78,13 @@ public class YamlCommand extends ChildCommand {
|
||||
config.set("test-item", stack);
|
||||
File dataFolder = new File(HamsterCorePlugin.getInstance().getDataFolder(), "yaml");
|
||||
if (dataFolder.mkdirs()) {
|
||||
HamsterCorePlugin.getInstance().getLogger().info("创建 yaml 存档文件夹");
|
||||
HamsterCorePlugin.getSimpleLogger().info("创建 yaml 存档文件夹");
|
||||
}
|
||||
File saveFile = new File(dataFolder, sender.getName() + "_" + System.currentTimeMillis() + ".yml");
|
||||
try {
|
||||
config.save(saveFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
HamsterCorePlugin.getSimpleLogger().error(e);
|
||||
}
|
||||
sender.sendMessage("§a信息已保存至文件 " + saveFile.getAbsolutePath());
|
||||
return true;
|
||||
|
@@ -4,7 +4,11 @@ import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.command.ParentCommand;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.constant.CoreMessage;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.util.CoreBukkitUtils;
|
||||
import de.tr7zw.changeme.nbtapi.*;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.NBTType;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
|
||||
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTList;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -62,13 +66,12 @@ public class NBTCommand extends ParentCommand {
|
||||
sender.sendMessage("§c你的手持物品为空");
|
||||
return true;
|
||||
}
|
||||
NBTItem nbtItem = new NBTItem(stack);
|
||||
sendNBTCompound(nbtItem, sender, 0);
|
||||
ReadWriteNBT readWriteNBT = NBT.itemStackToNBT(stack);
|
||||
sendNBTCompound(readWriteNBT, sender, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ForLoopReplaceableByForEach")
|
||||
private void sendNBTCompound(NBTCompound compound, CommandSender sender, int level) {
|
||||
private void sendNBTCompound(ReadWriteNBT compound, CommandSender sender, int level) {
|
||||
StringBuilder prefixBuilder = new StringBuilder();
|
||||
for (int i = 0; i < level; i++) {
|
||||
prefixBuilder.append(" ");
|
||||
@@ -78,31 +81,31 @@ public class NBTCommand extends ParentCommand {
|
||||
NBTType type = compound.getType(key);
|
||||
switch (type) {
|
||||
case NBTTagByte: {
|
||||
sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getByte(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getByte(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagShort: {
|
||||
sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getShort(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getShort(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagInt: {
|
||||
sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getInteger(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getInteger(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagLong: {
|
||||
sender.sendMessage(String.format("%s- %s:%d §e§l[%s]", space, key, compound.getLong(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%d §e§l[%s]", space, key, compound.getLong(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagFloat: {
|
||||
sender.sendMessage(String.format("%s- %s:%f §e§l[%s]", space, key, compound.getFloat(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%f §e§l[%s]", space, key, compound.getFloat(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagDouble: {
|
||||
sender.sendMessage(String.format("%s- %s:%f §e§l[%s]", space, key, compound.getDouble(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%f §e§l[%s]", space, key, compound.getDouble(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagString: {
|
||||
sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, compound.getString(key), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, compound.getString(key), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagCompound: {
|
||||
@@ -112,20 +115,20 @@ public class NBTCommand extends ParentCommand {
|
||||
}
|
||||
case NBTTagByteArray: {
|
||||
byte[] array = compound.getByteArray(key);
|
||||
sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagIntArray: {
|
||||
int[] array = compound.getIntArray(key);
|
||||
sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type)));
|
||||
if (array != null && array.length == 4) {
|
||||
sender.sendMessage(String.format("%s- %s:%s §e§l[uuid]", space, key, compound.getUUID(key)));
|
||||
sender.sendMessage(String.format("%s- %s=%s §e§l[uuid]", space, key, compound.getUUID(key)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NBTTagLongArray: {
|
||||
long[] array = compound.getLongArray(key);
|
||||
sender.sendMessage(String.format("%s- %s:%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type)));
|
||||
sender.sendMessage(String.format("%s- %s=%s §e§l[%s]", space, key, Arrays.toString(array), NBT_TYPE_NAME.get(type)));
|
||||
break;
|
||||
}
|
||||
case NBTTagList: {
|
||||
@@ -137,7 +140,7 @@ public class NBTCommand extends ParentCommand {
|
||||
String listSpace = space + " ";
|
||||
switch (listType) {
|
||||
case NBTTagString: {
|
||||
NBTList<String> list = compound.getStringList(key);
|
||||
ReadWriteNBTList<String> list = compound.getStringList(key);
|
||||
for (String string : list) {
|
||||
sender.sendMessage(String.format("%s- %s", listSpace, string));
|
||||
}
|
||||
@@ -145,7 +148,7 @@ public class NBTCommand extends ParentCommand {
|
||||
}
|
||||
case NBTTagIntArray: {
|
||||
boolean all4Length = true;
|
||||
NBTList<int[]> list = compound.getIntArrayList(key);
|
||||
ReadWriteNBTList<int[]> list = compound.getIntArrayList(key);
|
||||
for (int[] intArray : list) {
|
||||
if (intArray.length != 4) {
|
||||
all4Length = false;
|
||||
@@ -153,7 +156,7 @@ public class NBTCommand extends ParentCommand {
|
||||
}
|
||||
}
|
||||
if (all4Length) {
|
||||
NBTList<UUID> uuidList = compound.getUUIDList(key);
|
||||
ReadWriteNBTList<UUID> uuidList = compound.getUUIDList(key);
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
int[] intArray = list.get(i);
|
||||
UUID uuid = uuidList.get(i);
|
||||
@@ -169,37 +172,37 @@ public class NBTCommand extends ParentCommand {
|
||||
break;
|
||||
}
|
||||
case NBTTagInt: {
|
||||
NBTList<Integer> list = compound.getIntegerList(key);
|
||||
ReadWriteNBTList<Integer> list = compound.getIntegerList(key);
|
||||
for (Integer value : list) {
|
||||
sender.sendMessage(String.format("%s- %d", listSpace, value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NBTTagLong: {
|
||||
NBTList<Long> list = compound.getLongList(key);
|
||||
ReadWriteNBTList<Long> list = compound.getLongList(key);
|
||||
for (Long value : list) {
|
||||
sender.sendMessage(String.format("%s- %d", listSpace, value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NBTTagFloat: {
|
||||
NBTList<Float> list = compound.getFloatList(key);
|
||||
ReadWriteNBTList<Float> list = compound.getFloatList(key);
|
||||
for (Float value : list) {
|
||||
sender.sendMessage(String.format("%s- %f", listSpace, value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NBTTagDouble: {
|
||||
NBTList<Double> list = compound.getDoubleList(key);
|
||||
ReadWriteNBTList<Double> list = compound.getDoubleList(key);
|
||||
for (Double value : list) {
|
||||
sender.sendMessage(String.format("%s- %f", listSpace, value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NBTTagCompound: {
|
||||
NBTCompoundList compoundList = compound.getCompoundList(key);
|
||||
ReadWriteNBTCompoundList compoundList = compound.getCompoundList(key);
|
||||
for (int i = 0; i < compoundList.size(); i++) {
|
||||
NBTListCompound listCompound = compoundList.get(i);
|
||||
ReadWriteNBT listCompound = compoundList.get(i);
|
||||
sendNBTCompound(listCompound, sender, level + 1);
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Getter
|
||||
public enum CoreMessage {
|
||||
@@ -70,7 +71,6 @@ public enum CoreMessage {
|
||||
this.message = new DisplayMessage().setMessage(message);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CallToPrintStackTrace")
|
||||
public static void init(@NotNull Plugin plugin) {
|
||||
File dataFolder = plugin.getDataFolder();
|
||||
if (dataFolder.mkdirs()) {
|
||||
@@ -82,8 +82,7 @@ public enum CoreMessage {
|
||||
try {
|
||||
config.load(file);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("加载消息配置文件时出现了一个异常:");
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().log(Level.WARNING, "加载消息配置文件时出现了一个异常:", e);
|
||||
}
|
||||
}
|
||||
for (CoreMessage value : values()) {
|
||||
@@ -96,15 +95,13 @@ public enum CoreMessage {
|
||||
try {
|
||||
value.message = CoreBukkitUtils.loadDisplayMessage(section);
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("加载消息设置 " + value.name() + " 时遇到了一个异常: ");
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().log(Level.WARNING, "加载消息设置 " + value.name() + " 时遇到了一个异常: ", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
config.save(file);
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().warning("保存消息配置文件时出现了一个异常:");
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().log(Level.WARNING, "保存消息配置文件时出现了一个异常:", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ public class EconomyAPI {
|
||||
* @return true代表安装了,false代表未安装
|
||||
*/
|
||||
public static boolean isSetupEconomy() {
|
||||
return VaultAPI.isSetupVault() && VaultAPI.getEconomy() != null;
|
||||
return VaultAPI.isVaultEnabled() && VaultAPI.getEconomy() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.hamster3.mc.plugin.core.bukkit.hook;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
|
||||
import lombok.Getter;
|
||||
import org.black_ixx.playerpoints.PlayerPoints;
|
||||
import org.black_ixx.playerpoints.PlayerPointsAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -14,6 +15,7 @@ import java.util.UUID;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PointAPI {
|
||||
@Getter
|
||||
private static PlayerPointsAPI playerPointsAPI;
|
||||
|
||||
private PointAPI() {
|
||||
@@ -25,20 +27,10 @@ public class PointAPI {
|
||||
public static void reloadPlayerPointAPIHook() {
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin("PlayerPoints");
|
||||
if (plugin == null) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning("未检测到 PlayerPointAPI 插件");
|
||||
return;
|
||||
}
|
||||
playerPointsAPI = ((PlayerPoints) plugin).getAPI();
|
||||
HamsterCorePlugin.getInstance().getLogger().info("PlayerPointAPI 挂接成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 PlayerPointsAPI 实例
|
||||
*
|
||||
* @return PlayerPointsAPI 实例
|
||||
*/
|
||||
public static PlayerPointsAPI getPlayerPointsAPI() {
|
||||
return playerPointsAPI;
|
||||
HamsterCorePlugin.getSimpleLogger().info("已挂接 PlayerPointAPI");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,22 +1,27 @@
|
||||
package cn.hamster3.mc.plugin.core.bukkit.hook;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.bukkit.HamsterCorePlugin;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.util.BukkitSimpleLogger;
|
||||
import lombok.Getter;
|
||||
import net.milkbowl.vault.chat.Chat;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Vault API
|
||||
*/
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
public class VaultAPI {
|
||||
@Getter
|
||||
private static boolean vaultEnabled;
|
||||
@Getter
|
||||
private static Chat chat;
|
||||
@Getter
|
||||
private static Economy economy;
|
||||
@Getter
|
||||
private static Permission permission;
|
||||
|
||||
private VaultAPI() {
|
||||
@@ -27,74 +32,27 @@ public class VaultAPI {
|
||||
economy = null;
|
||||
permission = null;
|
||||
vaultEnabled = Bukkit.getPluginManager().isPluginEnabled("Vault");
|
||||
Logger logger = HamsterCorePlugin.getInstance().getLogger();
|
||||
BukkitSimpleLogger logger = HamsterCorePlugin.getSimpleLogger();
|
||||
if (!vaultEnabled) {
|
||||
logger.warning("未检测到 Vault 插件");
|
||||
return;
|
||||
}
|
||||
logger.info("已连接 Vault");
|
||||
|
||||
logger.info("检测到服务器已安装 Vault 插件");
|
||||
RegisteredServiceProvider<Chat> chatProvider = Bukkit.getServer().getServicesManager().getRegistration(Chat.class);
|
||||
|
||||
if (chatProvider != null) {
|
||||
chat = chatProvider.getProvider();
|
||||
logger.info("聊天系统挂接成功");
|
||||
} else {
|
||||
logger.warning("未检测到聊天系统");
|
||||
}
|
||||
|
||||
RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServer().getServicesManager().getRegistration(Economy.class);
|
||||
if (economyProvider != null) {
|
||||
economy = economyProvider.getProvider();
|
||||
logger.info("经济系统挂接成功");
|
||||
} else {
|
||||
logger.warning("未检测到经济系统");
|
||||
}
|
||||
|
||||
RegisteredServiceProvider<Permission> permissionProvider = Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
|
||||
if (permissionProvider != null) {
|
||||
permission = permissionProvider.getProvider();
|
||||
logger.info("权限系统挂接成功");
|
||||
} else {
|
||||
logger.warning("未检测到权限插件");
|
||||
}
|
||||
logger.info("已完成 VaultAPI 挂载");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回服务器是否安装了 Vault 插件
|
||||
*
|
||||
* @return true 代表服务器已安装
|
||||
*/
|
||||
public static boolean isSetupVault() {
|
||||
return vaultEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 Vault 的 Chat 前置系统
|
||||
*
|
||||
* @return Chat 系统
|
||||
*/
|
||||
public static Chat getChat() {
|
||||
return chat;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 Vault 的 Economy 前置系统
|
||||
*
|
||||
* @return Economy 系统
|
||||
*/
|
||||
public static Economy getEconomy() {
|
||||
return economy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 Vault 的 Permission 前置系统
|
||||
*
|
||||
* @return Permission 系统
|
||||
*/
|
||||
public static Permission getPermission() {
|
||||
return permission;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -188,8 +188,8 @@ public class ButtonGroup {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ButtonGroup{" +
|
||||
"name='" + name + '\'' +
|
||||
", buttonNameMap=" + buttonNameMap +
|
||||
'}';
|
||||
"name='" + name + '\'' +
|
||||
", buttonNameMap=" + buttonNameMap +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@@ -98,8 +98,7 @@ public class PageConfig implements InventoryHolder {
|
||||
try {
|
||||
buttonSounds.put(key, Sound.valueOf(soundName));
|
||||
} catch (Exception e) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning("初始化 PageConfig 时遇到了一个异常:");
|
||||
e.printStackTrace();
|
||||
HamsterCorePlugin.getSimpleLogger().error(e, "初始化 PageConfig 时遇到了一个异常: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,10 +196,10 @@ public class PageConfig implements InventoryHolder {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PageConfig{" +
|
||||
", title='" + title + '\'' +
|
||||
", graphic=" + graphic +
|
||||
", buttonMap=" + buttons +
|
||||
", buttonGroups=" + buttonGroups +
|
||||
'}';
|
||||
", title='" + title + '\'' +
|
||||
", graphic=" + graphic +
|
||||
", buttonMap=" + buttons +
|
||||
", buttonGroups=" + buttonGroups +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@@ -39,8 +39,7 @@ public class PageListener implements Listener {
|
||||
try {
|
||||
pageHandler.onClick(event);
|
||||
} catch (Exception e) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onClick(event) 时遇到了一个异常: ", pageHandler.getClass().getName()));
|
||||
e.printStackTrace();
|
||||
HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onClick(event) 时遇到了一个异常: ", pageHandler.getClass().getName());
|
||||
}
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
@@ -55,31 +54,29 @@ public class PageListener implements Listener {
|
||||
try {
|
||||
pageHandler.onClickInside(event);
|
||||
} catch (Exception e) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onClickInside(event) 时遇到了一个异常: ", pageHandler.getClass().getName()));
|
||||
e.printStackTrace();
|
||||
HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onClickInside(event) 时遇到了一个异常: ", pageHandler.getClass().getName());
|
||||
}
|
||||
try {
|
||||
pageHandler.onClickInside(event.getClick(), event.getAction(), index);
|
||||
} catch (Exception e) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning(String.format(
|
||||
HamsterCorePlugin.getSimpleLogger().warn(e,
|
||||
"执行 %s 的 onClickInside(%s, %s, %d) 时遇到了一个异常: ",
|
||||
pageHandler.getClass().getName(),
|
||||
event.getClick().name(),
|
||||
event.getAction().name(),
|
||||
index
|
||||
));
|
||||
e.printStackTrace();
|
||||
);
|
||||
}
|
||||
try {
|
||||
pageHandler.onPlayButtonSound(event.getClick(), event.getAction(), index);
|
||||
} catch (Exception e) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning(String.format(
|
||||
HamsterCorePlugin.getSimpleLogger().warn(e,
|
||||
"执行 %s 的 onPlayButtonSound(%s, %s, %d) 时遇到了一个异常: ",
|
||||
pageHandler.getClass().getName(),
|
||||
event.getClick().name(),
|
||||
event.getAction().name(),
|
||||
index
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +90,7 @@ public class PageListener implements Listener {
|
||||
try {
|
||||
pageHandler.onDrag(event);
|
||||
} catch (Exception e) {
|
||||
HamsterCorePlugin.getInstance().getLogger().warning(String.format("执行 %s 的 onDrag(event) 时遇到了一个异常: ", pageHandler.getClass().getName()));
|
||||
e.printStackTrace();
|
||||
HamsterCorePlugin.getSimpleLogger().warn(e, "执行 %s 的 onDrag(event) 时遇到了一个异常: ", pageHandler.getClass().getName());
|
||||
}
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package cn.hamster3.mc.plugin.core.bukkit.util;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.common.util.SimpleLogger;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
public class BukkitSimpleLogger extends SimpleLogger {
|
||||
@NotNull
|
||||
private final Plugin plugin;
|
||||
@NotNull
|
||||
private final Logger logger;
|
||||
|
||||
public BukkitSimpleLogger(@NotNull Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull String msg) {
|
||||
logger.log(level, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable) {
|
||||
logger.log(level, "", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg) {
|
||||
logger.log(level, msg, throwable);
|
||||
}
|
||||
}
|
@@ -3,10 +3,10 @@ package cn.hamster3.mc.plugin.core.bukkit.util;
|
||||
import cn.hamster3.mc.plugin.core.bukkit.listener.CallbackListener;
|
||||
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
|
||||
import com.google.gson.JsonObject;
|
||||
import de.tr7zw.changeme.nbtapi.NBTContainer;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -241,23 +241,45 @@ public final class CoreBukkitUtils {
|
||||
@NotNull
|
||||
public static DisplayMessage loadDisplayMessage(@NotNull ConfigurationSection config) {
|
||||
DisplayMessage displayMessage = new DisplayMessage();
|
||||
String message = config.getString("message");
|
||||
if (message != null) {
|
||||
displayMessage.setMessage(LegacyComponentSerializer.legacySection().deserialize(message));
|
||||
String miniMessage = config.getString("mini-message");
|
||||
if (miniMessage != null) {
|
||||
displayMessage.setMessage(MiniMessage.miniMessage().deserialize(miniMessage));
|
||||
} else {
|
||||
String message = config.getString("message");
|
||||
if (message != null) {
|
||||
displayMessage.setMessage(LegacyComponentSerializer.legacySection().deserialize(message));
|
||||
}
|
||||
}
|
||||
String actionbar = config.getString("actionbar");
|
||||
if (actionbar != null) {
|
||||
displayMessage.setActionbar(LegacyComponentSerializer.legacySection().deserialize(actionbar));
|
||||
String miniActionbar = config.getString("mini-actionbar");
|
||||
if (miniActionbar != null) {
|
||||
displayMessage.setActionbar(MiniMessage.miniMessage().deserialize(miniActionbar));
|
||||
} else {
|
||||
String actionbar = config.getString("actionbar");
|
||||
if (actionbar != null) {
|
||||
displayMessage.setActionbar(LegacyComponentSerializer.legacySection().deserialize(actionbar));
|
||||
}
|
||||
}
|
||||
String title = config.getString("title");
|
||||
String subtitle = config.getString("subtitle");
|
||||
if (title != null || subtitle != null) {
|
||||
String miniTitle = config.getString("mini-title");
|
||||
String miniSubtitle = config.getString("mini-subtitle");
|
||||
if (miniTitle != null || miniSubtitle != null) {
|
||||
displayMessage.setTitle(
|
||||
title, subtitle,
|
||||
MiniMessage.miniMessage().deserialize(miniTitle == null ? "" : miniTitle),
|
||||
MiniMessage.miniMessage().deserialize(miniSubtitle == null ? "" : miniSubtitle),
|
||||
config.getInt("fade-in", 10),
|
||||
config.getInt("stay", 70),
|
||||
config.getInt("fade-out", 20)
|
||||
);
|
||||
} else {
|
||||
String title = config.getString("title");
|
||||
String subtitle = config.getString("subtitle");
|
||||
if (title != null || subtitle != null) {
|
||||
displayMessage.setTitle(
|
||||
title, subtitle,
|
||||
config.getInt("fade-in", 10),
|
||||
config.getInt("stay", 70),
|
||||
config.getInt("fade-out", 20)
|
||||
);
|
||||
}
|
||||
}
|
||||
String sound = config.getString("sound");
|
||||
if (sound != null) {
|
||||
@@ -330,7 +352,7 @@ public final class CoreBukkitUtils {
|
||||
*/
|
||||
@NotNull
|
||||
public static String serializeItemStack(@NotNull ItemStack stack) {
|
||||
return NBTItem.convertItemtoNBT(stack).toString();
|
||||
return NBT.itemStackToNBT(stack).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,7 +363,7 @@ public final class CoreBukkitUtils {
|
||||
*/
|
||||
@Nullable
|
||||
public static ItemStack deserializeItemStack(@NotNull String string) {
|
||||
return NBTItem.convertNBTtoItem(new NBTContainer(string));
|
||||
return NBT.itemStackFromNBT(NBT.parseNBT(string));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -7,18 +7,18 @@ import org.jetbrains.annotations.NotNull;
|
||||
@SuppressWarnings("unused")
|
||||
public class MinecraftVersion {
|
||||
@Getter
|
||||
public static final int Version1;
|
||||
public static final int version1;
|
||||
@Getter
|
||||
public static final int Version2;
|
||||
public static final int version2;
|
||||
@Getter
|
||||
public static final int Version3;
|
||||
public static final int version3;
|
||||
|
||||
static {
|
||||
String version = getMCVersion();
|
||||
String[] split = version.split("\\.");
|
||||
Version1 = Integer.parseInt(split[0]);
|
||||
Version2 = Integer.parseInt(split[1]);
|
||||
Version3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0;
|
||||
version1 = Integer.parseInt(split[0]);
|
||||
version2 = Integer.parseInt(split[1]);
|
||||
version3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,18 +35,18 @@ public class MinecraftVersion {
|
||||
*/
|
||||
public static int compareTo(@NotNull String version) {
|
||||
String[] split = version.split("\\.");
|
||||
int version1 = Integer.parseInt(split[0]);
|
||||
int version2 = Integer.parseInt(split[1]);
|
||||
int version3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0;
|
||||
int compare = Integer.compare(Version1, version1);
|
||||
int compareVersion1 = Integer.parseInt(split[0]);
|
||||
int compareVersion2 = Integer.parseInt(split[1]);
|
||||
int compareVersion3 = split.length >= 3 ? Integer.parseInt(split[2]) : 0;
|
||||
int compare = Integer.compare(compareVersion1, MinecraftVersion.version1);
|
||||
if (compare != 0) {
|
||||
return compare;
|
||||
}
|
||||
compare = Integer.compare(Version2, version2);
|
||||
compare = Integer.compare(compareVersion2, MinecraftVersion.version2);
|
||||
if (compare != 0) {
|
||||
return compare;
|
||||
}
|
||||
return Integer.compare(Version3, version3);
|
||||
return Integer.compare(compareVersion3, MinecraftVersion.version3);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -61,8 +61,10 @@ public class MinecraftVersion {
|
||||
|
||||
@NotNull
|
||||
public static Class<?> getNMSClass(@NotNull String className) throws ClassNotFoundException {
|
||||
if (Version2 >= 17) {
|
||||
return Class.forName("net.minecraft.server." + className);
|
||||
if (version1 >= 1) {
|
||||
if (version2 >= 17) {
|
||||
return Class.forName("net.minecraft.server." + className);
|
||||
}
|
||||
}
|
||||
String nmsVersion = getNMSVersion();
|
||||
return Class.forName("net.minecraft.server." + nmsVersion + "." + className);
|
||||
@@ -70,9 +72,8 @@ public class MinecraftVersion {
|
||||
|
||||
@NotNull
|
||||
public static Class<?> getNMSClassSilent(@NotNull String className) {
|
||||
String nmsVersion = getNMSVersion();
|
||||
try {
|
||||
return Class.forName("net.minecraft.server." + nmsVersion + "." + className);
|
||||
return getNMSClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -80,15 +81,22 @@ public class MinecraftVersion {
|
||||
|
||||
@NotNull
|
||||
public static Class<?> getCraftBukkitClass(@NotNull String className) throws ClassNotFoundException {
|
||||
if (version1 >= 1) {
|
||||
if (version2 >= 21) {
|
||||
return Class.forName("org.bukkit.craftbukkit." + className);
|
||||
}
|
||||
if (version2 == 20 && version3 >= 6) {
|
||||
return Class.forName("org.bukkit.craftbukkit." + className);
|
||||
}
|
||||
}
|
||||
String nmsVersion = getNMSVersion();
|
||||
return Class.forName("org.bukkit.craftbukkit." + nmsVersion + "." + className);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Class<?> getCraftBukkitClassSilent(@NotNull String className) {
|
||||
String nmsVersion = getNMSVersion();
|
||||
try {
|
||||
return Class.forName("org.bukkit.craftbukkit." + nmsVersion + "." + className);
|
||||
return getCraftBukkitClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@@ -1,3 +1,6 @@
|
||||
# 是否启用 redis 连接池功能
|
||||
enable-redis: false
|
||||
|
||||
# redis 连接配置
|
||||
# 完整格式如下:
|
||||
# redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值
|
||||
@@ -8,18 +11,16 @@
|
||||
# 若不设置数据库,则默认使用 0
|
||||
redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
||||
|
||||
# 是否启用数据库连接池功能
|
||||
enable-database: false
|
||||
|
||||
# 数据库连接池配置
|
||||
datasource:
|
||||
# 数据库链接驱动地址
|
||||
# 除非你知道自己在做什么,否则不建议更改该项
|
||||
# 旧版服务端(低于1.13)请使用:com.mysql.jdbc.Driver
|
||||
# 数据库链接驱动地址,旧版服务端(低于1.13)请使用:com.mysql.jdbc.Driver
|
||||
driver: "com.mysql.cj.jdbc.Driver"
|
||||
# 数据库链接填写格式:
|
||||
# MySQL数据库链接填写格式:
|
||||
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
|
||||
# 除非你知道自己在做什么,否则不建议随意更改参数
|
||||
url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
|
||||
# 如果你不需要做多端跨服,那么请使用 sqlite 作本地数据库
|
||||
# driver: "org.sqlite.JDBC"
|
||||
# url: "jdbc:sqlite:./plugins/HamsterCore/database.db"
|
||||
# 用户名
|
||||
username: "root"
|
||||
# 密码
|
||||
|
@@ -4,8 +4,14 @@ version: ${version}
|
||||
api-version: 1.13
|
||||
|
||||
author: MiniDay
|
||||
description: ${description}
|
||||
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
|
||||
|
||||
load: STARTUP
|
||||
|
||||
|
@@ -1,6 +0,0 @@
|
||||
version: ${version}
|
||||
CHECK_TYPE: GITEA_RELEASES
|
||||
GIT_BASE_URL: https://git.airgame.net
|
||||
GIT_REPO: MiniDay/hamster-core
|
||||
GIT_TOKEN: a44a69a4d1b8601bf6091403247759cd28764d5e
|
||||
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-core/
|
@@ -1,11 +1,9 @@
|
||||
@file:Suppress("VulnerableLibrariesLocal")
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
evaluationDependsOn(":core-common")
|
||||
evaluationDependsOn(":core-relocate-lettuce")
|
||||
|
||||
val shade = configurations.create("shade")
|
||||
val shadeJava8 = configurations.create("shadeJava8")
|
||||
|
||||
dependencies {
|
||||
api(project(":core-common")) { isTransitive = false }
|
||||
@@ -19,20 +17,17 @@ dependencies {
|
||||
exclude(module = "adventure-api")
|
||||
exclude(group = "org.jetbrains")
|
||||
}
|
||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||
api("redis.clients:jedis:5.1.2") {
|
||||
|
||||
implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") }
|
||||
api("redis.clients:jedis:5.1.4") {
|
||||
exclude(group = "com.google.code.gson")
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
||||
api("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
||||
|
||||
implementation("com.zaxxer:HikariCP:4.0.3") { exclude(group = "org.slf4j") }
|
||||
|
||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib
|
||||
shade("org.jetbrains.kotlin:kotlin-stdlib:1.9.23") { exclude(group = "org.jetbrains") }
|
||||
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8
|
||||
shadeJava8("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.23") { exclude(group = "org.jetbrains") }
|
||||
compileOnlyApi("io.lettuce:lettuce-core:6.7.1.RELEASE") {
|
||||
exclude(group = "org.slf4j")
|
||||
exclude(group = "io.netty")
|
||||
}
|
||||
shade(project(":core-relocate-lettuce"))
|
||||
}
|
||||
|
||||
tasks {
|
||||
@@ -45,23 +40,9 @@ tasks {
|
||||
archiveBaseName = "HamsterCore-BungeeCord"
|
||||
}
|
||||
shadowJar {
|
||||
from(shade.map { if (it.isDirectory) it else zipTree(it) })
|
||||
dependsOn(":core-relocate-lettuce:shadowJar")
|
||||
val task = project(":core-relocate-lettuce").tasks.shadowJar.get()
|
||||
from(task.outputs.files.map { if (it.isDirectory) it else zipTree(it) })
|
||||
destinationDirectory = rootProject.layout.buildDirectory
|
||||
}
|
||||
shadowJar {
|
||||
from(shade.map { if (it.isDirectory) it else zipTree(it) })
|
||||
destinationDirectory = rootProject.layout.buildDirectory
|
||||
}
|
||||
val shadowJava8 = register<ShadowJar>("shadowJava8") {
|
||||
dependsOn(":core-common:build")
|
||||
archiveClassifier = "Java8"
|
||||
from(project.configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
|
||||
from(processResources.get().outputs)
|
||||
from(jar.get().outputs)
|
||||
from(shadeJava8.map { if (it.isDirectory) it else zipTree(it) })
|
||||
destinationDirectory = rootProject.layout.buildDirectory
|
||||
}
|
||||
build {
|
||||
dependsOn(shadowJava8)
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,15 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.bungee.api.CoreBungeeAPI;
|
||||
import cn.hamster3.mc.plugin.core.bungee.util.BungeeSimpleLogger;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
import cn.hamster3.mc.plugin.core.common.config.YamlConfig;
|
||||
import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
@@ -17,25 +19,25 @@ import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@SuppressWarnings("CallToPrintStackTrace")
|
||||
public class HamsterCorePlugin extends Plugin {
|
||||
@Getter
|
||||
private static HamsterCorePlugin instance;
|
||||
@Getter
|
||||
private static BungeeSimpleLogger simpleLogger;
|
||||
@Getter
|
||||
private BungeeAudiences audienceProvider;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
simpleLogger = new BungeeSimpleLogger(this);
|
||||
long start = System.currentTimeMillis();
|
||||
Logger logger = getLogger();
|
||||
logger.info("仓鼠核心正在初始化");
|
||||
simpleLogger.info("仓鼠核心正在初始化");
|
||||
try {
|
||||
File dataFolder = getDataFolder();
|
||||
if (dataFolder.mkdir()) {
|
||||
logger.info("已生成插件存档文件夹");
|
||||
simpleLogger.info("已生成插件存档文件夹");
|
||||
}
|
||||
File configFile = new File(dataFolder, "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
@@ -46,57 +48,63 @@ public class HamsterCorePlugin extends Plugin {
|
||||
}
|
||||
}
|
||||
CoreBungeeAPI.init(configFile);
|
||||
logger.info("已初始化 CoreAPI");
|
||||
simpleLogger.info("已初始化 CoreAPI");
|
||||
} catch (Exception e) {
|
||||
logger.warning("初始化 CoreAPI 出错");
|
||||
e.printStackTrace();
|
||||
simpleLogger.error(e, "初始化 CoreAPI 出错");
|
||||
}
|
||||
long time = System.currentTimeMillis() - start;
|
||||
logger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms");
|
||||
simpleLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
long start = System.currentTimeMillis();
|
||||
Logger logger = getLogger();
|
||||
logger.info("仓鼠核心正在启动");
|
||||
simpleLogger.info("仓鼠核心正在启动");
|
||||
audienceProvider = BungeeAudiences.create(this);
|
||||
logger.info("已创建 AudienceProvider");
|
||||
simpleLogger.info("已创建 AudienceProvider");
|
||||
CoreAPI.getInstance().getExecutorService().submit(this::checkUpdate);
|
||||
long time = System.currentTimeMillis() - start;
|
||||
logger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||
|
||||
CoreAPI.getInstance().getExecutorService().submit(() -> {
|
||||
for (Plugin plugin : ProxyServer.getInstance().getPluginManager().getPlugins()) {
|
||||
try (InputStream stream = plugin.getResourceAsStream("update.yml")) {
|
||||
if (stream == null) {
|
||||
continue;
|
||||
}
|
||||
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||
YamlConfig config = YamlConfig.load(reader);
|
||||
UpdateCheckUtils.showUpdate(
|
||||
plugin.getDescription().getName(), config,
|
||||
(s) -> ProxyServer.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(s))
|
||||
);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
simpleLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
long start = System.currentTimeMillis();
|
||||
Logger logger = getLogger();
|
||||
CoreAPI.getInstance().getJedisPool().close();
|
||||
logger.info("已关闭 Redis 连接池");
|
||||
CoreAPI.getInstance().getHikariDataSource().close();
|
||||
logger.info("已关闭数据库连接池");
|
||||
audienceProvider.close();
|
||||
simpleLogger.info("已关闭 AudienceProvider.");
|
||||
if (CoreAPI.getInstance().isEnableRedis()) {
|
||||
CoreAPI.getInstance().getJedisPool().close();
|
||||
CoreAPI.getInstance().getRedisClient().close();
|
||||
simpleLogger.info("已关闭 Redis 连接池");
|
||||
}
|
||||
if (CoreAPI.getInstance().isEnableDatabase()) {
|
||||
((HikariDataSource) CoreAPI.getInstance().getDataSource()).close();
|
||||
simpleLogger.info("已关闭数据库连接池");
|
||||
}
|
||||
CoreAPI.getInstance().getExecutorService().shutdownNow();
|
||||
logger.info("已关闭 ExecutorService 线程池");
|
||||
simpleLogger.info("已关闭 ExecutorService 线程池");
|
||||
CoreAPI.getInstance().getScheduledService().shutdownNow();
|
||||
logger.info("已关闭 ScheduledExecutorService 线程池");
|
||||
simpleLogger.info("已关闭 ScheduledExecutorService 线程池");
|
||||
long time = System.currentTimeMillis() - start;
|
||||
logger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
||||
simpleLogger.info("仓鼠核心已关闭,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
private void checkUpdate() {
|
||||
for (Plugin plugin : ProxyServer.getInstance().getPluginManager().getPlugins()) {
|
||||
try (InputStream stream = plugin.getResourceAsStream("bungee.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.getDescription().getName(), section);
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee.api;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.bungee.HamsterCorePlugin;
|
||||
import cn.hamster3.mc.plugin.core.bungee.util.BungeeSimpleLogger;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
import cn.hamster3.mc.plugin.core.common.config.YamlConfig;
|
||||
@@ -15,7 +16,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class CoreBungeeAPI extends CoreAPI {
|
||||
@@ -51,8 +51,8 @@ public final class CoreBungeeAPI extends CoreAPI {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Logger getLogger() {
|
||||
return HamsterCorePlugin.getInstance().getLogger();
|
||||
public @NotNull BungeeSimpleLogger getLogger() {
|
||||
return HamsterCorePlugin.getSimpleLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,38 @@
|
||||
package cn.hamster3.mc.plugin.core.bungee.util;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.common.util.SimpleLogger;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
public class BungeeSimpleLogger extends SimpleLogger {
|
||||
@NotNull
|
||||
private final Plugin plugin;
|
||||
@NotNull
|
||||
private final Logger logger;
|
||||
|
||||
public BungeeSimpleLogger(@NotNull Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull String msg) {
|
||||
logger.log(level, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable) {
|
||||
logger.log(level, "", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg) {
|
||||
logger.log(level, msg, throwable);
|
||||
}
|
||||
}
|
@@ -3,4 +3,11 @@ main: cn.hamster3.mc.plugin.core.bungee.HamsterCorePlugin
|
||||
version: ${version}
|
||||
|
||||
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
|
||||
|
@@ -1,3 +1,6 @@
|
||||
# 是否启用 redis 连接池功能
|
||||
enable-redis: false
|
||||
|
||||
# redis 连接配置
|
||||
# 完整格式如下:
|
||||
# redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值
|
||||
@@ -8,13 +11,15 @@
|
||||
# 若不设置数据库,则默认使用 0
|
||||
redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
||||
|
||||
# 是否启用数据库连接池功能
|
||||
enable-database: false
|
||||
|
||||
# 数据库连接池配置
|
||||
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"
|
||||
@@ -24,8 +29,8 @@ datasource:
|
||||
# 推荐值:1~3
|
||||
minimum-idle: 0
|
||||
# 最大链接数
|
||||
# 推荐值:不低于5
|
||||
maximum-pool-size: 5
|
||||
# 推荐值:不低于3
|
||||
maximum-pool-size: 3
|
||||
# 保持连接池可用的间隔
|
||||
# 除非你的服务器数据库连接经常断开,否则不建议启用该选项
|
||||
# 单位:毫秒
|
||||
|
@@ -1,6 +0,0 @@
|
||||
version: ${version}
|
||||
CHECK_TYPE: GITEA_RELEASES
|
||||
GIT_BASE_URL: https://git.airgame.net
|
||||
GIT_REPO: MiniDay/hamster-core
|
||||
GIT_TOKEN: a44a69a4d1b8601bf6091403247759cd28764d5e
|
||||
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-core/
|
@@ -12,16 +12,23 @@ dependencies {
|
||||
exclude(group = "org.jetbrains")
|
||||
exclude(group = "com.google.code.gson")
|
||||
}
|
||||
|
||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||
compileOnlyApi("redis.clients:jedis:5.1.2") {
|
||||
compileOnlyApi("net.kyori:adventure-text-serializer-legacy:4.13.1") {
|
||||
exclude(group = "org.jetbrains")
|
||||
exclude(group = "com.google.code.gson")
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
compileOnlyApi("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
||||
|
||||
// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
|
||||
compileOnly("com.zaxxer:HikariCP:4.0.3") { isTransitive = false }
|
||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||
compileOnlyApi("redis.clients:jedis:5.1.4") {
|
||||
exclude(group = "com.google.code.gson")
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
// https://mvnrepository.com/artifact/io.lettuce/lettuce-core
|
||||
compileOnlyApi("io.lettuce:lettuce-core:6.7.1.RELEASE") {
|
||||
exclude(group = "io.netty")
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
@@ -3,11 +3,16 @@ package cn.hamster3.mc.plugin.core.common.api;
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
import cn.hamster3.mc.plugin.core.common.thread.NamedThreadFactory;
|
||||
import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
|
||||
import cn.hamster3.mc.plugin.core.common.util.SimpleLogger;
|
||||
import com.google.gson.Gson;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.platform.AudienceProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@@ -16,64 +21,85 @@ import java.sql.SQLException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class CoreAPI {
|
||||
@Getter
|
||||
protected static CoreAPI instance;
|
||||
/**
|
||||
* Redis 连接池
|
||||
*/
|
||||
@Getter
|
||||
@NotNull
|
||||
private final JedisPool jedisPool;
|
||||
/**
|
||||
* HamsterCore 公用数据库连接池
|
||||
*/
|
||||
@Getter
|
||||
@NotNull
|
||||
private final HikariDataSource hikariDataSource;
|
||||
private final boolean enableRedis;
|
||||
private final boolean enableDatabase;
|
||||
/**
|
||||
* 异步线程池
|
||||
*/
|
||||
@Getter
|
||||
@NotNull
|
||||
private final ExecutorService executorService;
|
||||
/**
|
||||
* 调度器线程池
|
||||
*/
|
||||
@Getter
|
||||
@NotNull
|
||||
private final ScheduledExecutorService scheduledService;
|
||||
/**
|
||||
* 公用 Redis 连接池
|
||||
*/
|
||||
@Nullable
|
||||
private JedisPool jedisPool;
|
||||
/**
|
||||
* Lettuce Redis 连接池
|
||||
*/
|
||||
@Nullable
|
||||
private RedisClient redisClient;
|
||||
/**
|
||||
* 公用数据库连接池
|
||||
*/
|
||||
@Nullable
|
||||
private HikariDataSource hikariDataSource;
|
||||
|
||||
public CoreAPI(@NotNull ConfigSection config) {
|
||||
SimpleLogger logger = getLogger();
|
||||
executorService = Executors.newCachedThreadPool(new NamedThreadFactory("HamsterCore - Executor"));
|
||||
scheduledService = Executors.newScheduledThreadPool(1, new NamedThreadFactory("HamsterCore - Scheduler"));
|
||||
logger.info("已创建线程池");
|
||||
|
||||
getLogger().info("正在创建 Redis 连接池");
|
||||
jedisPool = new JedisPool(config.getString("redis-url"));
|
||||
getLogger().info("Redis 连接池创建完成");
|
||||
|
||||
ConfigSection datasourceConfig = config.getSection("datasource");
|
||||
if (datasourceConfig == null) {
|
||||
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
|
||||
enableRedis = config.getBoolean("enable-redis", true);
|
||||
if (enableRedis) {
|
||||
logger.info("正在创建 Redis 连接池");
|
||||
jedisPool = new JedisPool(config.getString("redis-url"));
|
||||
redisClient = RedisClient.create(config.getString("redis-url"));
|
||||
logger.info("Redis 连接池创建完成");
|
||||
} else {
|
||||
logger.info("未启用 Redis 功能");
|
||||
}
|
||||
|
||||
enableDatabase = config.getBoolean("enable-database", true);
|
||||
if (enableDatabase) {
|
||||
ConfigSection datasourceConfig = config.getSection("datasource");
|
||||
if (datasourceConfig == null) {
|
||||
throw new IllegalArgumentException("配置文件中未找到 datasource 节点");
|
||||
}
|
||||
logger.info("正在创建数据库连接池");
|
||||
hikariDataSource = (HikariDataSource) CoreUtils.getDataSource(datasourceConfig);
|
||||
logger.info("数据库连接池创建完成");
|
||||
} else {
|
||||
logger.info("未启用数据库功能");
|
||||
}
|
||||
getLogger().info("正在创建数据库连接池");
|
||||
hikariDataSource = (HikariDataSource) CoreUtils.getDataSource(datasourceConfig);
|
||||
getLogger().info("数据库连接池创建完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HamsterCore 公用数据库连接池
|
||||
* 获取公用数据库连接池
|
||||
*
|
||||
* @return 公用数据库连接池
|
||||
*/
|
||||
@NotNull
|
||||
public DataSource getDataSource() {
|
||||
return hikariDataSource;
|
||||
if (hikariDataSource != null) {
|
||||
return hikariDataSource;
|
||||
}
|
||||
throw new IllegalStateException("仓鼠核心未启用数据库功能");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 HamsterCore 公用数据库连接
|
||||
* 获取公用数据库连接
|
||||
*
|
||||
* @return 公用数据库连接
|
||||
* @throws SQLException -
|
||||
@@ -84,7 +110,33 @@ public abstract class CoreAPI {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract Logger getLogger();
|
||||
public JedisPool getJedisPool() {
|
||||
if (jedisPool != null) {
|
||||
return jedisPool;
|
||||
}
|
||||
throw new IllegalStateException("仓鼠核心未启用 Redis 功能");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RedisClient getRedisClient() {
|
||||
if (redisClient != null) {
|
||||
return redisClient;
|
||||
}
|
||||
throw new IllegalStateException("仓鼠核心未启用 Redis 功能");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StatefulRedisConnection<String, String> getRedisConnect() {
|
||||
return getRedisClient().connect();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StatefulRedisPubSubConnection<String, String> getRedisPubSub() {
|
||||
return getRedisClient().connectPubSub();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public abstract SimpleLogger getLogger();
|
||||
|
||||
/**
|
||||
* @return GSON 工具
|
||||
|
@@ -4,10 +4,9 @@ import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
@SuppressWarnings({"unused", "unchecked"})
|
||||
@Getter
|
||||
@@ -27,6 +26,15 @@ public class ConfigSection {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public Set<String> getKeys() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object get(@NotNull String key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ConfigSection getSection(@NotNull String key) {
|
||||
Object o = map.get(key);
|
||||
@@ -65,16 +73,6 @@ public class ConfigSection {
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
public List<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) {
|
||||
@@ -155,6 +153,45 @@ public class ConfigSection {
|
||||
return Long.parseLong(string);
|
||||
}
|
||||
|
||||
public <T> List<T> getList(@NotNull String key, Function<Object, T> function) {
|
||||
ArrayList<T> list = new ArrayList<>();
|
||||
Object object = map.get(key);
|
||||
if (object instanceof List) {
|
||||
List<?> mapList = (List<?>) object;
|
||||
for (Object o : mapList) {
|
||||
T result = function.apply(o);
|
||||
list.add(result);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<String> getStringList(@NotNull String key) {
|
||||
return getList(key, Object::toString);
|
||||
}
|
||||
|
||||
public List<Integer> getIntegerList(@NotNull String key) {
|
||||
return getList(key, o -> Integer.parseInt(o.toString()));
|
||||
}
|
||||
|
||||
public <T> List<T> toList(BiFunction<ConfigSection, String, T> function) {
|
||||
ArrayList<T> list = new ArrayList<>();
|
||||
for (String key : getKeys()) {
|
||||
T result = function.apply(this, key);
|
||||
list.add(result);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public <T> Map<String, T> toMap(BiFunction<ConfigSection, String, T> function) {
|
||||
HashMap<String, T> map = new HashMap<>();
|
||||
for (String key : getKeys()) {
|
||||
T result = function.apply(this, key);
|
||||
map.put(key, result);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void set(@NotNull String key, @Nullable Object value) {
|
||||
if (value == null) {
|
||||
map.remove(key);
|
||||
|
@@ -5,9 +5,12 @@ import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@SuppressWarnings({"unused", "VulnerableCodeUsages"})
|
||||
@SuppressWarnings("unused")
|
||||
public class YamlConfig extends ConfigSection {
|
||||
public static final Yaml YAML_LOADER = new Yaml();
|
||||
|
||||
@@ -19,11 +22,56 @@ public class YamlConfig extends ConfigSection {
|
||||
super(map);
|
||||
}
|
||||
|
||||
public static List<YamlConfig> loadFolder(@NotNull File file) throws IOException {
|
||||
if (file.isDirectory()) {
|
||||
ArrayList<YamlConfig> list = new ArrayList<>();
|
||||
for (File subFile : Objects.requireNonNull(file.listFiles())) {
|
||||
list.addAll(loadFolder(subFile));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
if (file.isFile() && file.getName().endsWith(".yml")) {
|
||||
return Collections.singletonList(load(file));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static List<YamlConfig> loadFolder(@NotNull File file, @NotNull Consumer<Exception> exceptionHandler) {
|
||||
if (file.isDirectory()) {
|
||||
ArrayList<YamlConfig> list = new ArrayList<>();
|
||||
for (File subFile : Objects.requireNonNull(file.listFiles())) {
|
||||
list.addAll(loadFolder(subFile, exceptionHandler));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
if (file.isFile() && file.getName().endsWith(".yml")) {
|
||||
try {
|
||||
YamlConfig load = load(file);
|
||||
return Collections.singletonList(load);
|
||||
} catch (IOException e) {
|
||||
exceptionHandler.accept(e);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static YamlConfig load(@NotNull Path path) {
|
||||
try {
|
||||
return load(Files.newInputStream(path));
|
||||
} catch (IOException e) {
|
||||
return new YamlConfig();
|
||||
}
|
||||
}
|
||||
|
||||
public static YamlConfig load(@NotNull File file) throws IOException {
|
||||
try (FileInputStream stream = new FileInputStream(file)) {
|
||||
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||
return load(reader);
|
||||
}
|
||||
return load(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public static YamlConfig load(@NotNull InputStream stream) throws IOException {
|
||||
try (InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {
|
||||
return load(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +80,25 @@ public class YamlConfig extends ConfigSection {
|
||||
return new YamlConfig(load);
|
||||
}
|
||||
|
||||
public void save(@NotNull File file) throws IOException {
|
||||
try (FileOutputStream stream = new FileOutputStream(file)) {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) {
|
||||
YAML_LOADER.dump(map, writer);
|
||||
}
|
||||
public void save(@NotNull Path path) throws IOException {
|
||||
try (OutputStream stream = Files.newOutputStream(path)) {
|
||||
save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(@NotNull File file) throws IOException {
|
||||
try (FileOutputStream stream = new FileOutputStream(file)) {
|
||||
save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(@NotNull OutputStream stream) throws IOException {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8)) {
|
||||
save(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(@NotNull Writer writer) {
|
||||
YAML_LOADER.dump(map, writer);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package cn.hamster3.mc.plugin.core.common.util;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
import cn.hamster3.mc.plugin.core.common.config.YamlConfig;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
@@ -8,42 +9,42 @@ import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Duration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class CoreUtils {
|
||||
private CoreUtils() {
|
||||
}
|
||||
|
||||
public static void zipCompressionFolder(@NotNull File folder, @NotNull File zipFile) throws IOException {
|
||||
try (ZipOutputStream stream = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) {
|
||||
putFileToZipStream(stream, "", folder);
|
||||
@NotNull
|
||||
public static DataSource getDataSource(@NotNull ConfigSection datasourceConfig) {
|
||||
HikariConfig hikariConfig = new HikariConfig();
|
||||
hikariConfig.setDriverClassName(datasourceConfig.getString("driver"));
|
||||
hikariConfig.setJdbcUrl(datasourceConfig.getString("url"));
|
||||
hikariConfig.setUsername(datasourceConfig.getString("username"));
|
||||
hikariConfig.setPassword(datasourceConfig.getString("password"));
|
||||
hikariConfig.setMaximumPoolSize(datasourceConfig.getInt("maximum-pool-size", 3));
|
||||
hikariConfig.setMinimumIdle(datasourceConfig.getInt("minimum-idle", 1));
|
||||
long keepAliveTime = datasourceConfig.getLong("keep-alive-time", 0);
|
||||
if (keepAliveTime > 5000) {
|
||||
hikariConfig.setKeepaliveTime(keepAliveTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static void putFileToZipStream(@NotNull ZipOutputStream stream, @NotNull String path, @NotNull File file) throws IOException {
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
if (files == null) {
|
||||
throw new IOException();
|
||||
}
|
||||
for (File subFile : files) {
|
||||
putFileToZipStream(stream, path + file.getName() + "/", subFile);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ZipEntry entry = new ZipEntry(path + file.getName());
|
||||
stream.putNextEntry(entry);
|
||||
stream.write(Files.readAllBytes(file.toPath()));
|
||||
stream.closeEntry();
|
||||
hikariConfig.setIdleTimeout(datasourceConfig.getLong("idle-timeout", 10 * 60 * 1000));
|
||||
hikariConfig.setMaxLifetime(datasourceConfig.getLong("max-lifetime", 30 * 60 * 1000));
|
||||
hikariConfig.setValidationTimeout(datasourceConfig.getLong("validation-timeout", 5000));
|
||||
hikariConfig.setPoolName(datasourceConfig.getString("name", "HamsterCore-Pool"));
|
||||
return new HikariDataSource(hikariConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,24 +126,30 @@ public final class CoreUtils {
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DataSource getDataSource(@NotNull ConfigSection datasourceConfig) {
|
||||
HikariConfig hikariConfig = new HikariConfig();
|
||||
hikariConfig.setDriverClassName(datasourceConfig.getString("driver"));
|
||||
hikariConfig.setJdbcUrl(datasourceConfig.getString("url"));
|
||||
hikariConfig.setUsername(datasourceConfig.getString("username"));
|
||||
hikariConfig.setPassword(datasourceConfig.getString("password"));
|
||||
hikariConfig.setMaximumPoolSize(datasourceConfig.getInt("maximum-pool-size", 3));
|
||||
hikariConfig.setMinimumIdle(datasourceConfig.getInt("minimum-idle", 1));
|
||||
long keepAliveTime = datasourceConfig.getLong("keep-alive-time", 0);
|
||||
if (keepAliveTime > 5000) {
|
||||
hikariConfig.setKeepaliveTime(keepAliveTime);
|
||||
public static void loadTranslation(@NotNull TranslationRegistry registry, @NotNull File folder) throws IOException {
|
||||
for (File subFile : Objects.requireNonNull(folder.listFiles())) {
|
||||
String filename = subFile.getName().split("\\.")[0];
|
||||
String[] args = filename.split("_");
|
||||
Locale locale = new Locale.Builder().setLanguage(args[0]).setRegion(args[1]).build();
|
||||
YamlConfig config = YamlConfig.load(subFile);
|
||||
Map<String, MessageFormat> map = loadTranslation(locale, config, "");
|
||||
registry.registerAll(locale, map);
|
||||
}
|
||||
hikariConfig.setIdleTimeout(datasourceConfig.getLong("idle-timeout", 10 * 60 * 1000));
|
||||
hikariConfig.setMaxLifetime(datasourceConfig.getLong("max-lifetime", 30 * 60 * 1000));
|
||||
hikariConfig.setValidationTimeout(datasourceConfig.getLong("validation-timeout", 5000));
|
||||
hikariConfig.setPoolName(datasourceConfig.getString("name", "HamsterCore-Pool"));
|
||||
return new HikariDataSource(hikariConfig);
|
||||
}
|
||||
|
||||
public static Map<String, MessageFormat> loadTranslation(@NotNull Locale locale, @NotNull ConfigSection config, @NotNull String prefix) {
|
||||
HashMap<String, MessageFormat> result = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : config.getMap().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof String) {
|
||||
String string = (String) value;
|
||||
result.put(prefix + key, new MessageFormat(string, locale));
|
||||
} else if (value instanceof Map) {
|
||||
loadTranslation(locale, config.getSectionOrCreate(key), "$prefix$key.");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,94 @@
|
||||
package cn.hamster3.mc.plugin.core.common.util;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class SimpleLogger {
|
||||
public abstract void log(@NotNull Level level, @NotNull String msg);
|
||||
|
||||
public abstract void log(@NotNull Level level, @NotNull Throwable throwable);
|
||||
|
||||
public abstract void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg);
|
||||
|
||||
public void log(@NotNull Level level, @NotNull String msg, @NotNull Object... args) {
|
||||
try {
|
||||
log(level, String.format(msg, args));
|
||||
} catch (Exception e) {
|
||||
log(Level.WARNING, "输出日志 " + msg + Arrays.toString(args) + " 时遇到一个异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) {
|
||||
try {
|
||||
log(level, throwable, String.format(msg, args));
|
||||
} catch (Exception e) {
|
||||
log(Level.WARNING, "输出日志 " + msg + Arrays.toString(args) + " 时遇到一个异常", e);
|
||||
log(Level.WARNING, "异常参数: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void info(@NotNull String msg) {
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
public void info(@NotNull String msg, @NotNull Object... args) {
|
||||
log(Level.INFO, msg, args);
|
||||
}
|
||||
|
||||
public void info(@NotNull Throwable throwable) {
|
||||
log(Level.INFO, throwable);
|
||||
}
|
||||
|
||||
public void info(@NotNull Throwable throwable, @NotNull String msg) {
|
||||
log(Level.INFO, throwable, msg);
|
||||
}
|
||||
|
||||
public void info(@NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) {
|
||||
log(Level.INFO, throwable, msg, args);
|
||||
}
|
||||
|
||||
public void warn(@NotNull String msg) {
|
||||
log(Level.WARNING, msg);
|
||||
}
|
||||
|
||||
public void warn(@NotNull String msg, @NotNull Object... args) {
|
||||
log(Level.WARNING, msg, args);
|
||||
}
|
||||
|
||||
public void warn(@NotNull Throwable throwable) {
|
||||
log(Level.WARNING, throwable);
|
||||
}
|
||||
|
||||
public void warn(@NotNull Throwable throwable, @NotNull String msg) {
|
||||
log(Level.WARNING, throwable, msg);
|
||||
}
|
||||
|
||||
public void warn(@NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) {
|
||||
log(Level.WARNING, throwable, msg, args);
|
||||
}
|
||||
|
||||
public void error(@NotNull String msg) {
|
||||
log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
public void error(@NotNull String msg, @NotNull Object... args) {
|
||||
log(Level.SEVERE, msg, args);
|
||||
}
|
||||
|
||||
public void error(@NotNull Throwable throwable) {
|
||||
log(Level.SEVERE, throwable);
|
||||
}
|
||||
|
||||
public void error(@NotNull Throwable throwable, @NotNull String msg) {
|
||||
log(Level.SEVERE, throwable, msg);
|
||||
}
|
||||
|
||||
public void error(@NotNull Throwable throwable, @NotNull String msg, @NotNull Object... args) {
|
||||
log(Level.SEVERE, throwable, msg, args);
|
||||
}
|
||||
}
|
@@ -1,10 +1,13 @@
|
||||
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;
|
||||
|
||||
@@ -12,8 +15,12 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
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();
|
||||
@@ -21,59 +28,72 @@ public final class UpdateCheckUtils {
|
||||
private UpdateCheckUtils() {
|
||||
}
|
||||
|
||||
public static void showUpdate(@NotNull String pluginName, @NotNull ConfigSection config, @NotNull UpdateReceiver sender) {
|
||||
String version = config.getString("version");
|
||||
if (version == null) {
|
||||
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 checkType = config.getString("CHECK_TYPE", "");
|
||||
try {
|
||||
switch (checkType) {
|
||||
case "GITEA_RELEASES": {
|
||||
String baseUrl = config.getString("GIT_BASE_URL");
|
||||
String gitRepo = config.getString("GIT_REPO");
|
||||
String downloadUrl = config.getString("DOWNLOAD_URL");
|
||||
if (baseUrl == null || gitRepo == null || downloadUrl == null) {
|
||||
return;
|
||||
}
|
||||
String gitToken = config.getString("GIT_TOKEN");
|
||||
String lastRelease = getGiteaLastRelease(baseUrl, gitRepo, gitToken);
|
||||
if (lastRelease == null) {
|
||||
break;
|
||||
}
|
||||
if (lastRelease.compareToIgnoreCase(version) <= 0) {
|
||||
break;
|
||||
}
|
||||
sender.sendMessage(String.format("§a插件 §l%s§a 发布了新版本 %s", pluginName, lastRelease));
|
||||
sender.sendMessage(String.format("§b下载链接: §n%s", downloadUrl));
|
||||
break;
|
||||
}
|
||||
case "GITLAB_RELEASES": {
|
||||
String baseUrl = config.getString("GIT_BASE_URL");
|
||||
String gitRepo = config.getString("GIT_REPO");
|
||||
String downloadUrl = config.getString("DOWNLOAD_URL");
|
||||
if (baseUrl == null || gitRepo == null || downloadUrl == null) {
|
||||
return;
|
||||
}
|
||||
String gitToken = config.getString("GIT_TOKEN");
|
||||
int projectID = getGitlabProjectID(baseUrl, gitRepo, gitToken);
|
||||
if (projectID < 0) {
|
||||
break;
|
||||
}
|
||||
String lastRelease = getGitlabLastRelease(baseUrl, projectID, gitToken);
|
||||
if (lastRelease == null) {
|
||||
break;
|
||||
}
|
||||
if (lastRelease.compareToIgnoreCase(version) <= 0) {
|
||||
break;
|
||||
}
|
||||
sender.sendMessage(String.format("§a插件 §l%s§a 发布了新版本 %s", pluginName, lastRelease));
|
||||
sender.sendMessage(String.format("§b下载链接: §n%s", downloadUrl));
|
||||
break;
|
||||
String gitToken = updateConfig.getString("GIT_TOKEN");
|
||||
String lastRelease = null;
|
||||
switch (checkType) {
|
||||
case "GITEA_RELEASES": {
|
||||
lastRelease = getGiteaLastRelease(baseUrl, gitRepo, gitToken);
|
||||
if (downloadUrl == null) {
|
||||
downloadUrl = URI.create(baseUrl).resolve("/" + gitRepo).toString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "GITLAB_RELEASES": {
|
||||
int projectID = getGitlabProjectID(baseUrl, gitRepo, gitToken);
|
||||
if (projectID < 0) {
|
||||
break;
|
||||
}
|
||||
lastRelease = getGitlabLastRelease(baseUrl, projectID, gitToken);
|
||||
if (downloadUrl == null) {
|
||||
downloadUrl = URI.create(baseUrl).resolve("/" + gitRepo).toString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
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
|
||||
@@ -91,7 +111,6 @@ public final class UpdateCheckUtils {
|
||||
JsonArray array = JSON_PARSER.parse(reader).getAsJsonArray();
|
||||
for (JsonElement element : array) {
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
//noinspection SpellCheckingInspection
|
||||
if (object.get("prerelease").getAsBoolean()) {
|
||||
continue;
|
||||
}
|
||||
@@ -103,12 +122,12 @@ public final class UpdateCheckUtils {
|
||||
}
|
||||
|
||||
public static int getGitlabProjectID(@NotNull String baseUrl, @NotNull String repo, @Nullable String token) throws IOException {
|
||||
URL url = new URL("https://" + baseUrl + "/api/v4/projects?search=" + repo);
|
||||
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 " + token);
|
||||
connection.setRequestProperty("PRIVATE-TOKEN", token);
|
||||
}
|
||||
connection.connect();
|
||||
try (InputStream stream = connection.getInputStream()) {
|
||||
@@ -130,7 +149,7 @@ public final class UpdateCheckUtils {
|
||||
connection.setDoInput(true);
|
||||
connection.setRequestMethod("GET");
|
||||
if (token != null) {
|
||||
connection.setRequestProperty("Authorization", "token " + token);
|
||||
connection.setRequestProperty("PRIVATE-TOKEN", token);
|
||||
}
|
||||
connection.connect();
|
||||
try (InputStream stream = connection.getInputStream()) {
|
||||
@@ -140,8 +159,4 @@ public final class UpdateCheckUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface UpdateReceiver {
|
||||
void sendMessage(@NotNull String message);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,146 @@
|
||||
package cn.hamster3.mc.plugin.core.common.util.async;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@SuppressWarnings({"unused", "CallToPrintStackTrace"})
|
||||
public class CompletableTask<T> {
|
||||
@NotNull
|
||||
private final List<Consumer<T>> onSuccess;
|
||||
@NotNull
|
||||
private final List<Consumer<Throwable>> onFailed;
|
||||
@NotNull
|
||||
private State state;
|
||||
private T value;
|
||||
private Throwable throwable;
|
||||
|
||||
public CompletableTask() {
|
||||
state = State.WAITING;
|
||||
onSuccess = new ArrayList<>();
|
||||
onFailed = new ArrayList<>();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CompletableTask<Void> runAsync(@NotNull RunTask runTask) {
|
||||
CompletableTask<Void> task = new CompletableTask<>();
|
||||
CoreAPI.getInstance().getExecutorService().submit(() -> {
|
||||
try {
|
||||
runTask.run();
|
||||
task.success(null);
|
||||
} catch (Exception e) {
|
||||
task.failed(e);
|
||||
}
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <T> CompletableTask<T> supplyAsync(@NotNull SupplyTask<T> supplyTask) {
|
||||
CompletableTask<T> task = new CompletableTask<>();
|
||||
CoreAPI.getInstance().getExecutorService().submit(() -> {
|
||||
try {
|
||||
T call = supplyTask.call();
|
||||
task.success(call);
|
||||
} catch (Exception e) {
|
||||
task.failed(e);
|
||||
}
|
||||
});
|
||||
return task;
|
||||
}
|
||||
|
||||
public void success(@Nullable T value) {
|
||||
if (state != State.WAITING) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.value = value;
|
||||
state = State.SUCCESS;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
for (Consumer<T> success : onSuccess) {
|
||||
try {
|
||||
success.accept(value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void failed(@Nullable Throwable throwable) {
|
||||
if (state != State.WAITING) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.value = null;
|
||||
state = State.FAILED;
|
||||
this.throwable = throwable;
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
for (Consumer<Throwable> consumer : onFailed) {
|
||||
try {
|
||||
consumer.accept(throwable);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompletableTask<T> onSuccess(@NotNull Consumer<T> consumer) {
|
||||
if (state == State.SUCCESS) {
|
||||
try {
|
||||
consumer.accept(value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
onSuccess.add(consumer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompletableTask<T> onFailed(@NotNull Consumer<Throwable> consumer) {
|
||||
if (state == State.FAILED) {
|
||||
try {
|
||||
consumer.accept(throwable);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
onFailed.add(consumer);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public T get() throws InterruptedException {
|
||||
if (state == State.WAITING) {
|
||||
synchronized (this) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
if (state == State.SUCCESS) {
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public T join() {
|
||||
try {
|
||||
return get();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public enum State {
|
||||
WAITING,
|
||||
SUCCESS,
|
||||
FAILED
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package cn.hamster3.mc.plugin.core.common.util.async;
|
||||
|
||||
public interface RunTask {
|
||||
void run() throws Exception;
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
package cn.hamster3.mc.plugin.core.common.util.async;
|
||||
|
||||
public interface SupplyTask<T> {
|
||||
T call() throws Exception;
|
||||
}
|
21
core-relocate-lettuce/build.gradle.kts
Normal file
21
core-relocate-lettuce/build.gradle.kts
Normal file
@@ -0,0 +1,21 @@
|
||||
// lettuce-core 需要使用 netty,但低版本 bukkit 服务端核心自带的 netty 版本 lettuce 需要的版本有冲突
|
||||
// 所以必须 shadow 并 relocate 依赖 io.netty,才能保证两个版本互不冲突
|
||||
// 但由于 core-bukkit 同时也 shadow 了 adventure-platform-bukkit,且 adventure 内部通过反射调用 netty
|
||||
// 如果在 core-bukkit 中直接 relocate netty,会导致 adventure 的反射调用也指向 relocate 后的 netty
|
||||
// 此时会导致 shadow 后的 adventure 与服务端中其他同样需要使用 netty 的插件关联时发生冲突
|
||||
// 例如:服务端上安装了 ViaVersion 时,core-bukkit 内置的 adventure 将会与其发生冲突
|
||||
// 因为 adventure 使用 relocate 之后的类路径,ViaVersion 在将类转换成原版 netty 类时,会发生 ClassCastException
|
||||
// 所以只能先将 lettuce-core 与其需要的 netty 一起打包,并 relocate netty,然后再使 core-bukkit 依赖这个打包后的版本
|
||||
// 才能使得 adventure 与 lettuce-core 正常运行
|
||||
|
||||
dependencies {
|
||||
implementation("io.lettuce:lettuce-core:6.7.1.RELEASE") {
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
shadowJar {
|
||||
relocate("io.netty", "cn.hamster3.mc.plugin.core.lib.io.netty")
|
||||
}
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
@file:Suppress("VulnerableLibrariesLocal")
|
||||
|
||||
evaluationDependsOn(":core-common")
|
||||
evaluationDependsOn(":core-relocate-lettuce")
|
||||
|
||||
val shade = configurations.create("shade")
|
||||
|
||||
dependencies {
|
||||
api(project(":core-common")) { isTransitive = false }
|
||||
@@ -8,21 +11,20 @@ dependencies {
|
||||
annotationProcessor("com.velocitypowered:velocity-api:3.3.0-SNAPSHOT")
|
||||
|
||||
compileOnlyApi("net.kyori:adventure-platform-api:4.3.2") { isTransitive = false }
|
||||
// https://mvnrepository.com/artifact/redis.clients/jedis
|
||||
api("redis.clients:jedis:5.1.2") {
|
||||
|
||||
implementation("com.zaxxer:HikariCP:5.1.0") { isTransitive = false }
|
||||
api("redis.clients:jedis:5.1.4") {
|
||||
exclude(group = "com.google.code.gson")
|
||||
exclude(group = "org.slf4j")
|
||||
}
|
||||
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
|
||||
api("org.quartz-scheduler:quartz:2.3.2") { isTransitive = false }
|
||||
|
||||
// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
|
||||
implementation("com.zaxxer:HikariCP:5.1.0") { isTransitive = false }
|
||||
compileOnlyApi("io.lettuce:lettuce-core:6.7.1.RELEASE") {
|
||||
exclude(group = "org.slf4j")
|
||||
exclude(group = "io.netty")
|
||||
}
|
||||
shade(project(":core-relocate-lettuce"))
|
||||
|
||||
// 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") }
|
||||
runtimeOnly("com.mysql:mysql-connector-j:8.4.0")
|
||||
}
|
||||
|
||||
sourceSets.create("templates") {
|
||||
@@ -52,6 +54,9 @@ tasks {
|
||||
archiveBaseName = "HamsterCore-Velocity"
|
||||
}
|
||||
shadowJar {
|
||||
dependsOn(":core-relocate-lettuce:shadowJar")
|
||||
val task = project(":core-relocate-lettuce").tasks.shadowJar.get()
|
||||
from(task.outputs.files.map { if (it.isDirectory) it else zipTree(it) })
|
||||
destinationDirectory = rootProject.layout.buildDirectory
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@ import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.config.YamlConfig;
|
||||
import cn.hamster3.mc.plugin.core.common.util.UpdateCheckUtils;
|
||||
import cn.hamster3.mc.plugin.core.velocity.api.CoreVelocityAPI;
|
||||
import cn.hamster3.mc.plugin.core.velocity.impl.AudienceProviderImpl;
|
||||
import cn.hamster3.mc.plugin.core.velocity.util.VelocitySimpleLogger;
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.PostOrder;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
@@ -15,11 +17,9 @@ import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -38,25 +38,22 @@ public class HamsterCorePlugin {
|
||||
@Getter
|
||||
private static HamsterCorePlugin instance;
|
||||
@Getter
|
||||
private final java.util.logging.Logger logger;
|
||||
@Getter
|
||||
private final Logger slf4jLogger;
|
||||
private final VelocitySimpleLogger simpleLogger;
|
||||
@Getter
|
||||
private final ProxyServer proxyServer;
|
||||
@Getter
|
||||
private final File dataFolder;
|
||||
|
||||
@Inject
|
||||
public HamsterCorePlugin(Logger slf4jLogger, ProxyServer proxyServer, @DataDirectory Path dataPath) {
|
||||
logger = java.util.logging.Logger.getLogger("hamster-core");
|
||||
this.slf4jLogger = slf4jLogger;
|
||||
public HamsterCorePlugin(Logger logger, ProxyServer proxyServer, @DataDirectory Path dataPath) {
|
||||
this.simpleLogger = new VelocitySimpleLogger(logger);
|
||||
this.proxyServer = proxyServer;
|
||||
dataFolder = dataPath.toFile();
|
||||
instance = this;
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
if (dataFolder.mkdir()) {
|
||||
slf4jLogger.info("已生成插件存档文件夹");
|
||||
simpleLogger.info("已生成插件存档文件夹");
|
||||
}
|
||||
File configFile = new File(dataFolder, "config.yml");
|
||||
if (!configFile.exists()) {
|
||||
@@ -67,60 +64,65 @@ public class HamsterCorePlugin {
|
||||
}
|
||||
}
|
||||
CoreVelocityAPI.init(configFile);
|
||||
slf4jLogger.info("已初始化 CoreAPI");
|
||||
simpleLogger.info("已初始化 CoreAPI");
|
||||
} catch (Exception e) {
|
||||
slf4jLogger.error("初始化 CoreAPI 出错", e);
|
||||
simpleLogger.error(e, "初始化 CoreAPI 出错");
|
||||
}
|
||||
long time = System.currentTimeMillis() - start;
|
||||
slf4jLogger.info("HamsterCore 初始化完成,总计耗时 " + time + " ms");
|
||||
simpleLogger.info("仓鼠核心初始化完成,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
@Subscribe(order = PostOrder.FIRST)
|
||||
public void onProxyInitialization(ProxyInitializeEvent event) {
|
||||
long start = System.currentTimeMillis();
|
||||
slf4jLogger.info("仓鼠核心正在启动");
|
||||
simpleLogger.info("仓鼠核心正在启动");
|
||||
CoreAPI.getInstance().getExecutorService().submit(this::checkUpdate);
|
||||
long time = System.currentTimeMillis() - start;
|
||||
slf4jLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||
CoreAPI.getInstance().getExecutorService().submit(() -> {
|
||||
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.showUpdate(pluginName, config, (s) -> proxyServer.sendMessage(Component.text(s)));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
simpleLogger.info("仓鼠核心启动完成,总计耗时 " + time + " ms");
|
||||
}
|
||||
|
||||
@Subscribe(order = PostOrder.LAST)
|
||||
public void onProxyShutdown(ProxyShutdownEvent event) {
|
||||
long start = System.currentTimeMillis();
|
||||
CoreAPI.getInstance().getJedisPool().close();
|
||||
slf4jLogger.info("已关闭 Redis 连接池");
|
||||
if (CoreAPI.getInstance().getDataSource() instanceof HikariDataSource dataSource) {
|
||||
dataSource.close();
|
||||
slf4jLogger.info("已关闭数据库连接池");
|
||||
AudienceProviderImpl.INSTANCE.close();
|
||||
simpleLogger.info("已关闭 AudienceProvider.");
|
||||
if (CoreAPI.getInstance().isEnableRedis()) {
|
||||
CoreAPI.getInstance().getJedisPool().close();
|
||||
CoreAPI.getInstance().getRedisClient().close();
|
||||
simpleLogger.info("已关闭 Redis 连接池");
|
||||
}
|
||||
if (CoreAPI.getInstance().isEnableDatabase()) {
|
||||
((HikariDataSource) CoreAPI.getInstance().getDataSource()).close();
|
||||
simpleLogger.info("已关闭数据库连接池");
|
||||
}
|
||||
CoreAPI.getInstance().getExecutorService().shutdownNow();
|
||||
slf4jLogger.info("已关闭 ExecutorService 线程池");
|
||||
simpleLogger.info("已关闭 ExecutorService 线程池");
|
||||
CoreAPI.getInstance().getScheduledService().shutdownNow();
|
||||
slf4jLogger.info("已关闭 ScheduledExecutorService 线程池");
|
||||
simpleLogger.info("已关闭 ScheduledExecutorService 线程池");
|
||||
long time = System.currentTimeMillis() - start;
|
||||
slf4jLogger.info("HamsterCore 关闭完成,总计耗时 " + time + " ms");
|
||||
simpleLogger.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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,16 +7,16 @@ 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 cn.hamster3.mc.plugin.core.velocity.util.VelocitySimpleLogger;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import cn.hamster3.mc.plugin.core.velocity.impl.AudienceProviderImpl;
|
||||
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 {
|
||||
@@ -57,8 +57,8 @@ public final class CoreVelocityAPI extends CoreAPI {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Logger getLogger() {
|
||||
return HamsterCorePlugin.getInstance().getLogger();
|
||||
public @NotNull VelocitySimpleLogger getLogger() {
|
||||
return HamsterCorePlugin.getInstance().getSimpleLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,57 @@
|
||||
package cn.hamster3.mc.plugin.core.velocity.util;
|
||||
|
||||
import cn.hamster3.mc.plugin.core.common.util.SimpleLogger;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Getter
|
||||
public class VelocitySimpleLogger extends SimpleLogger {
|
||||
@NotNull
|
||||
private final Logger logger;
|
||||
|
||||
public VelocitySimpleLogger(@NotNull Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull String msg) {
|
||||
if (level == Level.INFO) {
|
||||
logger.info(msg);
|
||||
} else if (level == Level.WARNING) {
|
||||
logger.warn(msg);
|
||||
} else if (level == Level.SEVERE) {
|
||||
logger.error(msg);
|
||||
} else {
|
||||
logger.trace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable) {
|
||||
if (level == Level.INFO) {
|
||||
logger.info("", throwable);
|
||||
} else if (level == Level.WARNING) {
|
||||
logger.warn("", throwable);
|
||||
} else if (level == Level.SEVERE) {
|
||||
logger.error("", throwable);
|
||||
} else {
|
||||
logger.trace("", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@NotNull Level level, @NotNull Throwable throwable, @NotNull String msg) {
|
||||
if (level == Level.INFO) {
|
||||
logger.info(msg, throwable);
|
||||
} else if (level == Level.WARNING) {
|
||||
logger.warn(msg, throwable);
|
||||
} else if (level == Level.SEVERE) {
|
||||
logger.error(msg, throwable);
|
||||
} else {
|
||||
logger.trace(msg, throwable);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,3 +1,6 @@
|
||||
# 是否启用 redis 连接池功能
|
||||
enable-redis: false
|
||||
|
||||
# redis 连接配置
|
||||
# 完整格式如下:
|
||||
# redis://用户名:密码@主机名:端口/数据库索引?参数名=参数值&参数名=参数值
|
||||
@@ -8,18 +11,16 @@
|
||||
# 若不设置数据库,则默认使用 0
|
||||
redis-url: "redis://localhost:6379/0?clientName=HamsterCore&timeout=5s"
|
||||
|
||||
# 是否启用数据库连接池功能
|
||||
enable-database: false
|
||||
|
||||
# 数据库连接池配置
|
||||
datasource:
|
||||
# 数据库链接驱动地址
|
||||
# 除非你知道自己在做什么,否则不建议更改该项
|
||||
# 旧版服务端(低于1.13)请使用:com.mysql.jdbc.Driver
|
||||
driver: "com.mysql.cj.jdbc.Driver"
|
||||
# 数据库链接填写格式:
|
||||
# MySQL数据库链接填写格式:
|
||||
# jdbc:mysql://{数据库地址}:{数据库端口}/{使用的库名}?参数
|
||||
# 除非你知道自己在做什么,否则不建议随意更改参数
|
||||
url: "jdbc:mysql://localhost:3306/Test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true"
|
||||
# 如果你不需要做多端跨服,那么请使用 sqlite 作本地数据库
|
||||
# driver: "org.sqlite.JDBC"
|
||||
# url: "jdbc:sqlite:./plugins/HamsterCore/database.db"
|
||||
# 用户名
|
||||
username: "root"
|
||||
# 密码
|
||||
|
@@ -1,6 +1,4 @@
|
||||
version: ${version}
|
||||
VERSION: ${version}
|
||||
CHECK_TYPE: GITEA_RELEASES
|
||||
GIT_BASE_URL: https://git.airgame.net
|
||||
GIT_REPO: MiniDay/hamster-core
|
||||
GIT_TOKEN: a44a69a4d1b8601bf6091403247759cd28764d5e
|
||||
DOWNLOAD_URL: https://jenkins.airgame.net/job/opensource/job/hamster-core/
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@@ -1,8 +1,6 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://maven.airgame.net/maven-public/")
|
||||
}
|
||||
maven("https://maven.airgame.net/maven-public/")
|
||||
}
|
||||
}
|
||||
rootProject.name = "hamster-core"
|
||||
@@ -10,3 +8,4 @@ include("core-common")
|
||||
include("core-bukkit")
|
||||
include("core-bungee")
|
||||
include("core-velocity")
|
||||
include("core-relocate-lettuce")
|
Reference in New Issue
Block a user