import org.gradle.api.tasks.Exec plugins { id("moonbridge.application-conventions") } val runtimeJavaHome = System.getProperty("java.home") dependencies { implementation(project(":messaging")) // The plugin contract is the only stable external boundary. Everything else // in this project remains an implementation package of the proxy core. api(project(":proxy-plugin-api")) implementation(libs.findLibrary("slf4j-api").get()) implementation(libs.findLibrary("netty-codec").get()) implementation(libs.findLibrary("netty-transport").get()) implementation(libs.findLibrary("netty-handler").get()) implementation(libs.findLibrary("netty-codec-http").get()) implementation(libs.findLibrary("netty-resolver-dns").get()) // Native transports are optional at runtime: NetworkTransport falls back to NIO when the // platform library is missing or cannot load (Windows, other CPU architectures, musl). implementation(libs.findLibrary("netty-transport-classes-epoll").get()) implementation(libs.findLibrary("netty-transport-classes-kqueue").get()) for (classifier in listOf("linux-x86_64", "linux-aarch_64")) { runtimeOnly(variantOf(libs.findLibrary("netty-transport-native-epoll").get()) { classifier(classifier) }) } for (classifier in listOf("osx-x86_64", "osx-aarch_64")) { runtimeOnly(variantOf(libs.findLibrary("netty-transport-native-kqueue").get()) { classifier(classifier) }) } implementation(libs.findLibrary("jackson-databind").get()) implementation(libs.findLibrary("jackson-yaml").get()) implementation(libs.findLibrary("adventure-gson").get()) implementation(libs.findLibrary("adventure-plain").get()) runtimeOnly(libs.findLibrary("logback-classic").get()) testImplementation(project(":backend")) testImplementation(libs.findLibrary("logback-classic").get()) testImplementation(libs.findLibrary("netty-pkitesting").get()) } val installedDistSmokeTest = tasks.register("installedDistSmokeTest") { group = "verification" description = "Runs the installed MoonBridge distribution in --validate-config mode." dependsOn(tasks.named("installDist")) val installDir = layout.buildDirectory.dir("install/moonbridge") inputs.dir(installDir) environment("JAVA_HOME", runtimeJavaHome) doFirst { val windows = System.getProperty("os.name").lowercase().contains("windows") val script = installDir.get().file("bin/" + if (windows) "moonbridge.bat" else "moonbridge").asFile val config = installDir.get().file("config/moonbridge.yml").asFile commandLine(script.absolutePath, "--validate-config", config.absolutePath) } } val installedDistHelpSmokeTest = tasks.register("installedDistHelpSmokeTest") { group = "verification" description = "Runs the installed MoonBridge distribution help command." dependsOn(tasks.named("installDist")) val installDir = layout.buildDirectory.dir("install/moonbridge") inputs.dir(installDir) environment("JAVA_HOME", runtimeJavaHome) doFirst { val windows = System.getProperty("os.name").lowercase().contains("windows") val script = installDir.get().file("bin/" + if (windows) "moonbridge.bat" else "moonbridge").asFile commandLine(script.absolutePath, "--help") } } val installedDistVersionSmokeTest = tasks.register("installedDistVersionSmokeTest") { group = "verification" description = "Runs the installed MoonBridge distribution version command." dependsOn(tasks.named("installDist")) val installDir = layout.buildDirectory.dir("install/moonbridge") inputs.dir(installDir) environment("JAVA_HOME", runtimeJavaHome) doFirst { val windows = System.getProperty("os.name").lowercase().contains("windows") val script = installDir.get().file("bin/" + if (windows) "moonbridge.bat" else "moonbridge").asFile commandLine(script.absolutePath, "--version") } } // The benchmarks in testing/benchmarks/ declare proxy-core packages to reach package-private classes and are // normally compiled by their PowerShell runners. Compiling them here keeps them building with main. val compileBenchmarks = tasks.register("compileBenchmarks") { group = "verification" description = "Compiles the benchmarks in testing/benchmarks/ against proxy-core." source(rootProject.fileTree("testing/benchmarks") { include("*.java") }) classpath = sourceSets.main.get().runtimeClasspath destinationDirectory.set(layout.buildDirectory.dir("classes/benchmarks")) options.release.set(25) } // permissionAcceptance needs the LuckPerms plugin, which is only built with -Pluckperms. val luckPerms = rootProject.findProject(":luckperms-moonbridge") if (luckPerms != null) { val compilePermissionAcceptance = tasks.register("compilePermissionAcceptance") { source(rootProject.file("testing/smoke/PermissionAcceptance.java")) classpath = sourceSets.main.get().runtimeClasspath destinationDirectory.set(layout.buildDirectory.dir("classes/permissionAcceptance")) options.release.set(25) } val permissionAcceptance = tasks.register("permissionAcceptance") { group = "verification" description = "Loads the packaged LuckPerms plugin and verifies native permissions, commands and H2 persistence." dependsOn(tasks.named("installDist"), compilePermissionAcceptance) classpath = sourceSets.main.get().runtimeClasspath + files(compilePermissionAcceptance.flatMap { it.destinationDirectory }) mainClass.set("PermissionAcceptance") args(layout.buildDirectory.dir("install/moonbridge").get().asFile.absolutePath, layout.buildDirectory.dir("permission-acceptance").get().asFile.absolutePath) } tasks.named("check") { dependsOn(permissionAcceptance) } } tasks.named("check") { dependsOn(installedDistSmokeTest) dependsOn(installedDistHelpSmokeTest) dependsOn(installedDistVersionSmokeTest) dependsOn(compileBenchmarks) } application { mainClass.set("dev.moonbridge.app.ProxyMain") applicationName = "moonbridge" // Netty's epoll/kqueue transports load a JNI library; allow it without JDK restricted-method warnings. // Leak detection is off in the distribution; every proxy-core test class runs with PARANOID detection // through LeakGate instead. Re-enable per deployment with JAVA_OPTS=-Dio.netty.leakDetection.level=simple. applicationDefaultJvmArgs = listOf("--enable-native-access=ALL-UNNAMED", "-Dio.netty.leakDetection.level=disabled") } tasks.withType().configureEach { jvmArgs("--enable-native-access=ALL-UNNAMED") // Tests track every buffer so LeakGate can fail on a leak; the distribution runs with detection off. systemProperty("io.netty.leakDetection.level", "paranoid") systemProperty("io.netty.leakDetection.targetRecords", "16") } tasks.jar { manifest.attributes("Implementation-Title" to "MoonBridge", "Implementation-Version" to project.version) } distributions { main { // Only what the proxy needs to run. Docs and test records stay in the repository, and the // backend jar ships separately in build/release/backend (see docs/release-layout.md). contents { from(rootProject.file("README.md")) if (luckPerms != null) { from(luckPerms.tasks.named("pluginJar")) { into("plugins") } } from("src/main/resources/config") { into("config") } } } }