import io.papermc.paperweight.attribute.DevBundleOutput import io.papermc.paperweight.util.* import io.papermc.paperweight.util.data.FileEntry import paper.libs.com.google.gson.annotations.SerializedName import java.time.Instant import kotlin.io.path.readText plugins { `java-library` `maven-publish` idea id("io.papermc.paperweight.core") } val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" dependencies { mache("io.papermc:mache:1.21.5+build.1") paperclip("io.papermc:paperclip:3.0.3") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } paperweight { minecraftVersion = providers.gradleProperty("mcVersion") gitFilePatches = false //updatingMinecraft { // oldPaperCommit = "f4f275519f7c1fbe9db173b7144a4fe81440e365" //} spigot { buildDataRef = "702e1a0a5072b2c4082371d5228cb30525687efc" packageVersion = "v1_21_R4" // also needs to be updated in MappingEnvironment } reobfPackagesToFix.addAll( "co.aikar.timings", "com.destroystokyo.paper", "com.mojang", "io.papermc.paper", "ca.spottedleaf", "net.kyori.adventure.bossbar", "net.minecraft", "org.bukkit.craftbukkit", "org.spigotmc", ) } tasks.generateDevelopmentBundle { libraryRepositories.addAll( "https://repo.maven.apache.org/maven2/", paperMavenPublicUrl, ) } abstract class Services { @get:Inject abstract val softwareComponentFactory: SoftwareComponentFactory @get:Inject abstract val archiveOperations: ArchiveOperations } val services = objects.newInstance() if (project.providers.gradleProperty("publishDevBundle").isPresent) { val devBundleComponent = services.softwareComponentFactory.adhoc("devBundle") components.add(devBundleComponent) val devBundle = configurations.consumable("devBundle") { attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.ZIP)) outgoing.artifact(tasks.generateDevelopmentBundle.flatMap { it.devBundleFile }) } devBundleComponent.addVariantsFromConfiguration(devBundle.get()) {} val runtime = configurations.consumable("serverRuntimeClasspath") { attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.SERVER_DEPENDENCIES)) attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) extendsFrom(configurations.runtimeClasspath.get()) } devBundleComponent.addVariantsFromConfiguration(runtime.get()) { mapToMavenScope("runtime") } val compile = configurations.consumable("serverCompileClasspath") { attributes.attribute(DevBundleOutput.ATTRIBUTE, objects.named(DevBundleOutput.SERVER_DEPENDENCIES)) attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API)) extendsFrom(configurations.compileClasspath.get()) } devBundleComponent.addVariantsFromConfiguration(compile.get()) { mapToMavenScope("compile") } tasks.withType(GenerateMavenPom::class).configureEach { doLast { val text = destination.readText() // Remove dependencies from pom, dev bundle is designed for gradle module metadata consumers destination.writeText( text.substringBefore("") + text.substringAfter("") ) } } publishing { publications.create("devBundle") { artifactId = "dev-bundle" from(devBundleComponent) } } } val log4jPlugins = sourceSets.create("log4jPlugins") configurations.named(log4jPlugins.compileClasspathConfigurationName) { extendsFrom(configurations.compileClasspath.get()) } val alsoShade: Configuration by configurations.creating val runtimeConfiguration by configurations.consumable("runtimeConfiguration") { attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) } // Configure mockito agent that is needed in newer java versions val mockitoAgent = configurations.register("mockitoAgent") abstract class MockitoAgentProvider : CommandLineArgumentProvider { @get:CompileClasspath abstract val fileCollection: ConfigurableFileCollection override fun asArguments(): Iterable { return listOf("-javaagent:" + fileCollection.files.single().absolutePath) } } dependencies { implementation(project(":paper-api")) implementation("ca.spottedleaf:concurrentutil:0.0.3") implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 implementation("net.minecrell:terminalconsoleappender:1.3.0") implementation("io.papermc.adventure:adventure-text-serializer-ansi:4.21.0-mc1215-SNAPSHOT") // Keep in sync with adventureVersion from Paper-API build file // FIXME back to release runtimeConfiguration(sourceSets.main.map { it.runtimeClasspath }) /* Required to add the missing Log4j2Plugins.dat file from log4j-core which has been removed by Mojang. Without it, log4j has to classload all its classes to check if they are plugins. Scanning takes about 1-2 seconds so adding this speeds up the server start. */ implementation("org.apache.logging.log4j:log4j-core:2.24.1") log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.24.1") // Needed to generate meta for our Log4j plugins runtimeOnly(log4jPlugins.output) alsoShade(log4jPlugins.output) implementation("com.velocitypowered:velocity-native:3.4.0-SNAPSHOT") { isTransitive = false } implementation("io.netty:netty-codec-haproxy:4.1.118.Final") // Add support for proxy protocol implementation("org.apache.logging.log4j:log4j-iostreams:2.24.1") implementation("org.ow2.asm:asm-commons:9.8") implementation("org.spongepowered:configurate-yaml:4.2.0-20250225.064233-199") implementation("org.spongepowered:configurate-core:4.2.0-20250225.064233-204") // Pinned dependency of above pinned yaml snapshot. // Deps that were previously in the API but have now been moved here for backwards compat, eventually to be removed runtimeOnly("commons-lang:commons-lang:2.6") runtimeOnly("org.xerial:sqlite-jdbc:3.49.1.0") runtimeOnly("com.mysql:mysql-connector-j:9.2.0") runtimeOnly("com.lmax:disruptor:3.4.4") runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6") runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") testImplementation("io.github.classgraph:classgraph:4.8.179") // For mob goal test testImplementation("org.junit.jupiter:junit-jupiter:5.12.2") testImplementation("org.junit.platform:junit-platform-suite-engine:1.12.2") testImplementation("org.hamcrest:hamcrest:2.2") testImplementation("org.mockito:mockito-core:5.14.1") mockitoAgent("org.mockito:mockito-core:5.14.1") { isTransitive = false } // Configure mockito agent that is needed in newer java versions testImplementation("org.ow2.asm:asm-tree:9.8") testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // CartesianTest implementation("net.neoforged:srgutils:1.0.9") // Mappings handling implementation("net.neoforged:AutoRenamingTool:2.0.3") // Remap plugins // Remap reflection val reflectionRewriterVersion = "0.0.3" implementation("io.papermc:reflection-rewriter:$reflectionRewriterVersion") implementation("io.papermc:reflection-rewriter-runtime:$reflectionRewriterVersion") implementation("io.papermc:reflection-rewriter-proxy-generator:$reflectionRewriterVersion") // Spark implementation("me.lucko:spark-api:0.1-20240720.200737-2") implementation("me.lucko:spark-paper:1.10.133-20250413.112336-1") } tasks.jar { manifest { val git = Git(rootProject.layout.projectDirectory.path) val mcVersion = rootProject.providers.gradleProperty("mcVersion").get() val build = System.getenv("BUILD_NUMBER") ?: null val buildTime = if (build != null) Instant.now() else Instant.EPOCH val gitHash = git.exec(providers, "rev-parse", "--short=7", "HEAD").get().trim() val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash" val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim() val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() attributes( "Main-Class" to "org.bukkit.craftbukkit.Main", "Implementation-Title" to "Paper", "Implementation-Version" to implementationVersion, "Implementation-Vendor" to date, "Specification-Title" to "Paper", "Specification-Version" to project.version, "Specification-Vendor" to "Paper Team", "Brand-Id" to "papermc:paper", "Brand-Name" to "Paper", "Build-Number" to (build ?: ""), "Build-Time" to buildTime.toString(), "Git-Branch" to gitBranch, "Git-Commit" to gitHash, ) for (tld in setOf("net", "com", "org")) { attributes("$tld/bukkit", "Sealed" to true) } } } // Compile tests with -parameters for better junit parameterized test names tasks.compileTestJava { options.compilerArgs.add("-parameters") } val scanJarForBadCalls by tasks.registering(io.papermc.paperweight.tasks.ScanJarForBadCalls::class) { badAnnotations.add("Lio/papermc/paper/annotation/DoNotUse;") jarToScan.set(tasks.jar.flatMap { it.archiveFile }) classpath.from(configurations.compileClasspath) } tasks.check { dependsOn(scanJarForBadCalls) } // Use TCA for console improvements tasks.jar { val archiveOperations = services.archiveOperations from(alsoShade.elements.map { it.map { f -> if (f.asFile.isFile) { archiveOperations.zipTree(f.asFile) } else { f.asFile } } }) } tasks.test { include("**/**TestSuite.class") workingDir = temporaryDir useJUnitPlatform { forkEvery = 1 excludeTags("Slow") } // Configure mockito agent that is needed in newer java versions val provider = objects.newInstance() provider.fileCollection.from(mockitoAgent) jvmArgumentProviders.add(provider) } val generatedDir: java.nio.file.Path = layout.projectDirectory.dir("src/generated/java").asFile.toPath() idea { module { generatedSourceDirs.add(generatedDir.toFile()) } } sourceSets { main { java { srcDir(generatedDir) } } } if (providers.gradleProperty("updatingMinecraft").getOrElse("false").toBoolean()) { val scanJarForOldGeneratedCode by tasks.registering(io.papermc.paperweight.tasks.ScanJarForOldGeneratedCode::class) { mcVersion.set(providers.gradleProperty("mcVersion")) annotation.set("Lio/papermc/paper/generated/GeneratedFrom;") jarToScan.set(tasks.jar.flatMap { it.archiveFile }) classpath.from(configurations.compileClasspath) } tasks.check { dependsOn(scanJarForOldGeneratedCode) } } fun TaskContainer.registerRunTask( name: String, block: JavaExec.() -> Unit ): TaskProvider = register(name) { group = "runs" mainClass.set("org.bukkit.craftbukkit.Main") standardInput = System.`in` workingDir = rootProject.layout.projectDirectory .dir(providers.gradleProperty("paper.runWorkDir").getOrElse("run")) .asFile javaLauncher.set(project.javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(21)) vendor.set(JvmVendorSpec.JETBRAINS) }) jvmArgs("-XX:+AllowEnhancedClassRedefinition") if (rootProject.childProjects["test-plugin"] != null) { val testPluginJar = rootProject.project(":test-plugin").tasks.jar.flatMap { it.archiveFile } inputs.file(testPluginJar) args("-add-plugin=${testPluginJar.get().asFile.absolutePath}") } args("--nogui") systemProperty("net.kyori.adventure.text.warnWhenLegacyFormattingDetected", true) if (providers.gradleProperty("paper.runDisableWatchdog").getOrElse("false") == "true") { systemProperty("disable.watchdog", true) } systemProperty("io.papermc.paper.suppress.sout.nags", true) val memoryGb = providers.gradleProperty("paper.runMemoryGb").getOrElse("2") minHeapSize = "${memoryGb}G" maxHeapSize = "${memoryGb}G" doFirst { workingDir.mkdirs() } block(this) } tasks.registerRunTask("runServer") { description = "Spin up a test server from the Mojang mapped server jar" classpath(tasks.includeMappings.flatMap { it.outputJar }) classpath(configurations.runtimeClasspath) } tasks.registerRunTask("runReobfServer") { description = "Spin up a test server from the reobfJar output jar" classpath(tasks.reobfJar.flatMap { it.outputJar }) classpath(configurations.runtimeClasspath) } tasks.registerRunTask("runDevServer") { description = "Spin up a test server without assembling a jar" classpath(sourceSets.main.map { it.runtimeClasspath }) } tasks.registerRunTask("runBundler") { description = "Spin up a test server from the Mojang mapped bundler jar" classpath(tasks.createMojmapBundlerJar.flatMap { it.outputZip }) mainClass.set(null as String?) } tasks.registerRunTask("runReobfBundler") { description = "Spin up a test server from the reobf bundler jar" classpath(tasks.createReobfBundlerJar.flatMap { it.outputZip }) mainClass.set(null as String?) } tasks.registerRunTask("runPaperclip") { description = "Spin up a test server from the Mojang mapped Paperclip jar" classpath(tasks.createMojmapPaperclipJar.flatMap { it.outputZip }) mainClass.set(null as String?) } tasks.registerRunTask("runReobfPaperclip") { description = "Spin up a test server from the reobf Paperclip jar" classpath(tasks.createReobfPaperclipJar.flatMap { it.outputZip }) mainClass.set(null as String?) }