buildscript { repositories { mavenLocal() maven { url = 'http://files.minecraftforge.net/maven' } jcenter() mavenCentral() } dependencies { classpath 'net.minecraftforge.gradle:ForgeGradle:3.+' } } import groovy.json.JsonSlurper import groovy.json.JsonBuilder import java.text.SimpleDateFormat import java.util.Date import java.security.MessageDigest import java.net.URL import net.minecraftforge.gradle.common.task.SignJar import org.apache.tools.ant.filters.ReplaceTokens import de.undercouch.gradle.tasks.download.Download plugins { id 'net.minecrell.licenser' version '0.4' id 'org.ajoberstar.grgit' version '2.3.0' id 'de.undercouch.download' version '3.3.0' } apply plugin: 'eclipse' group = 'net.minecraftforge' version = '1.0.0' project(':mcp') { apply plugin: 'net.minecraftforge.gradle.forgedev.mcp' mcp { config = 'de.oceanlabs.mcp:mcp_config:1.13-2018.09.12.04.11.00@zip' pipeline = 'joined' } } project(':clean') { evaluationDependsOn(':mcp') apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle.forgedev.patcher' repositories { mavenCentral() } patcher { parent = project(':mcp') patchedSrc = file('src/main/java') mappings channel: 'snapshot', version: '20180921-1.13' mcVersion = '1.13' } task runclient(type: JavaExec) { doFirst { mkdir 'runclient' } classpath sourceSets.main.runtimeClasspath args = ['--accessToken', '0', '--version', '1.13'] main 'net.minecraft.client.main.Main' workingDir 'runclient' } } project(':forge') { evaluationDependsOn(':clean') apply plugin: 'java-library' apply plugin: 'maven-publish' apply plugin: 'eclipse' apply plugin: 'net.minecraftforge.gradle.forgedev.patcher' apply plugin: 'net.minecrell.licenser' apply plugin: 'de.undercouch.download' compileJava.sourceCompatibility = compileJava.targetCompatibility = sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. sourceSets { main { java { srcDir "$rootDir/src/main/java" } resources { srcDir "$rootDir/src/main/resources" } } } repositories { mavenLocal() mavenCentral() } patcher { parent = project(':clean') patches = file("$rootDir/patches/minecraft") patchedSrc = file('src/main/java') accessTransformer = file("$rootDir/src/main/resources/forge_at.cfg") exc = file("$rootDir/src/main/resources/forge.exc") srgPatches = true clientRun { main = 'net.minecraftforge.fml.LaunchTesting' environment = [ target: 'fmldevclient' ] properties = [ target: 'fmldevclient', assetDirectory: downloadAssets.output ] } serverRun { main = 'net.minecraftforge.fml.LaunchTesting' environment = [ target: 'fmldevserver' ] } mcVersion = '1.13' } group = 'net.minecraftforge' version = getVersionFromJava(file("$rootDir/src/main/java/net/minecraftforge/common/ForgeVersion.java"), patcher.mcVersion) applyPatches { canonicalizeAccess true canonicalizeWhitespace true maxFuzz 3 } dependencies { api 'net.minecraft:client:1.13:extra' api 'org.ow2.asm:asm:6.2' api 'org.ow2.asm:asm-commons:6.2' api 'org.ow2.asm:asm-tree:6.2' api 'cpw.mods:modlauncher:0.1.0' api 'net.minecraftforge:accesstransformers:0.10+:shadowed' api 'net.minecraftforge:eventbus:0.1+:service' api 'net.minecraftforge:forgespi:0.1+' api 'net.minecraftforge:coremods:0.1+' api 'com.electronwill.night-config:core:3.4.0' api 'com.electronwill.night-config:toml:3.4.0' api 'org.jline:jline:3.5.1' api 'org.apache.maven:maven-artifact:3.5.3' api 'java3d:vecmath:1.5.2' } task runclient(type: JavaExec, dependsOn: [":forge:downloadAssets", ":forge:extractNatives"]) { doFirst { mkdir 'runclient' } doFirst { copy { from sourceSets.main.resources into "$buildDir/classes/java/main" } } //jvmArgs = ['-verbose:class'] classpath sourceSets.main.runtimeClasspath main 'net.minecraftforge.fml.LaunchTesting' systemProperties = [ "org.lwjgl.util.Debug": "true", "org.lwjgl.util.DebugLoader": "true" ] environment += [ target:'fmldevclient', assetDirectory: file("${gradle.getGradleUserHomeDir()}/caches/forge_gradle/assets/"), nativesDirectory: extractNatives.output ] workingDir 'runclient' } task runserver(type: JavaExec) { doFirst { mkdir 'runserver' } classpath sourceSets.main.runtimeClasspath main 'net.minecraftforge.fml.LaunchTesting' args 'nogui' environment target:'fmldevserver' workingDir 'runserver' } task ciWriteBuildNumber { doLast { def file = file("$rootDir/src/main/java/net/minecraftforge/common/ForgeVersion.java") def bn = System.getenv('BUILD_NUMBER') ?: project.ext.properties.buildNumber ?: 0 def outfile = '' file.eachLine{ String s -> if (s.matches('^ public static final int buildVersion = [\\d]+;\$')) s = " public static final int buildVersion = ${bn};" if (s.matches('^ public static final String mcVersion = "[^\\"]+";')) s = " public static final String mcVersion = \"${patcher.mcVersion}\";" outfile += (s+'\n') } file.write(outfile) } } def extraTxts = [ rootProject.file('CREDITS.txt'), rootProject.file('LICENSE.txt') ] /* TODO: Changelog if (project.hasProperty('forgeJenkinsPass')) extraTxts += changelog */ task downloadCrowdin() { ext { output = file('build/crowdin_raw.zip') update = file('build/crowdin.json') id = 'minecraft-forge' } onlyIf { project.hasProperty('crowdinKey') && !project.gradle.startParameter.isOffline() } doLast { download { src "https://api.crowdin.com/api/project/${id}/export?key=${project.crowdinKey}&json" dest update overwrite true } if (!update.text.contains('success')) { throw new RuntimeException("Crowdin export failed, see ${update} for more info") } download { src "https://api.crowdin.com/api/project/${id}/download/all.zip?key=${project.crowdinKey}" dest output overwrite true } } } task crowdin(type: Zip) { dependsOn downloadCrowdin baseName = project.name version = project.version classifier = 'crowdin' destinationDir = file('build/distributions') from(zipTree(downloadCrowdin.output)){ eachFile { //Tired of waiting for crowdin API, rename things myself. Remove once crowdin stops being dumb if (it.name.equals('en_us.json') && !it.path.startsWith('assets/')) { it.name = it.path.split('/')[0] + '.json' it.path = 'assets/forge/lang/' + it.name } } exclude { it.isDirectory() } rename { it.toLowerCase() }//Minecraft needs it lowercase. exclude '**/*.lang' //Pre-1.13 format } } task launcherJson() { ext { output = file('build/libs/version.json') vanilla = project(':mcp').file('build/mcp/downloadJson/version.json') timestamp = dateToIso8601(new Date()) comment = [ "Please do not automate the download and installation of Forge.", "Our efforts are supported by ads from the download page.", "If you MUST automate this, please consider supporting the project through https://www.patreon.com/LexManos/" ] } inputs.file vanilla outputs.file output doLast { def json_vanilla = new JsonSlurper().parseText(vanilla.text) def json = [ _comment_: comment, id: project.version.split('-')[0] + '-forge-' + project.version.split('-')[1], time: timestamp, releaseTime: timestamp, type: 'release', mainClass: 'cpw.mods.modlauncher.Launcher', inheritsFrom: patcher.mcVersion, logging: [], arguments: [ game: json_vanilla.arguments.game + ['--launchTarget', 'fmlclient'] ], libraries: [ [ name: "${project.group}:${project.name}:${project.version}" ] ] ] //TODO: There should be a way to mark this in the config declaration... def forge = [ 'cpw.mods:modlauncher', 'org.ow2.asm:asm', 'org.ow2.asm:asm-commons', 'org.ow2.asm:asm-tree', 'net.minecraftforge:accesstransformers', 'net.minecraftforge:eventbus', 'net.minecraftforge:forgespi', 'net.minecraftforge:coremods', 'com.electronwill.night-config:core', 'com.electronwill.night-config:toml', 'org.jline:jline', 'org.apache.maven:maven-artifact', 'java3d:vecmath' ] def mojang = [] def artifacts = getArtifacts(project, project.configurations.compileClasspath) artifacts.each { key, lib -> if (forge.contains(key) || mojang.contains(key)){ json.libraries.add(lib) } } output.text = new JsonBuilder(json).toPrettyString() } } task installerJson() { ext { output = file('build/libs/install_profile.json') } dependsOn launcherJson inputs.file launcherJson.output outputs.file output doLast { def idx = project.version.indexOf('-') def json = [ _comment_: launcherJson.comment, profile: project.name, version: project.version.substring(0, idx) + "-${project.name}" + project.version.substring(idx), json: '/version.json', path: "${project.group}:${project.name}:${project.version}", logo: '/big_logo.png', minecraft: patcher.mcVersion, welcome: "Welcome to the simple ${project.name.capitalize()} installer.", processors: [], data: [ MAPPINGS: [ client: '/data/joined.tsrg', server: '/data/joined.tsrg' ], BINPATCH: [ client: '/data/client.lzma', server: '/data/server.lzma' ], MC_SLIM: [ client: "[net.minecraft:client:${patcher.mcVersion}:slim]", server: "[net.minecraft:server:${patcher.mcVersion}:slim]" ], MC_DATA: [ client: "[net.minecraft:client:${patcher.mcVersion}:data]", server: "[net.minecraft:server:${patcher.mcVersion}:data]" ], MC_EXTRA: [ client: "[net.minecraft:client:${patcher.mcVersion}:extra]", server: "[net.minecraft:server:${patcher.mcVersion}:extra]" ], PATCHED: [ client: "[${project.group}:${project.name}:${project.version}:client-patched]", server: "[${project.group}:${project.name}:${project.version}:server-patched]" ], REMAPPED: [ client: "[${project.group}:${project.name}:${project.version}:client-srg]", server: "[${project.group}:${project.name}:${project.version}:server-srg]" ] ] ] def libs = [:] json.processors.add([ jar: 'net.minecraftforge:jarsplitter:1.0.3', classpath: getClasspath(project, libs, 'net.minecraftforge:jarsplitter:1.0.3'), args: [ '--input', '{MINECRAFT_JAR}', '--slim', "{MC_SLIM}", '--data', "{MC_DATA}", '--extra', "{MC_EXTRA}", '--srg', '{MAPPINGS}' ] ]) json.processors.add([ jar: 'net.minecraftforge:binarypatcher:1.0.3', classpath: getClasspath(project, libs, 'net.minecraftforge:binarypatcher:1.0.3'), args: [ '--clean', '{MC_SLIM}', '--output', '{PATCHED}', '--apply', '{BINPATCH}' ] ]) json.processors.add([ jar: 'net.md-5:SpecialSource:1.8.3', classpath: getClasspath(project, libs, 'net.md-5:SpecialSource:1.8.3'), args: [ '--in-jar', '{PATCHED}', '--out-jar', '{REMAPPED}', '--srg-in', '{MAPPINGS}' ] ]) json.libraries = libs.values() output.text = new JsonBuilder(json).toPrettyString() } } universalJar { dependsOn launcherJson from(launcherJson.output) { rename { 'version.json' } } from extraTxts /* TODO: Annotation Cache? need to talk to cpw about his new design. from(fixAnnotationsJson){ into 'META-INF' } dependsOn fixAnnotationsJson */ // add crowdin locales from { crowdin.getDidWork() ? zipTree(crowdin.archivePath) : null} dependsOn crowdin doFirst { def json = new JsonSlurper().parseText(launcherJson.output.text) def classpath = new StringBuilder() json.libraries.each { lib -> if (!lib.name.startsWith("${project.group}:${project.name}")) { // group : artifact : version [: classifier][@extension] def split = lib.name.split(':') def ext = 'jar' if (split[split.length-1].indexOf('@') != -1) { ext = split[split.length-1].split('@')[1] split[split.length-1] = split[split.length-1].split('@')[0] } def group = split[0].replace('.', '/') def artifact = split[1] def version = split[2] def classifier = split.length > 3 ? split[3] : null if (classifier == null) classpath += "libraries/$group/$artifact/$version/$artifact-${version}.${ext} " else classpath += "libraries/$group/$artifact/$version/$artifact-${version}-${classifier}.${ext} " } } classpath += "minecraft_server.${patcher.mcVersion}.jar" manifest.attributes([ "Main-Class": "net.minecraftforge.fml.relauncher.ServerLaunchWrapper", "TweakClass": "net.minecraftforge.fml.common.launcher.FMLTweaker", "Class-Path": classpath.toString() ]) } } task signUniversal(type: SignJar, dependsOn: universalJar) { onlyIf { project.hasProperty('jarsigner') } def jarsigner = [:]; if (project.hasProperty('jarsigner')) jarsigner = project.jarsigner; alias = 'forge' storePass = jarsigner.storepass keyPass = jarsigner.keypass keyStore = jarsigner.keystore inputFile = universalJar.archivePath outputFile = universalJar.archivePath } publish.dependsOn signUniversal build.dependsOn signUniversal /* installer { dependsOn signUniversal classifier = 'installer' from extraTxts from "src/main/resources/forge_logo.png" from "src/main/resources/url.png" rename "forge_logo\\.png", "big_logo.png" } */ task makeMdk(type: Zip) { baseName = project.name classifier = 'mdk' version = project.version destinationDir = file('build/distributions') from rootProject.file('gradlew') from rootProject.file('gradlew.bat') from extraTxts from(rootProject.file('gradle/')){ into('gradle/') } from(rootProject.file('mdk/')){ /* filter(ReplaceTokens, tokens: [ VERSION: project.version ]) */ rename 'gitignore\\.txt', '.gitignore' } } license { header = file("$rootDir/LICENSE-header.txt") include 'net/minecraftforge/' exclude 'net/minecraftforge/server/terminalconsole/' exclude 'net/minecraftforge/api/' // exclude API here because it's validated in the SPI build exclude 'net/minecraftforge/fml/common/versioning/ComparableVersion.java' exclude 'net/minecraftforge/fml/common/versioning/InvalidVersionSpecificationException.java' exclude 'net/minecraftforge/fml/common/versioning/Restriction.java' exclude 'net/minecraftforge/fml/common/versioning/VersionRange.java' tasks { main { files = files("$rootDir/src/main/java") } test { files = files("$rootDir/src/test/java") } } } publishing { publications { mavenJava(MavenPublication) { artifact universalJar //TODO: changelog //TODO: installer //TODO: installer-win artifact makeMdk artifact userdevJar pom { name = 'forge' description = 'Modifactions to Minecraft to enable mod developers.' url = 'https://github.com/MinecraftForge/MinecraftForge' scm { url = 'https://github.com/MinecraftForge/MinecraftForge' connection = 'scm:git:git://github.com/MinecraftForge/MinecraftForge.git' developerConnection = 'scm:git:git@github.com:MinecraftForge/MinecraftForge.git' } issueManagement { system = 'github' url = 'https://github.com/MinecraftForge/MinecraftForge/issues' } licenses { license { name = 'LGPL 2.1' url = 'https://github.com/MinecraftForge/MinecraftForge/blob/1.13-pre/LICENSE.txt' distribution = 'repo' } } } } } repositories { maven { if (project.hasProperty('forgeMavenPassword')) { credentials { username project.properties.forgeMavenUser password project.properties.forgeMavenPassword } url 'http://files.minecraftforge.net/maven/manage/upload' } else { url 'file://' + rootProject.file('repo').getAbsolutePath() } } } } } def getVersionFromJava(def file, def mcver) { def major, minor, revision, build = '0' def prefix = 'public static final int' file.eachLine{ String s -> s = s.trim() if (s.startsWith(prefix)) { s = s.substring(prefix.length(), s.length() - 1) s = s.replace('=', ' ').replace('Version', '').replaceAll(' +', ' ').trim() String[] pts = s.split(' ') if (pts[0].equals('major')) major = pts[pts.length - 1] else if (pts[0] == 'minor') minor = pts[pts.length - 1] else if (pts[0] == 'revision') revision = pts[pts.length - 1] } } build = System.getenv('BUILD_NUMBER') ?: project.ext.properties.buildNumber ?: 0 String branch = null if (!System.getenv().containsKey('GIT_BRANCH')) { branch = grgit.branch.current().name } else { branch = System.getenv('GIT_BRANCH') branch = branch.substring(branch.lastIndexOf('/') + 1) } def out = "${mcver.replace('-', '_')}-$major.$minor.$revision.$build" if (branch && branch != 'master' && branch != 'HEAD' && branch != mcver && branch != mcver + '.0') { if (!(branch.endsWith('.x') && mcver.startsWith(branch.substring(0, branch.length() -2)))) out += "-$branch" } return out } def dateToIso8601(date) { def format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") def result = format.format(date) return result[0..21] + ':' + result[22..-1] } def sha1(file) { MessageDigest md = MessageDigest.getInstance('SHA-1') file.eachByte 4096, {bytes, size -> md.update(bytes, 0, size) } return md.digest().collect {String.format "%02x", it}.join() } def artifactTree(project, artifact) { if (!project.ext.has('tree_resolver')) project.ext.tree_resolver = 1 def cfg = project.configurations.create('tree_resolver_' + project.ext.tree_resolver++) def dep = project.dependencies.create(artifact) cfg.dependencies.add(dep) def files = cfg.resolve() return getArtifacts(project, cfg) } def getArtifacts(project, config) { def ret = [:] config.resolvedConfiguration.resolvedArtifacts.each { def art = [ group: it.moduleVersion.id.group, name: it.moduleVersion.id.name, version: it.moduleVersion.id.version, classifier: it.classifier, extension: it.extension, file: it.file ] def key = art.group + ':' + art.name def folder = "${art.group.replace('.', '/')}/${art.name}/${art.version}/" def filename = "${art.name}-${art.version}" if (art.classifier != null) filename += "-${art.classifier}" filename += ".${art.extension}" def path = "${folder}${filename}" def url = "https://libraries.minecraft.net/${path}" if (!checkExists(url)) { url = "https://files.minecraftforge.net/maven/${path}" /* project.logger.lifecycle("Artifact: ${path}") def repo = project.file("build/dep_repo/${folder}") repo.mkdirs() copy { from art.file into folder rename { filename } } project.file("build/dep_repo/${path}.sha1").text = sha1(it.file) */ } ret[key] = [ name: "${art.group}:${art.name}:${art.version}" + (art.classifier == null ? '' : ":${art.classifier}") + (art.extension == 'jar' ? '' : "@${art.extension}"), downloads: [ artifact: [ path: path, url: url, sha1: sha1(art.file), size: art.file.length() ] ] ] } return ret } def checkExists(url) { def code = new URL(url).openConnection().with { requestMethod = 'HEAD' connect() responseCode } return code == 200 } def getClasspath(project, libs, artifact) { def ret = [] artifactTree(project, artifact).each { key, lib -> libs[lib.name] = lib if (lib.name != artifact) ret.add(lib.name) } return ret } //evaluationDependsOnChildren() task setup() { dependsOn ':clean:extractMapped' dependsOn ':forge:extractMapped' //These must be strings so that we can do lazy resolution. Else we need evaluationDependsOnChildren above }