buildscript { repositories { jcenter() maven { name "Modmuss50 Repository" url 'https://maven.modmuss50.me' } } dependencies { classpath "net.fabricmc:weave:0.2.0.+" classpath "net.fabricmc:stitch:0.1.0.23+" classpath "commons-io:commons-io:1.4" classpath "com.google.guava:guava:19.0" classpath 'de.undercouch:gradle-download-task:3.4.3' classpath 'net.fabricmc:tiny-remapper:+' } } plugins { id 'de.undercouch.download' version '3.4.3' id 'maven' id 'maven-publish' } def minecraft_version = "18w50a" def ENV = System.getenv() // Fetch build number from Jenkins def build_number = ENV.BUILD_NUMBER ?: "local" def yarnVersion = "${minecraft_version}.$build_number" repositories { mavenCentral() maven { name "Modmuss50 Repository" url 'https://maven.modmuss50.me' } } configurations { enigmaRuntime { resolutionStrategy { cacheDynamicVersionsFor 0, "seconds" cacheChangingModulesFor 0, "seconds" } } } dependencies { enigmaRuntime "net.fabricmc:stitch:0.1.0.23+" enigmaRuntime "cuchaz:enigma:0.12.2.+:all" } def mappingsDir = file("mappings") def cacheFilesMinecraft = file(".gradle/minecraft") def tempDir = file(".gradle/temp") def mergedFile = file("${minecraft_version}-merged.jar") def mappedFile = file("${minecraft_version}-mapped.jar") def versionFile = new File(cacheFilesMinecraft, "${minecraft_version}.json") def clientJar = new File(cacheFilesMinecraft, "${minecraft_version}-client.jar") def serverJar = new File(cacheFilesMinecraft, "${minecraft_version}-server.jar") def libraries = new File(cacheFilesMinecraft, "${minecraft_version}-libraries") def libs = new File("build/libs/") import groovy.json.JsonSlurper import org.apache.commons.io.FileUtils import com.google.common.hash.Hashing import com.google.common.io.Files import net.fabricmc.stitch.commands.CommandMergeTiny import net.fabricmc.stitch.merge.JarMerger import net.fabricmc.tinyremapper.OutputConsumerPath import net.fabricmc.tinyremapper.TinyRemapper import net.fabricmc.tinyremapper.TinyUtils import net.fabricmc.weave.CommandTinyify import net.fabricmc.weave.CommandFindMappingErrors import groovy.io.FileType import java.util.zip.GZIPOutputStream boolean validateChecksum(File file, String checksum) { if (file != null) { def hash = Files.hash(file, Hashing.sha1()) def builder = new StringBuilder() hash.asBytes().each { builder.append(Integer.toString((it & 0xFF) + 0x100, 16).substring(1)) } return builder.toString().equals(checksum) } return false } task downloadVersionsManifest { //inputs.property "mc_ver", minecraft_version inputs.property "currenttime", new Date() def manifestFile = new File(cacheFilesMinecraft, "version_manifest.json") outputs.file(manifestFile) doLast { logger.lifecycle(":downloading minecraft versions manifest") FileUtils.copyURLToFile(new URL("https://launchermeta.mojang.com/mc/game/version_manifest.json"), manifestFile) } } def getManifestVersion(File manifestFile, String minecraft_version) { def manifest = manifestFile.exists() ? new JsonSlurper().parseText(FileUtils.readFileToString(manifestFile)) : null return manifest != null ? manifest.versions.stream().filter({it.id.equals(minecraft_version)}).findFirst() : java.util.Optional.empty() } task downloadWantedVersionManifest(dependsOn: downloadVersionsManifest) { def manifestFile = downloadVersionsManifest.outputs.files.singleFile def manifestVersion = getManifestVersion(manifestFile, minecraft_version) //have to grab the release time as there's a current timestamp on each element?! inputs.property "releaseTime", manifestVersion.isPresent() ? manifestVersion.get().releaseTime : -1 outputs.file versionFile doLast { manifestVersion = getManifestVersion(manifestFile, minecraft_version) //nb need to re-read here in case it didn't exist before if (manifestVersion.isPresent() || versionFile.exists()) { if (manifestVersion.isPresent()) { FileUtils.copyURLToFile(new URL(manifestVersion.get().url), versionFile) } } else { throw new RuntimeException("No version data for Minecraft version ${minecraft_version}") } } } task downloadMcJars(dependsOn: downloadWantedVersionManifest) { inputs.files versionFile outputs.files(clientJar, serverJar) outputs.upToDateWhen { def version = new JsonSlurper().parseText(FileUtils.readFileToString(versionFile)) return clientJar.exists() && serverJar.exists() && validateChecksum(clientJar, version.downloads.client.sha1) && validateChecksum(serverJar, version.downloads.server.sha1) } doLast { if (!versionFile.exists()) { throw new RuntimeException("Can't download the jars without the ${versionFile.name} file!") } //reload in case it changed def version = new JsonSlurper().parseText(FileUtils.readFileToString(versionFile)) logger.lifecycle(":downloading minecraft jars") if (!clientJar.exists() || !validateChecksum(clientJar, version.downloads.client.sha1)) { logger.lifecycle(":downloading minecraft client") FileUtils.copyURLToFile(new URL(version.downloads.client.url), clientJar) } if (!serverJar.exists() || !validateChecksum(serverJar, version.downloads.server.sha1)) { logger.lifecycle(":downloading minecraft server") FileUtils.copyURLToFile(new URL(version.downloads.server.url), serverJar) } } } task mergeJars(dependsOn: downloadMcJars) { inputs.files downloadMcJars.outputs.files.files outputs.file(mergedFile) doLast { logger.lifecycle(":merging jars") def client = new FileInputStream(inputs.files.files.find {it.name.endsWith("-client.jar")}) def server = new FileInputStream(inputs.files.files.find {it.name.endsWith("-server.jar")}) def merged = new FileOutputStream(mergedFile) def jarMerger = new JarMerger(client, server, merged) jarMerger.merge() jarMerger.close() client.close() server.close() merged.close() } } task setupYarn(dependsOn: mergeJars) { } task yarn(dependsOn: setupYarn) { doLast { ant.java( classname: 'cuchaz.enigma.Main', classpath: configurations.enigmaRuntime.asPath, fork: true, spawn: true ) { arg(value: mergedFile.getAbsolutePath()) arg(value: mappingsDir.getAbsolutePath()) } } } task buildEnigma(type: Zip) { from mappingsDir include "**/*" archiveName "yarn-enigma-${yarnVersion}.zip" destinationDir(file("build/libs")) } task checkMappings { inputs.dir mappingsDir doLast { logger.lifecycle(":checking mappings") String[] args = [ mergedFile.getAbsolutePath(), mappingsDir.getAbsolutePath() ] new CommandFindMappingErrors().run(args) } } task downloadIntermediary(type: Download){ src "https://github.com/FabricMC/intermediary/raw/master/mappings/${minecraft_version}.tiny" dest new File(cacheFilesMinecraft, "${minecraft_version}-intermediary.tiny") } task buildYarnTiny(dependsOn: "mergeJars",type: FileOutput) { inputs.dir mappingsDir if (!libs.exists()) { libs.mkdirs() } def yarnTiny = new File(tempDir, "yarn-mappings.tiny") fileOutput = yarnTiny outputs.upToDateWhen {return false} doLast { logger.lifecycle(":generating tiny mappings") String[] args = [ mergedFile.getAbsolutePath(), mappingsDir.getAbsolutePath(), yarnTiny.getAbsolutePath(), "official", "named" ] new CommandTinyify().run(args) } } task mergeTiny(dependsOn: ["buildYarnTiny", "downloadIntermediary"], type: FileOutput) { def yarnTinyInput = buildYarnTiny.fileOutput def intermediaryTinyInput = downloadIntermediary.dest def outputFile = new File(tempDir, "mappings.tiny") outputs.file(outputFile) fileOutput = outputFile outputs.upToDateWhen {return false} doLast { logger.lifecycle(":merging yarn and intermediary") String[] args = [ yarnTinyInput.getAbsolutePath(), intermediaryTinyInput.getAbsolutePath(), outputFile.getAbsolutePath(), "intermediary", "official" ] new CommandMergeTiny().run(args) } } task tinyJar(type: Jar, dependsOn: "mergeTiny") { outputs.upToDateWhen {return false} archiveName = "yarn-${yarnVersion}.jar" destinationDir(file("build/libs")) classifier = "" from (mergeTiny.fileOutput) { rename { "mappings/mappings.tiny" } } } task compressTiny(dependsOn: ["tinyJar", "mergeTiny"], type: FileOutput){ def outputFile = new File(libs, "yarn-tiny-${yarnVersion}.gz") outputs.file(outputFile) fileOutput = outputFile def inputFile = mergeTiny.fileOutput outputs.upToDateWhen {return false} doLast { logger.lifecycle(":compressing tiny mappings") def buffer = new byte[1024] def fileOutputStream = new FileOutputStream(outputFile) def outputStream = new GZIPOutputStream(fileOutputStream) def fileInputStream = new FileInputStream(inputFile) def length while ((length = fileInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, length) } fileInputStream.close() outputStream.finish() outputStream.close() inputFile.delete() } } clean.doFirst { delete tempDir, cacheFilesMinecraft } tasks.build.dependsOn "compressTiny" tasks.build.dependsOn "buildEnigma" tasks.build.dependsOn "tinyJar" task downloadMcLibs(dependsOn: downloadWantedVersionManifest) { inputs.files versionFile outputs.file(libraries) outputs.upToDateWhen { return false } doLast { if (!versionFile.exists()) { throw new RuntimeException("Can't download the jars without the ${versionFile.name} file!") } def version = new JsonSlurper().parseText(FileUtils.readFileToString(versionFile)) logger.lifecycle(":downloading minecraft libraries") if (!libraries.exists()) { libraries.mkdirs() } version.libraries.each { def downloadUrl = it.downloads.artifact.url download { src downloadUrl dest new File(libraries, downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1)) overwrite false } } } } task mapJar(dependsOn: [downloadMcLibs, build]) { inputs.files downloadMcLibs.outputs.files.files outputs.file(mappedFile) //Force the task to always run outputs.upToDateWhen { return false } doLast { logger.lifecycle(":mapping minecraft") if (mappedFile.exists()) { mappedFile.delete() } def tinyInput = new File("build/libs/yarn-tiny-${yarnVersion}.gz").toPath() def remapper = TinyRemapper.newRemapper() .withMappings(TinyUtils.createTinyMappingProvider(tinyInput, "official", "named")) .build() try { def outputConsumer = new OutputConsumerPath(mappedFile.toPath()) outputConsumer.addNonClassFiles(mergedFile.toPath()) remapper.read(mergedFile.toPath()) libraries.eachFileRecurse(FileType.FILES) {file -> remapper.read(file.toPath()) } remapper.apply(mergedFile.toPath(), outputConsumer) outputConsumer.finish() remapper.finish() } catch (Exception e) { remapper.finish(); throw new RuntimeException("Failed to remap jar", e); } } } publishing { publications { maven(MavenPublication) { groupId 'net.fabricmc' artifactId "yarn" version yarnVersion artifact (compressTiny.fileOutput) { classifier "tiny" builtBy compressTiny } artifact (buildEnigma) { classifier "enigma" } artifact (tinyJar) } } repositories { maven { url "http://mavenupload.modmuss50.me/" if (project.hasProperty('mavenPass')) { credentials { username 'buildslave' password project.getProperty('mavenPass') } } } } } class FileOutput extends DefaultTask { @OutputFile File fileOutput }