import java.net.URI import java.security.MessageDigest import org.gradle.api.tasks.bundling.Zip plugins { java } group = "games.dmg" version = providers.gradleProperty("releaseVersion").orElse("0.1.0-SNAPSHOT").get() val pluginVersion = version.toString() repositories { mavenCentral() maven("https://repo.purpurmc.org/snapshots/") } java { toolchain { languageVersion = JavaLanguageVersion.of(25) } } tasks.withType().configureEach { options.compilerArgs.addAll(listOf("-Xlint:all,-deprecation,-removal", "-Werror")) } dependencies { compileOnly("org.purpurmc.purpur:purpur-api:26.3.build.2651-stable") compileOnly("net.dmulloy2:ProtocolLib:5.4.0") testImplementation("net.dmulloy2:ProtocolLib:5.4.0") testImplementation("org.purpurmc.purpur:purpur-api:26.3.build.2651-stable") testImplementation(platform("org.junit:junit-bom:5.13.4")) testImplementation("org.junit.jupiter:junit-jupiter") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } val resourcePackInput = layout.buildDirectory.dir("generated/resource-pack-input") val prepareResourcePack = tasks.register("prepareResourcePack") { from("src/resourcePack") into(resourcePackInput) filesMatching("pack.mcmeta") { expand("version" to pluginVersion) } } val sheetResourcePack = tasks.register("sheetResourcePack") { dependsOn(prepareResourcePack) from(resourcePackInput) archiveFileName.set("purpur-fantasy-stick-$pluginVersion-resource-pack.zip") destinationDirectory.set(layout.buildDirectory.dir("distributions")) isPreserveFileTimestamps = false isReproducibleFileOrder = true } val resourcePackMetadata = layout.buildDirectory.dir("generated/resource-pack-metadata") val generateResourcePackMetadata = tasks.register("generateResourcePackMetadata") { dependsOn(sheetResourcePack) inputs.file(sheetResourcePack.flatMap { it.archiveFile }) inputs.property("pluginVersion", pluginVersion) outputs.file(resourcePackMetadata.map { it.file("sheet-resource-pack.properties") }) doLast { val pack = sheetResourcePack.get().archiveFile.get().asFile val sha1 = MessageDigest.getInstance("SHA-1").digest(pack.readBytes()).joinToString("") { "%02x".format(it) } val version = pluginVersion val output = resourcePackMetadata.get().file("sheet-resource-pack.properties").asFile output.parentFile.mkdirs() output.writeText("url=https://git.garvis.dev/dmg/purpur-fantasy-stick/releases/download/v$version/purpur-fantasy-stick-$version-resource-pack.zip\nsha1=$sha1\n") } } sourceSets.main.get().resources.srcDir(resourcePackMetadata) tasks.test { useJUnitPlatform() dependsOn(tasks.jar, sheetResourcePack) systemProperty("distribution.jar", tasks.jar.get().archiveFile.get().asFile.absolutePath) systemProperty("distribution.version", pluginVersion) systemProperty("resource.pack.zip", sheetResourcePack.get().archiveFile.get().asFile.absolutePath) } // Patch the exact supported runtime for non-listening native API tests, as in Purpur Base. val nativeRuntime = layout.buildDirectory.dir("native-runtime") val downloadNativeRuntime = tasks.register("downloadNativeRuntime") { val launcher = nativeRuntime.map { it.file("purpur-26.3-2651.jar") } outputs.file(launcher) doLast { val file = launcher.get().asFile file.parentFile.mkdirs() val connection = URI("https://api.purpurmc.org/v2/purpur/26.3/2651/download").toURL().openConnection() connection.connectTimeout = 30_000 connection.readTimeout = 120_000 val bytes = connection.getInputStream().use { it.readBytes() } val digest = MessageDigest.getInstance("SHA-256").digest(bytes).joinToString("") { "%02x".format(it) } check(digest == "0677c1febecfbc2e5b0a7f76abd647b70a1f38d3cbdf3dd6a82e401b4262a598") { "Purpur 2651 checksum mismatch" } file.writeBytes(bytes) } } val prepareNativeRuntime = tasks.register("prepareNativeRuntime") { dependsOn(downloadNativeRuntime) javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(25) } classpath = files(nativeRuntime.map { it.file("purpur-26.3-2651.jar") }) mainClass = "io.papermc.paperclip.Main" jvmArgs("-Dpaperclip.patchonly=true") workingDir(nativeRuntime) outputs.dir(nativeRuntime.map { it.dir("versions") }) outputs.dir(nativeRuntime.map { it.dir("libraries") }) } val nativeTest = sourceSets.create("nativeTest") dependencies { add(nativeTest.implementationConfigurationName, platform("org.junit:junit-bom:5.13.4")) add(nativeTest.implementationConfigurationName, "org.junit.jupiter:junit-jupiter") add(nativeTest.implementationConfigurationName, "net.dmulloy2:ProtocolLib:5.4.0") add(nativeTest.implementationConfigurationName, "org.mockito:mockito-core:5.18.0") add(nativeTest.compileOnlyConfigurationName, "org.jetbrains:annotations:26.0.2") add(nativeTest.compileOnlyConfigurationName, "org.checkerframework:checker-qual:3.49.2") add(nativeTest.runtimeOnlyConfigurationName, "org.junit.platform:junit-platform-launcher") } val nativeRuntimeJars = files(fileTree(nativeRuntime) { include("versions/**/*.jar", "libraries/**/*.jar") }).builtBy(prepareNativeRuntime) // Pinned output-only packet codec; native classes remain provided by the server, never bundled. sourceSets.main.get().compileClasspath += nativeRuntimeJars nativeTest.compileClasspath += sourceSets.main.get().output + nativeRuntimeJars nativeTest.runtimeClasspath += sourceSets.main.get().output + nativeRuntimeJars val nativeCompatibilityTest = tasks.register("nativeCompatibilityTest") { description = "Verifies packaged metadata and native item serialization without starting a server" dependsOn(tasks.jar, sheetResourcePack) testClassesDirs = nativeTest.output.classesDirs classpath = nativeTest.runtimeClasspath useJUnitPlatform() maxHeapSize = "1G" workingDir(nativeRuntime) systemProperty("distribution.jar", tasks.jar.get().archiveFile.get().asFile.absolutePath) systemProperty("resource.pack.zip", sheetResourcePack.get().archiveFile.get().asFile.absolutePath) } val installReleaseTools = tasks.register("installReleaseTools") { commandLine("npm", "ci", "--ignore-scripts", "--no-audit", "--no-fund") } val releaseToolCheck = tasks.register("releaseToolCheck") { dependsOn(installReleaseTools) commandLine("npm", "test") } tasks.check { dependsOn(nativeCompatibilityTest, releaseToolCheck) } tasks.processResources { dependsOn(generateResourcePackMetadata) inputs.property("pluginVersion", pluginVersion) filesMatching("plugin.yml") { expand("version" to pluginVersion) } }