aab8adb884
* Add simple patch checker and cleanup patches * Address comments * move task implementation * genPatches is now finalized by checkPatches * the S2S artifacts are automatically removed * added class and method access checking
1543 lines
65 KiB
Groovy
1543 lines
65 KiB
Groovy
buildscript {
|
|
repositories {
|
|
mavenLocal()
|
|
maven { url = 'https://files.minecraftforge.net/maven' }
|
|
jcenter()
|
|
//mavenCentral() //TODO: Update Gradle to use HTTPS by default
|
|
maven {
|
|
name 'maven_central'
|
|
url 'https://repo.maven.apache.org/maven2/'
|
|
}
|
|
}
|
|
dependencies {
|
|
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.179'
|
|
classpath 'org.ow2.asm:asm:7.2'
|
|
classpath 'org.ow2.asm:asm-tree:7.2'
|
|
}
|
|
}
|
|
import groovy.json.JsonSlurper
|
|
import groovy.json.JsonBuilder
|
|
|
|
import java.nio.file.Files
|
|
import java.text.SimpleDateFormat
|
|
import java.util.Date
|
|
import java.util.LinkedHashMap
|
|
import java.util.TreeSet
|
|
import java.util.stream.Collectors
|
|
import java.util.zip.ZipEntry
|
|
import java.util.zip.ZipInputStream
|
|
import java.util.zip.ZipOutputStream
|
|
import java.security.MessageDigest
|
|
import java.net.URL
|
|
import net.minecraftforge.forge.tasks.*
|
|
import net.minecraftforge.gradle.common.task.ArchiveChecksum
|
|
import net.minecraftforge.gradle.common.task.DownloadMavenArtifact
|
|
import net.minecraftforge.gradle.common.task.ExtractInheritance
|
|
import net.minecraftforge.gradle.common.task.SignJar
|
|
import net.minecraftforge.gradle.common.util.HashStore
|
|
import net.minecraftforge.gradle.mcp.function.MCPFunction
|
|
import net.minecraftforge.gradle.mcp.util.MCPEnvironment
|
|
import net.minecraftforge.gradle.patcher.task.ApplyBinPatches
|
|
import net.minecraftforge.gradle.patcher.task.TaskReobfuscateJar
|
|
import net.minecraftforge.gradle.userdev.tasks.RenameJar
|
|
import org.apache.tools.ant.filters.ReplaceTokens
|
|
import de.undercouch.gradle.tasks.download.Download
|
|
import org.gradle.plugins.ide.eclipse.model.SourceFolder
|
|
import org.objectweb.asm.ClassReader
|
|
import org.objectweb.asm.Opcodes
|
|
|
|
plugins {
|
|
id 'net.minecrell.licenser' version '0.4'
|
|
id 'org.ajoberstar.grgit' version '3.1.1'
|
|
id 'de.undercouch.download' version '3.3.0'
|
|
id 'com.github.ben-manes.versions' version '0.22.0'
|
|
}
|
|
apply plugin: 'eclipse'
|
|
|
|
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
|
|
|
|
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 = '20200514-1.16'
|
|
MC_VERSION = '1.16.1'
|
|
MCP_VERSION = '20200625.160719'
|
|
}
|
|
|
|
project(':mcp') {
|
|
apply plugin: 'net.minecraftforge.gradle.mcp'
|
|
repositories {
|
|
mavenLocal()
|
|
}
|
|
mcp {
|
|
config = MC_VERSION + '-' + MCP_VERSION
|
|
pipeline = 'joined'
|
|
}
|
|
}
|
|
|
|
project(':clean') {
|
|
evaluationDependsOn(':mcp')
|
|
apply plugin: 'eclipse'
|
|
apply plugin: 'net.minecraftforge.gradle.patcher'
|
|
compileJava.sourceCompatibility = compileJava.targetCompatibility = sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
|
|
|
repositories {
|
|
mavenLocal()
|
|
//mavenCentral() //TODO: Update Gradle to use HTTPS by default
|
|
maven {
|
|
name 'maven_central'
|
|
url 'https://repo.maven.apache.org/maven2/'
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation 'net.minecraftforge:forgespi:2.0.+'
|
|
}
|
|
patcher {
|
|
parent = project(':mcp')
|
|
mcVersion = MC_VERSION
|
|
patchedSrc = file('src/main/java')
|
|
|
|
mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION
|
|
|
|
runs {
|
|
clean_client {
|
|
taskName 'clean_client'
|
|
|
|
main 'net.minecraft.client.main.Main'
|
|
workingDirectory project.file('run')
|
|
|
|
args '--gameDir', '.'
|
|
args '--version', MC_VERSION
|
|
args '--assetsDir', downloadAssets.output
|
|
args '--assetIndex', '{asset_index}'
|
|
args '--accessToken', '0'
|
|
}
|
|
|
|
clean_server {
|
|
taskName 'clean_server'
|
|
|
|
main 'net.minecraft.server.Main'
|
|
workingDirectory project.file('run')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
project(':forge') {
|
|
evaluationDependsOn(':clean')
|
|
apply plugin: 'java-library'
|
|
apply plugin: 'maven-publish'
|
|
apply plugin: 'eclipse'
|
|
apply plugin: 'net.minecraftforge.gradle.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'
|
|
|
|
sourceSets {
|
|
fmllauncher {
|
|
java {
|
|
srcDirs = ["$rootDir/src/fmllauncher/java"]
|
|
}
|
|
resources {
|
|
srcDirs = ["$rootDir/src/fmllauncher/resources"]
|
|
}
|
|
}
|
|
main {
|
|
compileClasspath += sourceSets.fmllauncher.runtimeClasspath
|
|
runtimeClasspath += sourceSets.fmllauncher.runtimeClasspath
|
|
java {
|
|
srcDirs = ["$rootDir/src/main/java"]
|
|
}
|
|
resources {
|
|
srcDirs = [
|
|
"$rootDir/src/main/resources",
|
|
"$rootDir/src/generated/resources"
|
|
]
|
|
}
|
|
}
|
|
test {
|
|
compileClasspath += sourceSets.fmllauncher.runtimeClasspath
|
|
runtimeClasspath += sourceSets.fmllauncher.runtimeClasspath
|
|
java {
|
|
srcDirs = [
|
|
"$rootDir/src/test/java",
|
|
"$rootDir/src/fmllaunchertest/java"
|
|
]
|
|
}
|
|
resources {
|
|
srcDirs = [
|
|
"$rootDir/src/test/resources",
|
|
"$rootDir/src/generated_test/resources"
|
|
]
|
|
}
|
|
}
|
|
userdev {
|
|
compileClasspath += sourceSets.main.runtimeClasspath
|
|
runtimeClasspath += sourceSets.main.runtimeClasspath
|
|
java {
|
|
srcDirs = ["$rootDir/src/userdev/java"]
|
|
}
|
|
resources {
|
|
srcDirs = ["$rootDir/src/userdev/resources"]
|
|
}
|
|
}
|
|
userdev_test {
|
|
compileClasspath += sourceSets.userdev.runtimeClasspath
|
|
runtimeClasspath += sourceSets.userdev.runtimeClasspath
|
|
compileClasspath += sourceSets.test.runtimeClasspath
|
|
runtimeClasspath += sourceSets.test.runtimeClasspath
|
|
}
|
|
}
|
|
//Eclipse adds the sourcesets twice, once where we tell it to, once in the projects folder. No idea why. So delete them
|
|
eclipse.classpath.file.whenMerged { cls -> cls.entries.removeIf { e -> e instanceof SourceFolder && e.path.startsWith('src/') && !e.path.startsWith('src/main/') } }
|
|
|
|
repositories {
|
|
mavenLocal()
|
|
//mavenCentral() //TODO: Update Gradle to use HTTPS by default
|
|
maven {
|
|
name 'maven_central'
|
|
url 'https://repo.maven.apache.org/maven2/'
|
|
}
|
|
}
|
|
|
|
ext {
|
|
SPEC_VERSION = '31.2' // 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
|
|
SPECIAL_SOURCE = 'net.md-5:SpecialSource:1.8.5'
|
|
VERSION_JSON = project(':mcp').file('build/mcp/downloadJson/version.json')
|
|
BINPATCH_TOOL = 'net.minecraftforge:binarypatcher:1.0.12:fatjar'
|
|
INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.1.11'
|
|
}
|
|
|
|
def getVersion = {
|
|
//TAG-offset-hash
|
|
def raw = grgit.describe(longDescr: true, tags:true)
|
|
def desc = (raw == null ? '0.0-0-unknown' : grgit.describe(longDescr: true, tags: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()
|
|
println('Forge Version: ' + version)
|
|
|
|
patcher {
|
|
exc = file("$rootDir/src/main/resources/forge.exc")
|
|
parent = project(':clean')
|
|
patches = file("$rootDir/patches/minecraft")
|
|
patchedSrc = file('src/main/java')
|
|
srgPatches = true
|
|
accessTransformer = file("$rootDir/src/main/resources/META-INF/accesstransformer.cfg")
|
|
sideAnnotationStripper = file("$rootDir/src/main/resources/forge.sas")
|
|
|
|
runs {
|
|
forge_client {
|
|
taskName 'forge_client'
|
|
|
|
main 'net.minecraftforge.userdev.LaunchTesting'
|
|
workingDirectory project.file('run')
|
|
|
|
environment 'target', 'fmldevclient'
|
|
environment 'assetIndex', '{asset_index}'
|
|
environment 'assetDirectory', downloadAssets.output
|
|
environment 'nativesDirectory', extractNatives.output
|
|
|
|
environment 'MC_VERSION', MC_VERSION
|
|
environment 'MCP_VERSION', MCP_VERSION
|
|
environment 'FORGE_GROUP', project.group
|
|
environment 'FORGE_SPEC', SPEC_VERSION
|
|
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1).toString()
|
|
environment 'LAUNCHER_VERSION', SPEC_VERSION
|
|
property 'org.lwjgl.system.SharedLibraryExtractDirectory', 'lwjgl_dll'
|
|
|
|
ideaModule "${rootProject.name}.${project.name}.userdev"
|
|
|
|
source sourceSets.main
|
|
source sourceSets.userdev
|
|
}
|
|
|
|
forge_test_client {
|
|
parent runs.forge_client
|
|
taskName 'forge_test_client'
|
|
|
|
environment 'MOD_CLASSES', 'dummy' // Needed to work around FG limitation, FG will replace this!
|
|
|
|
ideaModule "${rootProject.name}.${project.name}.userdev_test"
|
|
|
|
mods {
|
|
TestMods { sources sourceSets.test }
|
|
}
|
|
}
|
|
|
|
forge_server {
|
|
taskName 'forge_server'
|
|
|
|
main 'net.minecraftforge.userdev.LaunchTesting'
|
|
workingDirectory project.file('run')
|
|
|
|
environment 'target', 'fmldevserver'
|
|
|
|
environment 'MC_VERSION', MC_VERSION
|
|
environment 'MCP_VERSION', MCP_VERSION
|
|
environment 'FORGE_GROUP', project.group
|
|
environment 'FORGE_SPEC', SPEC_VERSION
|
|
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1).toString()
|
|
environment 'LAUNCHER_VERSION', SPEC_VERSION
|
|
|
|
ideaModule "${rootProject.name}.${project.name}.userdev"
|
|
|
|
source sourceSets.main
|
|
source sourceSets.userdev
|
|
}
|
|
|
|
forge_test_server {
|
|
parent runs.forge_server
|
|
taskName 'forge_test_server'
|
|
|
|
environment 'MOD_CLASSES', 'dummy' // Needed to work around FG limitation, FG will replace this!
|
|
|
|
ideaModule "${rootProject.name}.${project.name}.userdev_test"
|
|
|
|
mods {
|
|
TestMods { sources sourceSets.test }
|
|
}
|
|
}
|
|
|
|
forge_data {
|
|
taskName 'forge_data'
|
|
|
|
main 'net.minecraftforge.userdev.LaunchTesting'
|
|
workingDirectory project.file('run')
|
|
|
|
environment 'target', 'fmldevdata'
|
|
|
|
environment 'MC_VERSION', MC_VERSION
|
|
environment 'MCP_VERSION', MCP_VERSION
|
|
environment 'FORGE_GROUP', project.group
|
|
environment 'FORGE_SPEC', SPEC_VERSION
|
|
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1).toString()
|
|
environment 'LAUNCHER_VERSION', SPEC_VERSION
|
|
|
|
ideaModule "${rootProject.name}.${project.name}.userdev"
|
|
|
|
source sourceSets.main
|
|
source sourceSets.userdev
|
|
|
|
args '--mod', 'forge', '--all', '--output', rootProject.file('src/generated/resources/'), '--validate',
|
|
'--existing', sourceSets.main.resources.srcDirs[0]
|
|
}
|
|
|
|
forge_test_data {
|
|
parent runs.forge_data
|
|
taskName 'forge_test_data'
|
|
|
|
environment 'MOD_CLASSES', 'dummy' // Needed to work around FG limitation, FG will replace this!
|
|
|
|
ideaModule "${rootProject.name}.${project.name}.userdev_test"
|
|
|
|
mods {
|
|
tests { sources sourceSets.test }
|
|
}
|
|
|
|
args '--flat', '--all', '--validate',
|
|
'--mod', 'data_gen_test',
|
|
'--mod', 'piston_event_test',
|
|
'--output', rootProject.file('src/generated_test/resources/'),
|
|
'--existing', sourceSets.main.resources.srcDirs[0]
|
|
}
|
|
}
|
|
}
|
|
|
|
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/mclanguageprovider/': [
|
|
'Specification-Title': 'Mod Language Provider',
|
|
'Specification-Vendor': 'Forge Development LLC',
|
|
'Specification-Version': '1',
|
|
'Implementation-Title': 'Minecraft Language Mod Provider',
|
|
'Implementation-Version': '1',
|
|
'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,
|
|
'net/minecraftforge/fml/userdev/': [
|
|
'Specification-Title': 'Forge User Development',
|
|
'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
|
|
]
|
|
}
|
|
|
|
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 {
|
|
installer 'org.ow2.asm:asm:7.2'
|
|
installer 'org.ow2.asm:asm-commons:7.2'
|
|
installer 'org.ow2.asm:asm-tree:7.2'
|
|
installer 'cpw.mods:modlauncher:5.1.+'
|
|
installer 'cpw.mods:grossjava9hacks:1.3.+'
|
|
installer 'net.minecraftforge:accesstransformers:2.1.+:shadowed'
|
|
installer 'net.minecraftforge:eventbus:2.2.+:service'
|
|
installer 'net.minecraftforge:forgespi:3.0.+'
|
|
installer 'net.minecraftforge:coremods:2.0.+'
|
|
installer 'net.minecraftforge:unsafe:0.2.+'
|
|
installer 'com.electronwill.night-config:core:3.6.2'
|
|
installer 'com.electronwill.night-config:toml:3.6.2'
|
|
installer 'org.jline:jline:3.12.+'
|
|
installer 'org.apache.maven:maven-artifact:3.6.0'
|
|
installer 'net.jodah:typetools:0.8.+'
|
|
installer 'org.apache.logging.log4j:log4j-api:2.11.2'
|
|
installer 'org.apache.logging.log4j:log4j-core:2.11.2'
|
|
installer 'net.minecrell:terminalconsoleappender:1.2.+'
|
|
installer 'net.sf.jopt-simple:jopt-simple:5.0.4'
|
|
fmllauncherImplementation 'com.google.guava:guava:21.0'
|
|
fmllauncherImplementation 'com.google.code.gson:gson:2.8.0'
|
|
fmllauncherImplementation "org.lwjgl:lwjgl:3.2.2"
|
|
fmllauncherImplementation "org.lwjgl:lwjgl-glfw:3.2.2"
|
|
fmllauncherImplementation "org.lwjgl:lwjgl-opengl:3.2.2"
|
|
fmllauncherImplementation "org.lwjgl:lwjgl-stb:3.2.2"
|
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.0'
|
|
testImplementation 'org.junit.vintage:junit-vintage-engine:5.+'
|
|
testImplementation 'org.opentest4j:opentest4j:1.0.0' // needed for junit 5
|
|
testImplementation 'org.hamcrest:hamcrest-all:1.3' // needs advanced matching for list order
|
|
}
|
|
|
|
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
|
|
genClientBinPatches.tool = BINPATCH_TOOL
|
|
task applyClientBinPatches(type: ApplyBinPatches, dependsOn: genClientBinPatches) {
|
|
clean = { genClientBinPatches.cleanJar }
|
|
input = genClientBinPatches.output
|
|
tool = BINPATCH_TOOL
|
|
}
|
|
genServerBinPatches.tool = BINPATCH_TOOL
|
|
task applyServerBinPatches(type: ApplyBinPatches, dependsOn: genServerBinPatches) {
|
|
clean = { genServerBinPatches.cleanJar }
|
|
input = genServerBinPatches.output
|
|
tool = BINPATCH_TOOL
|
|
}
|
|
genJoinedBinPatches.tool = BINPATCH_TOOL
|
|
task applyJoinedBinPatches(type: ApplyBinPatches, dependsOn: genJoinedBinPatches) {
|
|
clean = { genJoinedBinPatches.cleanJar }
|
|
input = genJoinedBinPatches.output
|
|
tool = BINPATCH_TOOL
|
|
}
|
|
// Create SRG named Vanilla jars, using the SpecialSource we have in the installer
|
|
task createClientSRG(type: RenameJar, dependsOn: genClientBinPatches) {
|
|
tool = SPECIAL_SOURCE + ':shaded'
|
|
args = ['--stable', '--in-jar', '{input}', '--out-jar', '{output}', '--srg-in', '{mappings}']
|
|
mappings = { genClientBinPatches.srg }
|
|
input = { genClientBinPatches.cleanJar }
|
|
output = file('build/createClientSRG/output.jar')
|
|
}
|
|
task createServerSRG(type: RenameJar, dependsOn: genServerBinPatches) {
|
|
tool = SPECIAL_SOURCE + ':shaded'
|
|
args = ['--stable', '--in-jar', '{input}', '--out-jar', '{output}', '--srg-in', '{mappings}']
|
|
mappings = { genServerBinPatches.srg }
|
|
input = { genServerBinPatches.cleanJar }
|
|
output = file('build/createServerSRG/output.jar')
|
|
}
|
|
// 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 downloadLibraries(dependsOn: ':mcp:setupMCP') {
|
|
inputs.file VERSION_JSON
|
|
doLast {
|
|
def json = new JsonSlurper().parseText(VERSION_JSON.text)
|
|
json.libraries.each {lib ->
|
|
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
|
|
artifacts.each{ art ->
|
|
def target = file('build/libraries/' + art.path)
|
|
if (!target.exists()) {
|
|
download {
|
|
src art.url
|
|
dest target
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
task extractInheritance(type: ExtractInheritance, dependsOn: [genJoinedBinPatches, downloadLibraries]) {
|
|
tool = INSTALLER_TOOLS + ':fatjar'
|
|
input { genJoinedBinPatches.cleanJar }
|
|
doFirst {
|
|
def json = new JsonSlurper().parseText(VERSION_JSON.text)
|
|
json.libraries.each {lib ->
|
|
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
|
|
artifacts.each{ art ->
|
|
def target = file('build/libraries/' + art.path)
|
|
if (target.exists())
|
|
addLibrary(target)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
task checkATs(dependsOn: extractInheritance) {
|
|
inputs.file { extractInheritance.output }
|
|
inputs.files patcher.accessTransformers
|
|
doLast {
|
|
def parse = { line ->
|
|
def idx = line.indexOf('#')
|
|
def comment = idx == -1 ? null : line.substring(idx)
|
|
if (idx != -1) line = line.substring(0, idx - 1)
|
|
def (modifier, cls, desc) = (line.trim() + ' ').split(' ', -1)
|
|
def key = cls + (desc.isEmpty() ? '' : ' ' + desc)
|
|
return [modifier, cls, desc, comment, key]
|
|
}
|
|
def accessLevel = { access ->
|
|
if ((access & Opcodes.ACC_PUBLIC) != 0) return 3
|
|
if ((access & Opcodes.ACC_PROTECTED) != 0) return 2
|
|
if ((access & Opcodes.ACC_PRIVATE) != 0) return 0
|
|
return 1
|
|
}
|
|
def accessStr = { access ->
|
|
if (access.endsWith('-f') || access.endsWith('+f'))
|
|
return 4
|
|
switch (access.toLowerCase()) {
|
|
case 'public': return 3
|
|
case 'protected': return 2
|
|
case 'default': return 1
|
|
case 'private': return 0
|
|
default: return -1
|
|
}
|
|
}
|
|
def json = new JsonSlurper().parseText(extractInheritance.output.text)
|
|
|
|
patcher.accessTransformers.each { f ->
|
|
TreeMap lines = [:]
|
|
def group = null
|
|
for (def line : f.readLines()) {
|
|
if (line.isEmpty()) continue
|
|
if (line.startsWith('#group ')) {
|
|
def (modifier, cls, desc, comment, key) = parse.call(line.substring(7))
|
|
|
|
if (!desc.equals('*') && !desc.equals('*()') && !desc.equals('<init>'))
|
|
throw new IllegalStateException('Invalid group: ' + line)
|
|
|
|
group = [modifier: modifier, cls: cls, desc: desc, comment: comment,
|
|
'existing': [] as Set,
|
|
'children': [] as TreeSet,
|
|
group: true
|
|
]
|
|
if (lines.containsKey(key))
|
|
throw new IllegalStateException('Duplicate group: ' + line)
|
|
|
|
lines[key] = group
|
|
} else if (group != null) {
|
|
if (line.startsWith('#endgroup')) {
|
|
group = null
|
|
} else {
|
|
def (modifier, cls, desc, comment, key) = parse.call(line)
|
|
group['existing'].add(key)
|
|
}
|
|
} else if (line.startsWith('#endgroup')) {
|
|
throw new IllegalStateException('Invalid group ending: ' + line)
|
|
} else if (line.startsWith('#')) {
|
|
//Nom
|
|
} else {
|
|
def (modifier, cls, desc, comment, key) = parse.call(line)
|
|
if (lines.containsKey(key)) {
|
|
println('Duplicate: ' + line)
|
|
continue
|
|
}
|
|
lines[key] = [modifier: modifier, cls: cls, desc: desc, comment: comment, group: false]
|
|
}
|
|
}
|
|
|
|
// Process Groups, this will remove any entries outside the group that is covered by the group
|
|
for (def key : new ArrayList<>(lines.keySet())) {
|
|
def entry = lines.get(key)
|
|
if (entry != null && entry['group']) {
|
|
def cls = entry['cls']
|
|
def jcls = json.get(cls.replaceAll('\\.', '/'))
|
|
if (jcls == null) {
|
|
lines.remove(key)
|
|
println('Invalid Group: ' + key)
|
|
} else if ('*'.equals(entry['desc'])) {
|
|
if (!jcls.containsKey('fields')) {
|
|
lines.remove(key)
|
|
println('Invalid Group, Class has no fields: ' + key)
|
|
} else {
|
|
jcls['fields'].each { field, value ->
|
|
def fkey = cls + ' ' + field
|
|
if (accessLevel.call(value['access']) < accessStr.call(entry['modifier'])) {
|
|
if (lines.containsKey(fkey)) {
|
|
lines.remove(fkey)
|
|
} else if (!entry['existing'].contains(fkey)) {
|
|
println('Added: ' + fkey)
|
|
}
|
|
entry['children'].add(fkey)
|
|
} else if (lines.containsKey(fkey)) {
|
|
lines.remove(fkey)
|
|
println('Removed: ' + fkey)
|
|
}
|
|
}
|
|
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
|
|
}
|
|
} else if ('*()'.equals(entry['desc'])) {
|
|
if (!jcls.containsKey('methods')) {
|
|
lines.remove(key)
|
|
println('Invalid Group, Class has no methods: ' + key)
|
|
} else {
|
|
jcls['methods'].each{ mtd, value ->
|
|
if (mtd.startsWith('<clinit>'))
|
|
return
|
|
key = cls + ' ' + mtd.replace(' ', '')
|
|
if (accessLevel.call(value['access']) < accessStr.call(entry['modifier'])) {
|
|
if (lines.containsKey(key)) {
|
|
lines.remove(key)
|
|
} else if (!entry['existing'].contains(key)) {
|
|
println('Added: ' + key)
|
|
}
|
|
entry['children'].add(key)
|
|
} else if (lines.containsKey(key)) {
|
|
lines.remove(key)
|
|
println('Removed: ' + key)
|
|
}
|
|
}
|
|
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
|
|
}
|
|
} else if ('<init>'.equals(entry['desc'])) { //Make all public non-abstract subclasses
|
|
json.each{ tcls,value ->
|
|
if (!value.containsKey('methods') || ((value['access'] & Opcodes.ACC_ABSTRACT) != 0))
|
|
return
|
|
def parents = [] as Set
|
|
def parent = tcls
|
|
while (parent != null && json.containsKey(parent)) {
|
|
parents.add(parent)
|
|
def p = json[parent]
|
|
parent = p == null ? null : p['superName']
|
|
}
|
|
if (parents.contains(cls.replaceAll('\\.', '/'))) {
|
|
value['methods'].each{ mtd, v ->
|
|
if (mtd.startsWith('<init>')) {
|
|
def child = tcls.replaceAll('/', '\\.') + ' ' + mtd.replace(' ', '')
|
|
if (accessLevel.call(v['access']) < 3) {
|
|
if (lines.containsKey(child)) {
|
|
lines.remove(child)
|
|
} else if (!entry['existing'].contains(child)) {
|
|
println('Added: ' + child)
|
|
}
|
|
entry['children'].add(child)
|
|
} else if (lines.containsKey(child)) {
|
|
lines.remove(child)
|
|
println('Removed: ' + child)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process normal lines, remove invalid and remove narrowing
|
|
for (def key : new ArrayList<>(lines.keySet())) {
|
|
def entry = lines.get(key)
|
|
if (entry != null && !entry['group']) {
|
|
def cls = entry['cls']
|
|
def jcls = json.get(cls.replaceAll('\\.', '/'))
|
|
if (jcls == null) {
|
|
lines.remove(key)
|
|
println('Invalid: ' + key)
|
|
} else if (entry['desc'] == '') {
|
|
if (accessLevel.call(jcls['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
|
lines.remove(key)
|
|
println('Invalid Narrowing: ' + key)
|
|
}
|
|
} else if (!entry['desc'].contains('(')) {
|
|
if (!jcls.containsKey('fields') || !jcls['fields'].containsKey(entry['desc'])) {
|
|
lines.remove(key)
|
|
println('Invalid: ' + key)
|
|
} else {
|
|
def value = jcls['fields'][entry['desc']]
|
|
if (accessLevel.call(value['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
|
lines.remove(key)
|
|
println('Invalid Narrowing: ' + key)
|
|
println(entry.comment)
|
|
}
|
|
}
|
|
} else {
|
|
def jdesc = entry['desc'].replace('(', ' (')
|
|
if (!jcls.containsKey('methods') || !jcls['methods'].containsKey(jdesc)) {
|
|
lines.remove(key)
|
|
println('Invalid: ' + key)
|
|
} else {
|
|
def value = jcls['methods'][jdesc]
|
|
if (accessLevel.call(value['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
|
|
lines.remove(key)
|
|
println('Invalid Narrowing: ' + key)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
def data = []
|
|
lines.each { key,value ->
|
|
if (!value.group) {
|
|
data.add(value.modifier + ' ' + key + (value.comment == null ? '' : ' ' + value.comment))
|
|
} else {
|
|
data.add('#group ' + value.modifier + ' ' + key + (value.comment == null ? '' : ' ' + value.comment))
|
|
value.children.each{ data.add(value.modifier + ' ' + it) }
|
|
data.add('#endgroup')
|
|
}
|
|
}
|
|
f.text = data.join('\n')
|
|
}
|
|
}
|
|
}
|
|
task checkSAS(dependsOn: extractInheritance) {
|
|
inputs.file { extractInheritance.output }
|
|
inputs.files patcher.sideAnnotationStrippers
|
|
doLast {
|
|
def json = new JsonSlurper().parseText(extractInheritance.output.text)
|
|
|
|
patcher.sideAnnotationStrippers.each { f ->
|
|
def lines = []
|
|
f.eachLine { line ->
|
|
if (line[0] == '\t') return //Skip any tabed lines, those are ones we add
|
|
def idx = line.indexOf('#')
|
|
if (idx == 0 || line.isEmpty()) {
|
|
lines.add(line)
|
|
return
|
|
}
|
|
|
|
def comment = idx == -1 ? null : line.substring(idx)
|
|
if (idx != -1) line = line.substring(0, idx - 1)
|
|
|
|
def (cls, desc) = (line.trim() + ' ').split(' ', -1)
|
|
cls = cls.replaceAll('\\.', '/')
|
|
desc = desc.replace('(', ' (')
|
|
if (desc.isEmpty() || json[cls] == null || json[cls]['methods'] == null || json[cls]['methods'][desc] == null) {
|
|
println('Invalid: ' + line)
|
|
return
|
|
}
|
|
|
|
def mtd = json[cls]['methods'][desc]
|
|
lines.add(cls + ' ' + desc.replace(' ', '') + (comment == null ? '' : ' ' + comment))
|
|
def children = json.values().findAll{ it.methods != null && it.methods[desc] != null && it.methods[desc].override == cls}
|
|
.collect { it.name + ' ' + desc.replace(' ', '') } as TreeSet
|
|
children.each { lines.add('\t' + it) }
|
|
}
|
|
f.text = lines.join('\n')
|
|
}
|
|
}
|
|
}
|
|
|
|
task checkPatchesAndFix(type: CheckPatches) {
|
|
patchDir = file("$rootDir/patches")
|
|
autoFix = true
|
|
}
|
|
|
|
task checkPatches(type: CheckPatches) {
|
|
patchDir = file("$rootDir/patches")
|
|
autoFix = false
|
|
}
|
|
project(':forge').getTasks().getByName('genPatches').finalizedBy(checkPatches)
|
|
|
|
task launcherJson(dependsOn: ['signUniversalJar', 'signLauncherJar']) {
|
|
inputs.file universalJar.archivePath
|
|
inputs.file { launcherJar.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: {},
|
|
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/*, createClientSRG, createServerSRG*/]) {
|
|
ext {
|
|
output = file('build/install_profile.json')
|
|
JAR_SPLITTER = 'net.minecraftforge:jarsplitter:1.1.2'
|
|
}
|
|
doFirst {
|
|
ext.BIN_PATCHER = BINPATCH_TOOL.substring(0, BINPATCH_TOOL.length() - 1 - BINPATCH_TOOL.split(':')[3].length())
|
|
}
|
|
inputs.file applyClientBinPatches.output
|
|
inputs.file applyServerBinPatches.output
|
|
inputs.file genClientBinPatches.toolJar
|
|
inputs.file launcherJson.output
|
|
/*
|
|
inputs.file createClientSRG.output
|
|
inputs.file createServerSRG.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,
|
|
icon: "data:image/png;base64," + new String(Base64.getEncoder().encode(Files.readAllBytes(rootProject.file("icon.ico").toPath()))),
|
|
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}-${MCP_VERSION}:slim]",
|
|
server: "[net.minecraft:server:${MC_VERSION}-${MCP_VERSION}:slim]"
|
|
],
|
|
MC_SLIM_SHA: [
|
|
client: "'${sha1(tasks.getByName('downloadClientSlim').output)}'",
|
|
server: "'${sha1(tasks.getByName('downloadServerSlim').output)}'"
|
|
],
|
|
MC_EXTRA: [
|
|
client: "[net.minecraft:client:${MC_VERSION}-${MCP_VERSION}:extra]",
|
|
server: "[net.minecraft:server:${MC_VERSION}-${MCP_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]"
|
|
],
|
|
/*MC_SRG_SHA: [
|
|
client: "'${sha1(createClientSRG.output)}'",
|
|
server: "'${sha1(createServerSRG.output)}'"
|
|
],*/
|
|
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)}'"
|
|
],
|
|
MCP_VERSION: [
|
|
client: "'${MCP_VERSION}'",
|
|
server: "'${MCP_VERSION}'"
|
|
]
|
|
],
|
|
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}',
|
|
'--extra', '{MC_EXTRA}',
|
|
'--srg', '{MAPPINGS}'
|
|
],
|
|
outputs: [
|
|
'{MC_SLIM}': '{MC_SLIM_SHA}',
|
|
'{MC_EXTRA}': '{MC_EXTRA_SHA}'
|
|
]
|
|
], [
|
|
jar: SPECIAL_SOURCE,
|
|
classpath: getClasspath(project, libs, SPECIAL_SOURCE),
|
|
args: [
|
|
//'--stable', Java 9 Is borked, https://bugs.openjdk.java.net/browse/JDK-8184940 TODO: find a fix.
|
|
'--in-jar', '{MC_SLIM}',
|
|
'--out-jar', '{MC_SRG}',
|
|
'--srg-in', '{MAPPINGS}'
|
|
]/*,
|
|
outputs: [
|
|
'{MC_SRG}': '{MC_SRG_SHA}'
|
|
]
|
|
*/
|
|
], [
|
|
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'].each { type ->
|
|
def name = "download${side.capitalize()}${type.capitalize()}"
|
|
task "${name}"(type: DownloadMavenArtifact) {
|
|
artifact = "net.minecraft:${side}:${MC_VERSION}-${MCP_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
|
|
*/
|
|
|
|
/* We do not actually check this anywhere, so it's 400KB of uselless data
|
|
// 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}-${MCP_VERSION}/server-${MC_VERSION}-${MCP_VERSION}-extra.jar"
|
|
|
|
MANIFESTS.each{ pkg, values ->
|
|
if (pkg == '/') {
|
|
manifest.attributes(values += [
|
|
'Main-Class': 'net.minecraftforge.server.ServerMain',
|
|
'Class-Path': classpath.toString(),
|
|
'ServerLaunchArgs': [
|
|
'--gameDir', '.',
|
|
'--launchTarget', 'fmlserver',
|
|
'--fml.forgeVersion', "${project.version.substring(MC_VERSION.length() + 1)}".toString(),
|
|
'--fml.mcpVersion', MCP_VERSION,
|
|
'--fml.mcVersion', MC_VERSION,
|
|
'--fml.forgeGroup', project.group
|
|
].join(' ')
|
|
])
|
|
} 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('/installer_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'
|
|
rename 'gitattributes\\.txt', '.gitattributes'
|
|
}
|
|
}
|
|
|
|
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.LaunchTesting'
|
|
|
|
environment 'target', 'fmluserdevclient'
|
|
environment 'assetIndex', '{asset_index}'
|
|
environment 'assetDirectory', '{assets_root}'
|
|
environment 'nativesDirectory', '{natives}'
|
|
|
|
environment 'MC_VERSION', "${MC_VERSION}"
|
|
environment 'FORGE_GROUP', "${project.group}"
|
|
environment 'MCP_VERSION', "${MCP_VERSION}"
|
|
environment 'MOD_CLASSES', '{source_roots}'
|
|
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
|
environment 'FORGE_VERSION', "${project.version.substring(MC_VERSION.length() + 1)}"
|
|
}
|
|
|
|
server {
|
|
main 'net.minecraftforge.userdev.LaunchTesting'
|
|
|
|
environment 'target', 'fmluserdevserver'
|
|
|
|
environment 'MC_VERSION', "${MC_VERSION}"
|
|
environment 'FORGE_GROUP', "${project.group}"
|
|
environment 'MCP_VERSION', "${MCP_VERSION}"
|
|
environment 'MOD_CLASSES', '{source_roots}'
|
|
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
|
environment 'FORGE_VERSION', "${project.version.substring(MC_VERSION.length() + 1)}"
|
|
}
|
|
|
|
data {
|
|
main 'net.minecraftforge.userdev.LaunchTesting'
|
|
|
|
environment 'target', 'fmluserdevdata'
|
|
|
|
environment 'MC_VERSION', "${MC_VERSION}"
|
|
environment 'FORGE_GROUP', "${project.group}"
|
|
environment 'MCP_VERSION', "${MCP_VERSION}"
|
|
environment 'MOD_CLASSES', '{source_roots}'
|
|
environment 'MCP_MAPPINGS', '{mcp_mappings}'
|
|
environment 'FORGE_VERSION', "${project.version.substring(MC_VERSION.length() + 1)}"
|
|
}
|
|
}
|
|
}
|
|
|
|
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.compile
|
|
srg = tasks.createMcp2Srg.output
|
|
}
|
|
|
|
userdevJar {
|
|
dependsOn userdevExtrasReobf
|
|
from (zipTree(tasks.userdevExtrasReobf.output)) {
|
|
into '/inject/'
|
|
}
|
|
from (sourceSets.userdev.output.resourcesDir) {
|
|
into '/inject/'
|
|
}
|
|
}
|
|
|
|
extractRangeMap {
|
|
addDependencies jar.archivePath
|
|
addSources sourceSets.userdev.java.srcDirs
|
|
}
|
|
applyRangeMap {
|
|
setSources sourceSets.userdev.java.srcDirs
|
|
}
|
|
|
|
tasks.eclipse.dependsOn('genEclipseRuns')
|
|
|
|
if (project.hasProperty('UPDATE_MAPPINGS')) {
|
|
extractRangeMap {
|
|
sources sourceSets.test.java.srcDirs
|
|
}
|
|
applyRangeMap {
|
|
sources sourceSets.test.java.srcDirs
|
|
}
|
|
sourceSets.test.java.srcDirs.each { extractMappedNew.addTarget it }
|
|
}
|
|
|
|
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) {
|
|
try {
|
|
def code = new URL(url).openConnection().with {
|
|
requestMethod = 'HEAD'
|
|
connect()
|
|
responseCode
|
|
}
|
|
return code == 200
|
|
} catch (Exception e) {
|
|
if (e.toString().contains('unable to find valid certification path to requested target'))
|
|
throw new RuntimeException('Failed to connect to ' + url + ': Missing certificate root authority, try updating java')
|
|
throw e
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
|