From 6b8ba8b80b2670b309df3551212ebb17353a25b0 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 11 Sep 2024 18:00:11 +0100 Subject: [PATCH] Shadow netty rather than jar-in-jaring Under Forge, netty-codec lives on the BOOT layer. However, this means it does not have access to our jzlib (which lives on the GAME layer). To fix this, we now shadow netty-codec (and its dependents, like netty-http and netty-proxy) rather than jar-in-jaring them. This involves some horrible build logic, but means websocket compression works on Forge. Fixes #1958. --- gradle/libs.versions.toml | 5 ++++- projects/core/build.gradle.kts | 20 ++++++++++++++++++++ projects/forge/build.gradle.kts | 31 ++++++++++++++++++------------- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1510581d89..ac6263d683 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -71,6 +71,7 @@ librarian = "1.+" lwjgl = "3.3.3" minotaur = "2.+" nullAway = "0.10.25" +shadow = "8.3.1" spotless = "6.23.3" taskTree = "2.1.1" teavm = "0.11.0-SQUID.1" @@ -94,9 +95,10 @@ jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" } kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" } kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } +netty-codec = { module = "io.netty:netty-codec", version.ref = "netty" } netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" } -netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" } netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" } +netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" } nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" } nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" } slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } @@ -175,6 +177,7 @@ githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "g gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" } kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" } +shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" } versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" } diff --git a/projects/core/build.gradle.kts b/projects/core/build.gradle.kts index f579159a80..e976ce5349 100644 --- a/projects/core/build.gradle.kts +++ b/projects/core/build.gradle.kts @@ -7,6 +7,7 @@ import cc.tweaked.gradle.getAbsolutePath plugins { `java-library` `java-test-fixtures` + alias(libs.plugins.shadow) id("cc-tweaked.kotlin-convention") id("cc-tweaked.java-convention") @@ -57,3 +58,22 @@ val checkChangelog by tasks.registering(cc.tweaked.gradle.CheckChangelog::class) } tasks.check { dependsOn(checkChangelog) } + +// We configure the shadow jar to ship netty-codec and all its dependencies, relocating them under the +// dan200.computercraft.core package. +// This is used as part of the Forge build, so that our version of netty-codec is loaded under the GAME layer, and so +// has access to our jar-in-jar'ed jzlib. +tasks.shadowJar { + minimize() + + dependencies { + include(dependency(libs.netty.codec.get())) + include(dependency(libs.netty.http.get())) + include(dependency(libs.netty.socks.get())) + include(dependency(libs.netty.proxy.get())) + } + + for (pkg in listOf("io.netty.handler.codec", "io.netty.handler.proxy")) { + relocate(pkg, "dan200.computercraft.core.vendor.$pkg") + } +} diff --git a/projects/forge/build.gradle.kts b/projects/forge/build.gradle.kts index a1454b5df2..1457aae787 100644 --- a/projects/forge/build.gradle.kts +++ b/projects/forge/build.gradle.kts @@ -105,6 +105,10 @@ minecraft { configurations { minecraftLibrary { extendsFrom(minecraftEmbed.get()) } + // Move minecraftLibrary/minecraftEmbed out of implementation, and into runtimeOnly. + implementation { setExtendsFrom(extendsFrom - setOf(minecraftLibrary.get(), minecraftEmbed.get())) } + runtimeOnly { extendsFrom(minecraftLibrary.get(), minecraftEmbed.get()) } + val testMinecraftLibrary by registering { isCanBeResolved = true isCanBeConsumed = false @@ -138,18 +142,11 @@ dependencies { minecraftEmbed(libs.jzlib) { jarJar.ranged(this, "[${libs.versions.jzlib.get()},)") } - minecraftEmbed(libs.netty.http) { - jarJar.ranged(this, "[${libs.versions.netty.get()},)") - isTransitive = false - } - minecraftEmbed(libs.netty.socks) { - jarJar.ranged(this, "[${libs.versions.netty.get()},)") - isTransitive = false - } - minecraftEmbed(libs.netty.proxy) { - jarJar.ranged(this, "[${libs.versions.netty.get()},)") - isTransitive = false - } + // We don't jar-in-jar our additional netty dependencies (see the tasks.jarJar configuration), but still want them + // on the legacy classpath. + minecraftLibrary(libs.netty.http) { isTransitive = false } + minecraftLibrary(libs.netty.socks) { isTransitive = false } + minecraftLibrary(libs.netty.proxy) { isTransitive = false } testFixturesApi(libs.bundles.test) testFixturesApi(libs.bundles.kotlin) @@ -195,9 +192,17 @@ tasks.sourcesJar { tasks.jarJar { finalizedBy("reobfJarJar") archiveClassifier.set("") + duplicatesStrategy = DuplicatesStrategy.FAIL + // Include all classes from other projects except core. + val coreSources = project(":core").sourceSets["main"] for (source in cct.sourceDirectories.get()) { - if (source.classes) from(source.sourceSet.output) + if (source.classes && source.sourceSet != coreSources) from(source.sourceSet.output) + } + + // Include core separately, along with the relocated netty classes. + from(zipTree(project(":core").tasks.named("shadowJar", AbstractArchiveTask::class).map { it.archiveFile })) { + exclude("META-INF/**") } }