Primarily because of 1728e10 Default to no team color when receiving unknown values. 63e06fa Remove hard bitsPerEntry limit, enforce minimum of 4. 6de0593 Add CustomStatistic as fallback for custom or unimplemented statistic IDs.
349 lines
12 KiB
Groovy
349 lines
12 KiB
Groovy
buildscript {
|
|
repositories {
|
|
mavenCentral()
|
|
}
|
|
dependencies {
|
|
classpath 'org.ow2.asm:asm:6.0'
|
|
}
|
|
|
|
// This and calls to it should really also be handled by the gradle/reprod/init.gradle script
|
|
// but apparently there's no sane way to do that for external scripts in gradle :(
|
|
def convertRepoToHttp = { repo ->
|
|
if (repo instanceof MavenArtifactRepository && repo.url.toString().startsWith('https://')) {
|
|
URL url = repo.url.toURL()
|
|
repo.url = new URL("http", url.getHost(), url.getPort(), url.getFile()).toURI()
|
|
}
|
|
}
|
|
if (System.getenv('REPRODUCIBLE_BUILD') == '1') repositories.all convertRepoToHttp
|
|
}
|
|
|
|
apply plugin: 'net.minecraftforge.gradle.forge'
|
|
apply plugin: 'org.spongepowered.mixin'
|
|
|
|
sourceCompatibility = 1.8
|
|
targetCompatibility = 1.8
|
|
|
|
afterEvaluate {
|
|
version = project.minecraft.version + '-' + rootProject.version
|
|
}
|
|
group= "com.replaymod"
|
|
archivesBaseName = "replaymod"
|
|
|
|
minecraft {
|
|
coreMod = 'com.replaymod.core.LoadingPlugin'
|
|
runDir = "../../eclipse"
|
|
}
|
|
afterEvaluate {
|
|
// Note cannot use minecraft.replace because that has already been forwarded to the task by FG by now
|
|
tasks.sourceMainJava.replace '@MOD_VERSION@', project.version
|
|
// Includes intentional whitespace to stop Forge from declaring the mod to be compatible with
|
|
// a newer srg-compatible MC version (that may be using a different protocol version)
|
|
tasks.sourceMainJava.replace '@MC_VERSION@', "[ ${project.minecraft.version} ]"
|
|
}
|
|
|
|
repositories {
|
|
maven {
|
|
name = "SpongePowered Repo"
|
|
url = "http://repo.spongepowered.org/maven/"
|
|
}
|
|
maven { url 'https://jitpack.io' }
|
|
}
|
|
|
|
// And because gradle does *something*, this definition even needs to be duplicated instead of shared
|
|
def convertRepoToHttp = { repo ->
|
|
if (repo instanceof MavenArtifactRepository && repo.url.toString().startsWith('https://')) {
|
|
URL url = repo.url.toURL()
|
|
repo.url = new URL("http", url.getHost(), url.getPort(), url.getFile()).toURI()
|
|
}
|
|
}
|
|
if (System.getenv('REPRODUCIBLE_BUILD') == '1') repositories.all convertRepoToHttp
|
|
|
|
configurations {
|
|
shade
|
|
compile.extendsFrom shade
|
|
}
|
|
|
|
dependencies {
|
|
// compile 'com.github.SpongePowered:Mixin:404f5da' // 0.7.5-SNAPSHOT
|
|
// ^ mixin doesn't compile on jitpack, so we'll have to depend on the SNAPSHOT and build it manually for reprod
|
|
compile 'org.spongepowered:mixin:0.7.5-SNAPSHOT'
|
|
shade 'com.googlecode.mp4parser:isoparser:1.1.7'
|
|
shade 'org.apache.commons:commons-exec:1.3'
|
|
def withoutGuava = { exclude group: 'com.google.guava', module: 'guava-jdk5' }
|
|
shade 'com.google.apis:google-api-services-youtube:v3-rev178-1.22.0', withoutGuava
|
|
shade 'com.google.api-client:google-api-client-gson:1.20.0', withoutGuava
|
|
shade 'com.google.api-client:google-api-client-java6:1.20.0', withoutGuava
|
|
shade 'com.google.oauth-client:google-oauth-client-jetty:1.20.0'
|
|
|
|
shade 'org.aspectj:aspectjrt:1.8.2'
|
|
|
|
def studioVersion = project.name
|
|
if (studioVersion == '1.8.9') studioVersion = '1.8'
|
|
shade("com.github.ReplayMod.ReplayStudio:$studioVersion:e6f898d"){
|
|
exclude group: 'com.google.guava', module: 'guava' // provided by MC
|
|
exclude group: 'org.projectlombok', module: 'lombok' // runtime only for @SneakyThrows which isn't used
|
|
}
|
|
|
|
def jGuiVersion = project.name
|
|
if (['1.10.2', '1.11', '1.11.2'].contains(jGuiVersion)) jGuiVersion = '1.9.4'
|
|
if (['1.12.1', '1.12.2'].contains(jGuiVersion)) jGuiVersion = '1.12'
|
|
shade(project(":jGui:versions:$jGuiVersion")){
|
|
exclude group: 'org.projectlombok', module: 'lombok' // runtime only for @SneakyThrows which isn't used
|
|
}
|
|
|
|
compile 'org.projectlombok:lombok:1.16.6' // runtime only for @SneakyThrows which isn't used
|
|
|
|
testCompile 'junit:junit:4.11'
|
|
}
|
|
|
|
if (project.name != 'core') {
|
|
apply from: '../preprocessor.gradle'
|
|
|
|
def preprocessedSrc = 'build/preprocessed/src'
|
|
def preprocessedRes = 'build/preprocessed/res'
|
|
def originalSrc = '../../src/main/java'
|
|
def originalRes = '../../src/main/resources'
|
|
def (major, minor, patch) = project.name.tokenize('.')
|
|
def mcVersion = "${major}${minor.padLeft(2, '0')}${(patch ?: '').padLeft(2, '0')}"
|
|
def vars = [MC: mcVersion as int]
|
|
|
|
sourceSets {
|
|
main.java.srcDir preprocessedSrc
|
|
main.resources.srcDir preprocessedRes
|
|
}
|
|
|
|
task preprocessJava {
|
|
inputs.dir(originalSrc)
|
|
outputs.dir(preprocessedSrc)
|
|
doLast {
|
|
project.convertTree(vars, originalSrc, preprocessedSrc)
|
|
}
|
|
}
|
|
|
|
task preprocessResources {
|
|
inputs.dir(originalRes)
|
|
outputs.dir(preprocessedRes)
|
|
doLast {
|
|
project.convertTree(vars, originalRes, preprocessedRes)
|
|
}
|
|
}
|
|
|
|
compileJava.dependsOn preprocessJava
|
|
processResources.dependsOn preprocessResources
|
|
[deobfMcMCP, deobfMcSRG].each { task ->
|
|
task.dependsOn preprocessResources
|
|
}
|
|
|
|
minecraft.accessTransformer preprocessedRes + '/META-INF/replaymod_at.cfg'
|
|
}
|
|
|
|
|
|
task configureRelocation() {
|
|
dependsOn tasks.jar
|
|
dependsOn configurations.shade
|
|
doLast {
|
|
def extraSrg = tasks.reobfJar.extraSrgLines
|
|
files(configurations.shade).filter { it.exists() }.collect {
|
|
def tree = it.isDirectory() ? fileTree(it) : zipTree(it)
|
|
def pkgs = [].toSet()
|
|
tree.visit { file ->
|
|
if (!file.directory && file.name.endsWith('.class')) {
|
|
def pkg = file.path.substring(0, file.path.lastIndexOf('/'))
|
|
if (!pkg.startsWith('com/replaymod') && !pkg.startsWith('javax/')) {
|
|
pkgs << pkg
|
|
}
|
|
}
|
|
}
|
|
pkgs
|
|
}.flatten().unique().each { pkg ->
|
|
extraSrg << "PK: $pkg com/replaymod/lib/$pkg".toString()
|
|
}
|
|
}
|
|
}
|
|
tasks.reobfJar.dependsOn configureRelocation
|
|
|
|
jar {
|
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
|
|
dependsOn configurations.compile
|
|
dependsOn configurations.shade
|
|
|
|
def shade = {files(
|
|
configurations.compile.findAll {it.name.startsWith 'mixin-'}
|
|
+ configurations.shade
|
|
)}
|
|
|
|
def noticeDir = file("$buildDir/NOTICE")
|
|
doFirst {
|
|
noticeDir.deleteDir()
|
|
noticeDir.mkdirs()
|
|
shade().collect { it.isDirectory() ? fileTree(it) : zipTree(it) }.each {
|
|
it.matching { include '**/NOTICE*' }.each {
|
|
new File(noticeDir, 'NOTICE.txt') << it.getText('UTF-8') + '\n'
|
|
}
|
|
}
|
|
}
|
|
from noticeDir
|
|
|
|
from ({shade().collect { it.isDirectory() ? it : zipTree(it) }}) {
|
|
exclude '**/NOTICE*'
|
|
eachFile {
|
|
if (getName() == 'LICENSE.txt') {
|
|
setName(getFile().getParentFile().getName().split('.jar_')[0].tokenize('-')[0] + '-LICENSE.txt')
|
|
}
|
|
}
|
|
}
|
|
|
|
manifest {
|
|
attributes 'TweakClass': 'org.spongepowered.asm.launch.MixinTweaker',
|
|
'TweakOrder': '0',
|
|
'FMLCorePluginContainsFMLMod': 'true',
|
|
'FMLAT': 'replaymod_at.cfg'
|
|
}
|
|
}
|
|
|
|
processResources
|
|
{
|
|
// this will ensure that this task is redone when the versions change.
|
|
inputs.property 'version', { project.version }
|
|
inputs.property 'mcversion', { project.minecraft.version }
|
|
|
|
// replace stuff in mcmod.info, nothing else
|
|
from(sourceSets.main.resources.srcDirs) { spec ->
|
|
include 'mcmod.info'
|
|
|
|
// replace version and mcversion
|
|
afterEvaluate {
|
|
spec.expand 'version': project.version, 'mcversion': project.minecraft.version
|
|
}
|
|
}
|
|
|
|
// copy everything else, thats not the mcmod.info
|
|
from(sourceSets.main.resources.srcDirs) {
|
|
exclude 'mcmod.info'
|
|
}
|
|
}
|
|
|
|
sourceSets {
|
|
main {
|
|
ext.refMap = "mixins.replaymod.refmap.json"
|
|
}
|
|
integrationTest {
|
|
compileClasspath += main.runtimeClasspath + main.output
|
|
java {
|
|
srcDir file('src/integration-test/java')
|
|
}
|
|
resources.srcDir file('src/integration-test/resources')
|
|
}
|
|
}
|
|
|
|
task copySrg(type: Copy, dependsOn: 'genSrgs') {
|
|
from {project.tasks.genSrgs.mcpToSrg}
|
|
into 'build'
|
|
}
|
|
|
|
setupDecompWorkspace.dependsOn copySrg
|
|
setupDevWorkspace.dependsOn copySrg
|
|
project.tasks.idea.dependsOn copySrg
|
|
|
|
// Mixin uses multiple HashMaps to generate the refmap.
|
|
// HashMaps are unordered collections and as such do not produce deterministic output.
|
|
// To fix that, we simply sort the refmap json file.
|
|
import groovy.json.JsonSlurper
|
|
import groovy.json.JsonOutput
|
|
compileJava.doLast {
|
|
File refmapFile = compileJava.ext.refMapFile
|
|
if (refmapFile.exists()) {
|
|
def ordered
|
|
ordered = {
|
|
if (it instanceof Map) {
|
|
def sorted = new TreeMap(it)
|
|
sorted.replaceAll { k, v -> ordered(v) }
|
|
sorted
|
|
} else if (it instanceof List) {
|
|
it.replaceAll { v -> ordered(v) }
|
|
} else {
|
|
it
|
|
}
|
|
}
|
|
def json = JsonOutput.toJson(ordered(new JsonSlurper().parse(refmapFile)))
|
|
refmapFile.withWriter { it.write json }
|
|
}
|
|
}
|
|
|
|
import java.util.zip.ZipEntry
|
|
import java.util.zip.ZipFile
|
|
import java.util.zip.ZipOutputStream
|
|
|
|
import org.objectweb.asm.*
|
|
|
|
import static org.objectweb.asm.Opcodes.ASM5
|
|
|
|
// MC binaries were complied with a java version that produces invalid class files under certain circumstances
|
|
// This causes setupCIWorkspace to be insufficient for compiling.
|
|
// Related JDK bug: https://bugs.openjdk.java.net/browse/JDK-8066725
|
|
// As a workaround, to use setupCIWorkspace on Drone, we modify the bin jar in-place and remove all parameter annotations.
|
|
// WARNING: This piece of code ignores any and all gradle conventions and will probably fail horribly when run outside
|
|
// of a single-use environment (e.g. Drone). Use setupDecompWorkspace for normal use.
|
|
tasks.deobfMcMCP.doLast {
|
|
println "Applying RuntimeInvisibleParameterAnnotations workaround..."
|
|
File jar = getOutJar()
|
|
File tmp = new File((File) getTemporaryDir(), "workaround.jar")
|
|
tmp.withOutputStream {
|
|
new ZipOutputStream(it).withStream { dst ->
|
|
new ZipFile(jar).withCloseable { src ->
|
|
src.entries().each {
|
|
if (it.name.startsWith("net/minecraft/") && it.name.endsWith(".class")) {
|
|
def cw = new ClassWriter(0)
|
|
def cv = new ClassVisitor(ASM5, cw) {
|
|
@Override
|
|
MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
|
return new MethodVisitor(ASM5, cv.visitMethod(access, name, desc, signature, exceptions)) {
|
|
@Override
|
|
AnnotationVisitor visitParameterAnnotation(int parameter, String pdesc, boolean visible) {
|
|
return null // Strip all parameter annotations
|
|
}
|
|
}
|
|
}
|
|
}
|
|
new ClassReader(src.getInputStream(it)).accept(cv, 0)
|
|
dst.putNextEntry(new ZipEntry(it.name))
|
|
dst.write(cw.toByteArray())
|
|
} else {
|
|
dst.putNextEntry(it)
|
|
dst.write(src.getInputStream(it).bytes)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
jar.delete()
|
|
tmp.renameTo(jar)
|
|
}
|
|
|
|
task runIntegrationTest(type: JavaExec, dependsOn: ["makeStart", "jar"]) {
|
|
main = 'GradleStart'
|
|
standardOutput = System.out
|
|
errorOutput = System.err
|
|
workingDir file(minecraft.runDir)
|
|
|
|
def testDir = new File(minecraft.runDir, "integration-test")
|
|
doFirst {
|
|
testDir.deleteDir()
|
|
testDir.mkdirs()
|
|
}
|
|
|
|
doLast {
|
|
testDir.deleteDir()
|
|
}
|
|
|
|
afterEvaluate {
|
|
def runClient = tasks.getByName("runClient")
|
|
runIntegrationTest.jvmArgs = runClient.jvmArgs + "-Dfml.noGrab=true"
|
|
runIntegrationTest.args = runClient.args + "--gameDir" + testDir.canonicalPath
|
|
runIntegrationTest.classpath runClient.classpath + sourceSets.integrationTest.output
|
|
}
|
|
}
|
|
|
|
defaultTasks 'build'
|