ForgePatch/build.gradle
liach c01b336095 Improves topological sort
This can be used for mod sorting, dependencies between registries, etc.
e.g. https://github.com/MinecraftForge/MinecraftForge/pull/4694#issuecomment-412520302

New features:
Now accepts guava graph
Performance improvement: no longer reverse the graph; changed dfs to bfs
Accepets a comparator for secondary order, e.g. natural order, index by map
Now properly reports all cycles in a graph with Tarjan's strongly connected component algorithm
Adds a test to prove the validity of the sort and cycle detection
Modified build.gradle for test source directory and dependencies

Mod loading changes:
Sort mod file info instead of suppliers (we don't have suppliers instances)
Moves cycle error reporting out of topological sort and into mod sorter
Prevent mod file dependencies between mods that share the same file

Signed-off-by: liach <liach@users.noreply.github.com>
2019-01-21 03:06:27 +00:00

1037 lines
41 KiB
Groovy

buildscript {
repositories {
mavenLocal()
maven { url = 'https://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.util.LinkedHashMap
import java.security.MessageDigest
import java.net.URL
import net.minecraftforge.gradle.common.task.ArchiveChecksum
import net.minecraftforge.gradle.common.task.DownloadMavenArtifact
import net.minecraftforge.gradle.common.task.SignJar
import net.minecraftforge.gradle.patcher.task.ApplyBinPatches
import org.apache.tools.ant.filters.ReplaceTokens
import de.undercouch.gradle.tasks.download.Download
import net.minecraftforge.gradle.patcher.task.TaskReobfuscateJar
import java.util.stream.Collectors
plugins {
id 'net.minecrell.licenser' version '0.4'
id 'org.ajoberstar.grgit' version '2.3.0'
id 'de.undercouch.download' version '3.3.0'
id "com.github.ben-manes.versions" version '0.20.0'
}
apply plugin: 'eclipse'
ext {
JAR_SIGNER = null
if (project.hasProperty('keystore')) {
JAR_SIGNER = [
storepass: project.properties.keystoreStorePass,
keypass: project.properties.keystoreKeyPass,
keystore: project.properties.keystore
]
}
MAPPING_CHANNEL = 'snapshot'
MAPPING_VERSION = '20180921-1.13'
MC_VERSION = '1.13'
MCP_VERSION = '2018.09.12.04.11.00'
}
project(':mcp') {
apply plugin: 'net.minecraftforge.gradle.forgedev.mcp'
mcp {
config = MC_VERSION + '-' + MCP_VERSION
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: MAPPING_CHANNEL, version: MAPPING_VERSION
mcVersion = MC_VERSION
}
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.
group = 'net.minecraftforge.test' //TODO: remove test when we finish patches and want users to find it
sourceSets {
fmllauncher {
java {
srcDir "$rootDir/src/fmllauncher/java"
}
resources {
srcDir "$rootDir/src/fmllauncher/resources"
}
}
main {
compileClasspath += sourceSets.fmllauncher.runtimeClasspath
runtimeClasspath += sourceSets.fmllauncher.runtimeClasspath
java {
srcDir "$rootDir/src/main/java"
}
resources {
srcDir "$rootDir/src/main/resources"
}
}
test {
compileClasspath += sourceSets.fmllauncher.runtimeClasspath
runtimeClasspath += sourceSets.fmllauncher.runtimeClasspath
java {
// srcDir "$rootDir/src/test/java" TODO fix later
srcDir "$rootDir/src/fmllaunchertest/java"
}
resources {
srcDir "$rootDir/src/test/resources"
}
}
userdev {
compileClasspath += sourceSets.main.runtimeClasspath
runtimeClasspath += sourceSets.main.runtimeClasspath
java {
srcDir "$rootDir/src/userdev/java"
}
resources {
srcDir "$rootDir/src/userdev/resources"
}
}
}
repositories {
mavenLocal()
mavenCentral()
}
ext {
SPEC_VERSION = '24.0' // This is overwritten by git tag, but here so dev time doesnt explode
// The new versioning sceme is <MCVersion>-<ForgeMC>.<RB>.<CommitsSinceRB>
// ForgeMC is a unique identifier for every MC version we have supported.
// Essentially, the same as the old, except dropping the first number, and the builds are no longer unique.
MCP_ARTIFACT = project(':mcp').mcp.config
}
def getVersion = {
//TAG-offset-hash
def raw = grgit.describe(longDescr: true)
def desc = (raw == null ? '0.0-0-unknown' : grgit.describe(longDescr: true)).split('-') as List
def hash = desc.remove(desc.size() - 1)
def offset = desc.remove(desc.size() - 1)
def tag = desc.join('-')
def branch = grgit.branch.current().name
if (branch in ['master', 'HEAD', MC_VERSION, MC_VERSION + '.0'])
branch = null
if (branch != null && branch.endsWith('.x') && MC_VERSION.startsWith(branch.substring(0, branch.length() - 2))) //1.13.x
branch = null
SPEC_VERSION = tag
return "${MC_VERSION}-${tag}.${offset}${t -> if (branch != null) t << '-' + branch}".toString() //Bake the response instead of making it dynamic
}
version = getVersion()
patcher {
parent = project(':clean')
patches = file("$rootDir/patches/minecraft")
patchedSrc = file('src/main/java')
accessTransformer = file("$rootDir/src/main/resources/META-INF/accesstransformer.cfg")
exc = file("$rootDir/src/main/resources/forge.exc")
srgPatches = true
runs {
forge_client = {
main 'net.minecraftforge.fml.LaunchTesting'
environment = [
target: 'fmldevclient',
assetDirectory: downloadAssets.output,
nativesDirectory: extractNatives.output
]
properties = [
'org.lwjgl.util.Debug': 'true',
'org.lwjgl.util.DebugLoader': 'true',
'org.lwjgl.system.SharedLibraryExtractDirectory': 'lwjgl_dll',
'mc.version': MC_VERSION,
'mcp.version': MCP_VERSION,
'forge.version': project.version.substring(MC_VERSION.length() + 1),
'forge.spec': SPEC_VERSION,
'forge.group': project.group,
'fmllauncher.version': SPEC_VERSION
]
}
forge_server = {
main 'net.minecraftforge.fml.LaunchTesting'
environment = [
target: 'fmldevserver'
]
properties = [
'mc.version': MC_VERSION,
'mcp.version': MCP_VERSION,
'forge.version': "${project.version.substring(MC_VERSION.length() + 1)}".toString(),
'forge.spec': SPEC_VERSION,
'forge.group': project.group,
'fmllauncher.version': SPEC_VERSION
]
}
}
}
ext {
MANIFESTS = [
'/': [
'Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
'GitCommit': grgit.head().abbreviatedId,
'Git-Branch': grgit.branch.current().getName()
] as LinkedHashMap,
'net/minecraftforge/versions/forge/': [
'Specification-Title': 'Forge',
'Specification-Vendor': 'Forge Development LLC',
'Specification-Version': SPEC_VERSION,
'Implementation-Title': project.group,
'Implementation-Version': project.version.substring(MC_VERSION.length() + 1),
'Implementation-Vendor': 'Forge Development LLC'
] as LinkedHashMap,
'net/minecraftforge/versions/mcp/': [
'Specification-Title': 'Minecraft',
'Specification-Vendor': 'Mojang',
'Specification-Version': MC_VERSION,
'Implementation-Title': 'MCP',
'Implementation-Version': MCP_VERSION,
'Implementation-Vendor': 'Forge'
] as LinkedHashMap,
'net/minecraftforge/fml/javafmlmod/': [
'Specification-Title': 'Mod Language Provider',
'Specification-Vendor': 'Forge Development LLC',
'Specification-Version': '1',
'Implementation-Title': 'FML Java Mod',
'Implementation-Version': SPEC_VERSION,
'Implementation-Vendor': 'Forge'
] as LinkedHashMap,
'net/minecraftforge/fml/loading/': [
'Specification-Title': 'Launcher',
'Specification-Vendor': 'Forge Development LLC',
'Specification-Version': '1',
'Implementation-Title': 'FML Launcher',
'Implementation-Version': SPEC_VERSION,
'Implementation-Vendor': 'Forge'
] as LinkedHashMap
]
}
applyPatches {
canonicalizeAccess true
canonicalizeWhitespace true
maxFuzz 3
}
configurations {
installer {
transitive = false //Don't pull all libraries, if we're missing something, add it to the installer list so the installer knows to download it.
}
api.extendsFrom(installer)
fmllauncherImplementation.extendsFrom(installer)
}
dependencies {
api 'net.minecraft:client:1.13:extra'
installer 'com.paulscode:soundsystem:2018+'
installer 'org.ow2.asm:asm:6.2'
installer 'org.ow2.asm:asm-commons:6.2'
installer 'org.ow2.asm:asm-tree:6.2'
installer 'cpw.mods:modlauncher:0.6.0'
installer 'net.minecraftforge:accesstransformers:0.14.+:shadowed'
installer 'net.minecraftforge:eventbus:0.6.+:service'
installer 'net.minecraftforge:forgespi:0.4.+'
installer 'net.minecraftforge:coremods:0.2.+'
installer 'com.electronwill.night-config:core:3.4.2'
installer 'com.electronwill.night-config:toml:3.4.2'
installer 'org.jline:jline:3.5.1'
installer 'org.apache.maven:maven-artifact:3.6.0'
installer 'net.jodah:typetools:0.6.0'
installer 'java3d:vecmath:1.5.2'
installer 'org.apache.logging.log4j:log4j-api:2.11.1'
installer 'org.apache.logging.log4j:log4j-core:2.11.1'
fmllauncherImplementation 'com.google.guava:guava:21.0'
fmllauncherImplementation 'com.google.code.gson:gson:2.8.0'
testImplementation "org.junit.jupiter:junit-jupiter-api:5.0.0"
testImplementation "org.opentest4j:opentest4j:1.0.0" // needed for junit 5
testImplementation "org.hamcrest:hamcrest-all:1.3" // needs advanced matching for list order
}
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 patcher.runs.forge_client.main
systemProperties = patcher.runs.forge_client.properties
environment += patcher.runs.forge_client.environment
workingDir 'runclient'
}
task runserver(type: JavaExec) {
doFirst {
mkdir 'runserver'
}
doFirst {
copy {
from sourceSets.main.resources
into "$buildDir/classes/java/main"
}
}
classpath sourceSets.main.runtimeClasspath
main patcher.runs.forge_server.main
args 'nogui'
systemProperties = patcher.runs.forge_server.properties
environment += patcher.runs.forge_server.environment
workingDir 'runserver'
standardInput = System.in
}
def extraTxts = [
rootProject.file('CREDITS.txt'),
rootProject.file('LICENSE.txt')
]
def changelog = rootProject.file('build/changelog.txt')
if (changelog.exists())
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
onlyIf {
!downloadCrowdin.state.skipped
}
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
}
}
// We apply the bin patches we just created to make a jar that is JUST our changes
task applyClientBinPatches(type: ApplyBinPatches, dependsOn: genClientBinPatches) {
clean = { genClientBinPatches.cleanJar }
input = genClientBinPatches.output
}
task applyServerBinPatches(type: ApplyBinPatches, dependsOn: genServerBinPatches) {
clean = { genServerBinPatches.cleanJar }
input = genServerBinPatches.output
}
task applyJoinedBinPatches(type: ApplyBinPatches, dependsOn: genJoinedBinPatches) {
clean = { genJoinedBinPatches.cleanJar }
input = genJoinedBinPatches.output
}
// Checksum tasks so that we can know if the vanilla classes are what we expect them to do!
task clientBaseChecksum(type: ArchiveChecksum, dependsOn: genClientBinPatches) {
input = { genClientBinPatches.cleanJar} //Lazy because Patcher Plugin sets the value afterEvaluate
name = 'client'
}
task serverBaseChecksum(type: ArchiveChecksum, dependsOn: genServerBinPatches) {
input = { genServerBinPatches.cleanJar }
name = 'server'
}
task joinedBaseChecksum(type: ArchiveChecksum, dependsOn: genJoinedBinPatches) {
input = { genJoinedBinPatches.cleanJar }
name = 'joined'
}
task clientPatchedChecksum(type: ArchiveChecksum, dependsOn: applyClientBinPatches) {
input = applyClientBinPatches.output
name = 'client_patched'
}
task serverPatchedChecksum(type: ArchiveChecksum, dependsOn: applyServerBinPatches) {
input = applyServerBinPatches.output
name = 'server_patched'
}
task joinedPatchedChecksum(type: ArchiveChecksum, dependsOn: applyJoinedBinPatches) {
input = applyJoinedBinPatches.output
name = 'joined_patched'
}
// Utility methods for testing checksums
task cleanChecksums() {
['client', 'server', 'joined'].each { side ->
['Base', 'Patched'].each { type ->
def clean = "clean${side.capitalize()}${type}Checksum"
dependsOn(clean)
tasks.findByName("${side}${type}Checksum").mustRunAfter(clean)
}
}
}
task checksums() {
['client', 'server', 'joined'].each { side ->
['Base', 'Patched'].each { type ->
dependsOn("${side}${type}Checksum")
}
}
}
task launcherJson(dependsOn: ['signUniversalJar', 'signLauncherJar']) {
inputs.file universalJar.archivePath
ext {
output = file('build/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/"
]
def idx = project.version.indexOf('-')
id = project.version.substring(0, idx) + "-${project.name}" + project.version.substring(idx)
}
inputs.file vanilla
outputs.file output
doLast {
def json_vanilla = new JsonSlurper().parseText(vanilla.text)
def json = [
_comment_: comment,
id: id,
time: timestamp,
releaseTime: timestamp,
type: 'release',
mainClass: 'cpw.mods.modlauncher.Launcher',
inheritsFrom: MC_VERSION,
logging: [
client: [
argument: '-Dlog4j.configurationFile=${path}',
file: [
id:'client-1.12.xml',
sha1:'ef4f57b922df243d0cef096efe808c72db042149',
size:877,
url:'https://launcher.mojang.com/v1/objects/ef4f57b922df243d0cef096efe808c72db042149/client-1.12.xml'
],
type: 'log4j2-xml'
]
],
arguments: [
game: ['--launchTarget', 'fmlclient', '--fml.forgeVersion', "${project.version.substring(MC_VERSION.length() + 1)}", '--fml.mcVersion', "${MC_VERSION}", '--fml.forgeGroup', "${project.group}", '--fml.mcpVersion', "${MCP_VERSION}"]
],
libraries: [
[
//Package our launcher jar as the 'main' jar Mojang's launcher loads. It will in turn load Forge's regular jars itself.
name: "${project.group}:${project.name}:${project.version}",
downloads: [
artifact: [
path: "${project.group.replace('.', '/')}/${project.name}/${project.version}/${project.name}-${project.version}.jar",
url: "", //Do not include the URL so that the installer/launcher won't grab it. This is also why we don't have the universal classifier
sha1: sha1(launcherJar.archivePath),
size: launcherJar.archivePath.length()
]
]
]
]
]
def artifacts = getArtifacts(project, project.configurations.installer, false)
artifacts.each { key, lib ->
json.libraries.add(lib)
}
output.text = new JsonBuilder(json).toPrettyString()
}
}
task installerJson(dependsOn: [launcherJson, genClientBinPatches, applyClientBinPatches, applyServerBinPatches]) {
ext {
output = file('build/install_profile.json')
INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.0.3'
JAR_SPLITTER = 'net.minecraftforge:jarsplitter:1.0.4'
}
doFirst {
ext.BIN_PATCHER = 'net.minecraftforge:binarypatcher:' + genClientBinPatches.resolvedVersion
}
inputs.file applyClientBinPatches.output
inputs.file applyServerBinPatches.output
inputs.file genClientBinPatches.toolJar
inputs.file launcherJson.output
outputs.file output
doLast {
def libs = [
"${project.group}:${project.name}:${project.version}:universal": [
name: "${project.group}:${project.name}:${project.version}:universal",
downloads: [
artifact: [
path: "${project.group.replace('.', '/')}/${project.name}/${project.version}/${project.name}-${project.version}-universal.jar",
url: "", //Do not include the URL so that the installer/launcher won't grab it. This is also why we don't have the universal classifier
sha1: sha1(universalJar.archivePath),
size: universalJar.archivePath.length()
]
]
]
]
def json = [
_comment_: launcherJson.comment,
spec: 0,
profile: project.name,
version: launcherJson.id,
json: '/version.json',
path: "${project.group}:${project.name}:${project.version}",
logo: '/big_logo.png',
minecraft: MC_VERSION,
welcome: "Welcome to the simple ${project.name.capitalize()} installer.",
data: [
MAPPINGS: [
client: "[${MCP_ARTIFACT.group}:${MCP_ARTIFACT.name}:${MCP_ARTIFACT.version}:mappings@txt]",
server: "[${MCP_ARTIFACT.group}:${MCP_ARTIFACT.name}:${MCP_ARTIFACT.version}:mappings@txt]"
],
BINPATCH: [
client: '/data/client.lzma',
server: '/data/server.lzma'
],
MC_SLIM: [
client: "[net.minecraft:client:${MC_VERSION}:slim]",
server: "[net.minecraft:server:${MC_VERSION}:slim]"
],
MC_SLIM_SHA: [
client: "'${sha1(tasks.getByName('downloadClientSlim').output)}'",
server: "'${sha1(tasks.getByName('downloadServerSlim').output)}'"
],
MC_DATA: [
client: "[net.minecraft:client:${MC_VERSION}:data]",
server: "[net.minecraft:server:${MC_VERSION}:data]"
],
MC_DATA_SHA: [
client: "'${sha1(tasks.getByName('downloadClientData').output)}'",
server: "'${sha1(tasks.getByName('downloadServerData').output)}'"
],
MC_EXTRA: [
client: "[net.minecraft:client:${MC_VERSION}:extra]",
server: "[net.minecraft:server:${MC_VERSION}:extra]"
],
MC_EXTRA_SHA: [
client: "'${sha1(tasks.getByName('downloadClientExtra').output)}'",
server: "'${sha1(tasks.getByName('downloadServerExtra').output)}'"
],
MC_SRG: [
client: "[net.minecraft:client:${MC_VERSION}-${MCP_VERSION}:srg]",
server: "[net.minecraft:server:${MC_VERSION}-${MCP_VERSION}:srg]"
],
PATCHED: [
client: "[${project.group}:${project.name}:${project.version}:client]",
server: "[${project.group}:${project.name}:${project.version}:server]"
],
PATCHED_SHA: [
client: "'${sha1(applyClientBinPatches.output)}'",
server: "'${sha1(applyServerBinPatches.output)}'"
]
],
processors: [
[
jar: INSTALLER_TOOLS,
classpath: getClasspath(project, libs, INSTALLER_TOOLS),
args: [
'--task', 'MCP_DATA',
'--input', "[${MCP_ARTIFACT.descriptor}]",
'--output', '{MAPPINGS}',
'--key', 'mappings'
]
], [
jar: JAR_SPLITTER,
classpath: getClasspath(project, libs, JAR_SPLITTER),
args: [
'--input', '{MINECRAFT_JAR}',
'--slim', '{MC_SLIM}',
'--data', '{MC_DATA}',
'--extra', '{MC_EXTRA}',
'--srg', '{MAPPINGS}'
],
outputs: [
'{MC_SLIM}': '{MC_SLIM_SHA}',
'{MC_DATA}': '{MC_DATA_SHA}',
'{MC_EXTRA}': '{MC_EXTRA_SHA}'
]
], [ // SpecialSource has a bug where it won't create the nessasary directories, remove when they fix that.
jar: INSTALLER_TOOLS,
classpath: getClasspath(project, libs, INSTALLER_TOOLS),
args: [
'--task', 'CREATE_PARENTS',
'--target', '{MC_SRG}'
]
], [
jar: 'net.md-5:SpecialSource:1.8.3',
classpath: getClasspath(project, libs, 'net.md-5:SpecialSource:1.8.3'),
args: [
'--in-jar', '{MC_SLIM}',
'--out-jar', '{MC_SRG}',
'--srg-in', '{MAPPINGS}'
]
], [
jar: BIN_PATCHER,
classpath: getClasspath(project, libs, BIN_PATCHER),
args: [
'--clean', '{MC_SRG}',
'--output', '{PATCHED}',
'--apply', '{BINPATCH}'
],
outputs: [
'{PATCHED}': '{PATCHED_SHA}'
]
]
]
]
getClasspath(project, libs, MCP_ARTIFACT.descriptor) //Tell it to download mcp_config
json.libraries = libs.values().sort{a,b -> a.name.compareTo(b.name)}
output.text = new JsonBuilder(json).toPrettyString()
}
}
['client', 'server'].each { side ->
['slim', 'extra', 'data'].each { type ->
def name = "download${side.capitalize()}${type.capitalize()}"
task "${name}"(type: DownloadMavenArtifact) {
artifact = "net.minecraft:${side}:${MC_VERSION}:${type}"
}
installerJson.dependsOn(name)
installerJson.inputs.file(tasks.getByName(name).output)
}
}
universalJar {
from extraTxts
/* TODO: Annotation Cache? need to talk to cpw about his new design.
from(fixAnnotationsJson){
into 'META-INF'
}
dependsOn fixAnnotationsJson
*/
// Add checksum files of clean and patched vanilla classes.
['client', 'server'].each { side ->
['Base', 'Patched'].each { type ->
from(tasks.getByName("${side}${type}Checksum").output) {
into 'checksums/'
}
}
}
dependsOn checksums
// add crowdin locales
from { !crowdin.state.skipped ? zipTree(crowdin.archivePath) : null}
dependsOn crowdin
doFirst {
MANIFESTS.each{ pkg, values ->
if (pkg == '/') {
manifest.attributes(values)
} else {
manifest.attributes(values, pkg)
}
}
}
}
task launcherJar(type: Jar) {
classifier 'launcher'
from sourceSets.fmllauncher.output
doFirst {
def classpath = new StringBuilder()
def artifacts = getArtifacts(project, project.configurations.installer, false)
artifacts.each { key, lib ->
classpath += "libraries/${lib.downloads.artifact.path} "
}
classpath += "libraries/net/minecraft/server/${MC_VERSION}/server-${MC_VERSION}-data.jar "
classpath += "libraries/net/minecraft/server/${MC_VERSION}/server-${MC_VERSION}-extra.jar"
MANIFESTS.each{ pkg, values ->
if (pkg == '/') {
manifest.attributes(values += [
'Main-Class': 'net.minecraftforge.server.ServerMain',
'Class-Path': classpath.toString()
])
} else {
manifest.attributes(values, pkg)
}
}
}
}
task downloadInstaller(type: DownloadMavenArtifact) {
artifact = 'net.minecraftforge:installer:2.0.+:shrunk'
changing = true
}
task installerJar(type: Zip, dependsOn: [downloadInstaller, installerJson, launcherJson, genClientBinPatches, genServerBinPatches, 'signUniversalJar', 'signLauncherJar']) {
classifier = 'installer'
extension = 'jar' //Needs to be Zip task to not override Manifest, so set extension
destinationDir = file('build/libs')
from(extraTxts)
from(rootProject.file('/src/main/resources/forge_logo.png')) {
rename{'big_logo.png'}
}
from(rootProject.file('/src/main/resources/url.png'))
from(genClientBinPatches.output) {
rename{'data/client.lzma'}
}
from(genServerBinPatches.output) {
rename{'data/server.lzma'}
}
from(universalJar) {
into "/maven/${project.group.replace('.', '/')}/${project.name}/${project.version}/"
}
from(launcherJar) {
into "/maven/${project.group.replace('.', '/')}/${project.name}/${project.version}/"
rename { "${project.name}-${project.version}.jar" }
}
from(installerJson.output)
from(launcherJson.output)
from(zipTree(downloadInstaller.output)) {
duplicatesStrategy = 'exclude'
}
}
[universalJar, launcherJar, installerJar].each { t ->
task "sign${t.name.capitalize()}"(type: SignJar, dependsOn: t) {
onlyIf {
JAR_SIGNER != null && t.state.failure == null
}
def jarsigner = JAR_SIGNER == null ? [:] : JAR_SIGNER
alias = 'forge'
storePass = jarsigner.storepass
keyPass = jarsigner.keypass
keyStore = jarsigner.keystore
inputFile = t.archivePath
outputFile = t.archivePath
doFirst {
project.logger.lifecycle('Signing: ' + inputFile)
}
}
t.finalizedBy(tasks.getByName("sign${t.name.capitalize()}"))
}
task makeMdk(type: Zip) {
baseName = project.name
classifier = 'mdk'
version = project.version
destinationDir = file('build/libs')
from rootProject.file('gradlew')
from rootProject.file('gradlew.bat')
from extraTxts
from(rootProject.file('gradle/')){
into('gradle/')
}
from(rootProject.file('mdk/')){
rootProject.file('mdk/gitignore.txt').eachLine{
if (!it.trim().isEmpty() && !it.trim().startsWith('#'))
exclude it
}
filter(ReplaceTokens, tokens: [
FORGE_VERSION: project.version,
FORGE_GROUP: project.group,
FORGE_NAME: project.name,
MC_VERSION: MC_VERSION,
MAPPING_CHANNEL: MAPPING_CHANNEL,
MAPPING_VERSION: MAPPING_VERSION
])
rename 'gitignore\\.txt', '.gitignore'
}
}
userdevConfig {
def artifacts = getArtifacts(project, project.configurations.installer, true)
artifacts.each { key, lib ->
addLibrary(lib.name)
}
addLibrary("${project.group}:${project.name}:${project.version}:launcher")
runs {
client = {
main 'net.minecraftforge.userdev.UserdevLauncher'
environment 'target', 'fmluserdevclient'
environment 'assetDirectory', '{assets_root}'
environment 'nativesDirectory', '{natives}'
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1)
environment 'FORGE_GROUP', project.group
environment 'MCP_VERSION', MCP_VERSION
environment 'MC_VERSION', MC_VERSION
environment 'MOD_CLASSES', '{source_roots}'
environment 'MCP_MAPPINGS', '{mcp_mappings}'
}
server = {
main 'net.minecraftforge.userdev.UserdevLauncher'
environment 'target', 'fmluserdevserver'
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1)
environment 'FORGE_GROUP', project.group
environment 'MCP_VERSION', MCP_VERSION
environment 'MC_VERSION', MC_VERSION
environment 'MOD_CLASSES', '{source_roots}'
environment 'MCP_MAPPINGS', '{mcp_mappings}'
}
}
}
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")
}
}
}
task userdevExtras(type:Jar) {
dependsOn classes
from sourceSets.userdev.output
classifier 'userdev-temp'
}
task userdevExtrasReobf(type:TaskReobfuscateJar) {
dependsOn userdevExtras, createMcp2Srg
input = tasks.userdevExtras.archivePath
classpath = project.configurations.getByName("compile")
srg = tasks.createMcp2Srg.output
}
userdevJar {
dependsOn userdevExtrasReobf
from (zipTree(tasks.userdevExtrasReobf.output)) {
into '/inject/'
}
from (sourceSets.userdev.output.resourcesDir) {
into '/inject/'
}
}
applyRangeMap {
setSources sourceSets.userdev.java.srcDirs.findAll({f -> (f != patcher.patchedSrc) })
}
publishing {
publications {
mavenJava(MavenPublication) {
artifact universalJar
if (changelog.exists()) {
artifact(changelog) {
classifier = 'changelog'
}
}
artifact installerJar
//TODO: installer-win
artifact makeMdk
artifact userdevJar
artifact sourcesJar
artifact launcherJar
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 'https://files.minecraftforge.net/maven/manage/upload'
} else {
url 'file://' + rootProject.file('repo').getAbsolutePath()
}
}
}
}
}
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, true)
}
def getArtifacts(project, config, classifiers) {
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}"
}
//TODO remove when Mojang launcher is updated
if (!classifiers && art.classifier != null) { //Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
art.version = "${art.version}-${art.classifier}"
art.classifier = null
art.extension = 'jar'
path = "${art.group.replace('.', '/')}/${art.name}/${art.version}/${art.name}-${art.version}.jar"
}
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
}