Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,11 @@ run/
logs
kbc.yml
plugins
permissions.json
permissions.json

# AI Tools
.claude/
.spec-workflow/
.fastRequest/
AGENTS.md
CLAUDE.md
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ java -jar kookbc-<version>.jar
配置完成后,再次使用之前的命令行启动 KookBC ,当如下语句出现时,您的 KookBC 就已经准备就绪,可以使用。

```text
[XX:XX:XX] [Main Thread/INFO] Done! Type "help" for help.
[XX:XX:XX] [Main Thread/INFO] 完成!输入 "help" 获取帮助。
```

其中,`X` 为任意可能的值,您可以忽视。
Expand Down
23 changes: 16 additions & 7 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import java.util.*
plugins {
`java-library`
`maven-publish`
id("com.gorylenko.gradle-git-properties") version "2.4.2"
id("com.gorylenko.gradle-git-properties") version "2.5.3"
id("com.gradleup.shadow") version "9.0.0-beta4"
id("publish-conventions")
}
Expand All @@ -25,7 +25,7 @@ dependencies {
shadow(dep)
api(dep)
}
shadowApi(libs.com.github.snwcreations.jkook)
shadowApi(libs.io.github.snwcreations.jkook)
shadowApi(libs.com.github.snwcreations.terminalconsoleappender)
shadowApi(libs.uk.org.lidalia.sysout.over.slf4j)
shadowApi(libs.org.apache.logging.log4j.log4j.core)
Expand All @@ -38,17 +38,21 @@ dependencies {
shadowApi(libs.net.kyori.event.method)
shadowApi(libs.net.freeutils.jlhttp)
shadowApi(libs.com.google.code.gson.gson)
shadow("com.fasterxml.jackson.core:jackson-core:2.17.2"); api("com.fasterxml.jackson.core:jackson-core:2.17.2")
shadow("com.fasterxml.jackson.core:jackson-databind:2.17.2"); api("com.fasterxml.jackson.core:jackson-databind:2.17.2")
shadow("com.fasterxml.jackson.core:jackson-annotations:2.17.2"); api("com.fasterxml.jackson.core:jackson-annotations:2.17.2")
shadow("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2"); api("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2")
shadowApi(libs.com.github.ben.manes.caffeine.caffeine)
shadowApi(libs.net.fabricmc.sponge.mixin)
shadowApi(libs.dev.rollczi.litecommands.framework)
shadowApi(libs.net.bytebuddy.byte.buddy.agent)
compileOnly(libs.org.jetbrains.annotations)
}
group = "io.github.snwcreations"
version = "0.32.2"
version = "0.33.0"
description = "KookBC"
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8
java.sourceCompatibility = JavaVersion.VERSION_21
java.targetCompatibility = JavaVersion.VERSION_21

tasks.compileJava {
options.encoding = "UTF-8"
Expand All @@ -71,6 +75,7 @@ gitProperties {
val skipShade = properties["skipShade"] == "true"
tasks.shadowJar {
enabled = !skipShade
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveClassifier = ""
transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer())
exclude(
Expand All @@ -81,9 +86,13 @@ tasks.shadowJar {
)
}

tasks.compileJava {
options.encoding = "UTF-8"
}

tasks.processResources {
filesMatching("*.json") {
expand(properties + mapOf("jkookVersion" to libs.versions.com.github.snwcreations.jkook.get()))
expand(properties + mapOf("jkookVersion" to libs.versions.io.github.snwcreations.jkook.get()))
}
}

Expand All @@ -99,7 +108,7 @@ tasks.jar {
mapOf(
"Build-Time" to Date(),
"Specification-Title" to "JKook",
"Specification-Version" to libs.com.github.snwcreations.jkook.get().version,
"Specification-Version" to libs.io.github.snwcreations.jkook.get().version,
"Specification-Vendor" to "SNWCreations",
"Implementation-Title" to "KookBC",
"Implementation-Version" to version.toString(),
Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/publish-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ indra {
gpl3OnlyLicense()

javaVersions {
target(8)
minimumToolchain(17)
target(21)
minimumToolchain(21)
}

configurePublications {
Expand Down
28 changes: 24 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[versions]
com-github-ben-manes-caffeine-caffeine = "2.9.3"
com-github-snwcreations-jkook = "0.54.1"
com-github-snwcreations-terminalconsoleappender = "1.3.5"
com-google-code-gson-gson = "2.10.1"
io-github-snwcreations-jkook = "0.54.2"
com-github-snwcreations-terminalconsoleappender = "1.3.5"
com-squareup-okhttp3-okhttp = "4.10.0"
dev-rollczi-litecommands-framework = "3.9.5"
net-bytebuddy-byte-buddy = "1.12.10"
Expand All @@ -18,12 +18,19 @@ org-fusesource-jansi-jansi = "2.4.0"
org-jetbrains-annotations = "23.1.0"
org-jline-jline-terminal-jansi = "3.21.0"
uk-org-lidalia-sysout-over-slf4j = "1.0.2"
# Test Dependencies
junit = "5.9.3"
mockito = "4.11.0"
wiremock = "2.27.2"
testcontainers = "1.17.6"
assertj = "3.24.2"
mockwebserver = "4.10.0"

[libraries]
com-github-ben-manes-caffeine-caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "com-github-ben-manes-caffeine-caffeine" }
com-github-snwcreations-jkook = { module = "com.github.SNWCreations:JKook", version.ref = "com-github-snwcreations-jkook" }
com-github-snwcreations-terminalconsoleappender = { module = "com.github.SNWCreations:TerminalConsoleAppender", version.ref = "com-github-snwcreations-terminalconsoleappender" }
com-google-code-gson-gson = { module = "com.google.code.gson:gson", version.ref = "com-google-code-gson-gson" }
io-github-snwcreations-jkook = { module = "io.github.snwcreations:jkook", version.ref = "io-github-snwcreations-jkook" }
com-github-snwcreations-terminalconsoleappender = { module = "com.github.SNWCreations:TerminalConsoleAppender", version.ref = "com-github-snwcreations-terminalconsoleappender" }
com-squareup-okhttp3-okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "com-squareup-okhttp3-okhttp" }
dev-rollczi-litecommands-framework = { module = "dev.rollczi:litecommands-framework", version.ref = "dev-rollczi-litecommands-framework" }
net-bytebuddy-byte-buddy = { module = "net.bytebuddy:byte-buddy", version.ref = "net-bytebuddy-byte-buddy" }
Expand All @@ -39,3 +46,16 @@ org-fusesource-jansi-jansi = { module = "org.fusesource.jansi:jansi", version.re
org-jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "org-jetbrains-annotations" }
org-jline-jline-terminal-jansi = { module = "org.jline:jline-terminal-jansi", version.ref = "org-jline-jline-terminal-jansi" }
uk-org-lidalia-sysout-over-slf4j = { module = "uk.org.lidalia:sysout-over-slf4j", version.ref = "uk-org-lidalia-sysout-over-slf4j" }
# Test Libraries
junit_jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }
junit_jupiter_engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
junit_jupiter_params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
mockito_core = { module = "org.mockito:mockito-core", version.ref = "mockito" }
mockito_junit_jupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" }
mockito_inline = { module = "org.mockito:mockito-inline", version.ref = "mockito" }
wiremock_jre8 = { module = "com.github.tomakehurst:wiremock-jre8", version.ref = "wiremock" }
testcontainers_junit_jupiter = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" }
testcontainers_core = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" }
assertj_core = { module = "org.assertj:assertj-core", version.ref = "assertj" }
mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "mockwebserver" }

2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/snw/kookbc/CLIOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public final class CLIOptions {
static {
NO_BUCKET = Boolean.getBoolean("kookbc.nobucket");
if (NO_BUCKET) {
logger.warn("You've used kookbc.nobucket option, we won't check if you're going to be out of rate limit!");
logger.warn("您已启用 kookbc.nobucket 选项,我们将不会检查是否会超出速率限制!");
}
}

Expand Down
53 changes: 30 additions & 23 deletions src/main/java/snw/kookbc/LaunchMain.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/*
* License: https://github.com/Mojang/LegacyLauncher
*/

package snw.kookbc;

import static snw.kookbc.util.VirtualThreadUtil.startVirtualThread;

import joptsimple.OptionParser;
import joptsimple.OptionSet;
import joptsimple.OptionSpec;
Expand Down Expand Up @@ -40,25 +43,31 @@ public static void main(String[] args) {
ClassLoader appClassLoader = LaunchMain.class.getClassLoader();
Class<?> mixinClass = Class.forName("org.spongepowered.asm.util.JavaVersion");
if (mixinClass.getClassLoader() != appClassLoader) {
System.out.println("[KookBC/WARN] Mixin support is already enabled!");
System.out.println("[KookBC/WARN] If you're sure you don't need Mixin support, visit the following link:");
System.out.println("[KookBC/WARN] Mixin 支持已启用!");
System.out.println("[KookBC/WARN] 如果您确定不需要 Mixin 支持,请访问以下链接:");
System.out.println("[KookBC/WARN] https://github.com/SNWCreations/KookBC/blob/main/docs/KookBC_CommandLine.md#%E5%90%AF%E5%8A%A8%E5%85%A5%E5%8F%A3");
// Never part, never give up!
classLoader = new LaunchClassLoader(getUrls(appClassLoader).toArray(new URL[0]));
AccessClassLoader loader = AccessClassLoader.of(classLoader);
MixinPluginManager.instance().loadFolder(loader, new File("plugins"));
String[] finalArgs = args;
Thread thread = new Thread(() -> {
Thread thread = startVirtualThread(() -> {
try {
Class<?> mainClass = Class.forName(LaunchMainTweaker.CLASS_NAME);
MethodHandles.lookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class))
.invoke((Object) finalArgs);
} catch (Throwable e) {
throw new RuntimeException(e);
}
});
}, "Mixin-Launch-Thread");
thread.setContextClassLoader(PluginClassLoaderDelegate.INSTANCE);
thread.start();

// 等待虚拟线程完成
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return;
}
} catch (ClassNotFoundException ignored) {
Expand All @@ -76,14 +85,6 @@ public static void main(String[] args) {
}
args = argsList.toArray(new String[0]);
Thread.currentThread().setName(MAIN_THREAD_NAME);
// Actually here should not be warning, but the logging level of the LaunchWrapper is WARN.
// Also, I think this message can let the user know they are running KookBC under Launch mode.
LogWrapper.LOGGER.warn("Launching KookBC with Mixin support");
LogWrapper.LOGGER.warn("The author of Mixin support: huanmeng_qwq@Github"); // thank you! --- SNWCreations
LogWrapper.LOGGER.warn("Tips: You can safely ignore this.");
LogWrapper.LOGGER.warn("But if you're really sure you don't need Mixin support, visit the following link:");
LogWrapper.LOGGER.warn("https://github.com/SNWCreations/KookBC/blob/main/docs/KookBC_CommandLine.md");
LogWrapper.LOGGER.warn("The documentation will tell you how can you launch KookBC without Mixin support.");
launch.launch(args);
}

Expand Down Expand Up @@ -138,7 +139,7 @@ private void launch(String[] args) {
final OptionParser parser = new OptionParser();
parser.allowsUnrecognizedOptions();

final OptionSpec<String> tweakClassOption = parser.accepts("tweakClass", "Tweak class(es) to load").withRequiredArg().defaultsTo(MIXIN_TWEAK, DEFAULT_TWEAK);
final OptionSpec<String> tweakClassOption = parser.accepts("tweakClass", "要加载的调整类").withRequiredArg().defaultsTo(MIXIN_TWEAK, DEFAULT_TWEAK);
final OptionSpec<String> nonOption = parser.nonOptions();

final OptionSet options = parser.parse(args);
Expand Down Expand Up @@ -175,14 +176,14 @@ private void launch(String[] args) {
final String tweakName = it.next();
// Safety check - don't reprocess something we've already visited
if (allTweakerNames.contains(tweakName)) {
LogWrapper.LOGGER.warn("Tweak class name {} has already been visited -- skipping", tweakName);
LogWrapper.LOGGER.warn("调整类名 {} 已经被访问过 -- 跳过", tweakName);
// remove the tweaker from the stack otherwise it will create an infinite loop
it.remove();
continue;
} else {
allTweakerNames.add(tweakName);
}
LogWrapper.LOGGER.info("Loading tweak class name {}", tweakName);
LogWrapper.LOGGER.info("正在加载调整类 {}", tweakName);

// Ensure we allow the tweak class to load with the parent classloader
classLoader.addClassLoaderExclusion(tweakName.substring(0, tweakName.lastIndexOf('.')));
Expand All @@ -193,15 +194,15 @@ private void launch(String[] args) {
it.remove();
// If we haven't visited a tweaker yet, the first will become the 'primary' tweaker
if (primaryTweaker == null) {
LogWrapper.LOGGER.info("Using primary tweak class name {}", tweakName);
LogWrapper.LOGGER.info("使用主要调整类 {}", tweakName);
primaryTweaker = tweaker;
}
}

// Now, iterate all the tweakers we just instantiated
for (final Iterator<ITweaker> it = tweakers.iterator(); it.hasNext(); ) {
final ITweaker tweaker = it.next();
LogWrapper.LOGGER.info("Calling tweak class {}", tweaker.getClass().getName());
LogWrapper.LOGGER.info("调用调整类 {}", tweaker.getClass().getName());
tweaker.acceptOptions(options.valuesOf(nonOption));
tweaker.injectIntoClassLoader(classLoader);
allTweakers.add(tweaker);
Expand All @@ -221,7 +222,7 @@ private void launch(String[] args) {
}

if (primaryTweaker == null) {
throw new NullPointerException("Tweaker not found");
throw new NullPointerException("未找到调整器");
}

// Finally, we turn to the primary tweaker, and let it tell us where to go to launch
Expand All @@ -231,19 +232,25 @@ private void launch(String[] args) {
if (launchTarget != null && !launchTarget.isEmpty()) {
final Class<?> clazz = Class.forName(launchTarget, false, classLoader);
MethodHandle mainMethodHandle = MethodHandles.lookup().findStatic(clazz, "main", MethodType.methodType(void.class, String[].class));
Thread main = new Thread(() -> {
Thread main = startVirtualThread(() -> {
try {
mainMethodHandle.invoke((Object) argumentList.toArray(new String[0]));
} catch (Throwable e) {
e.printStackTrace();
}
}, clazz.getSimpleName());
}, clazz.getSimpleName() + "-Main-Thread");
main.setContextClassLoader(PluginClassLoaderDelegate.INSTANCE);
main.start();

// 等待虚拟线程完成
try {
main.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
} catch (Exception e) {
LogWrapper.LOGGER.error("Unable to launch", e);
LogWrapper.LOGGER.error("无法启动", e);
System.exit(1);
}
}
Expand Down
Loading
Loading