buildscript { repositories { mavenCentral() } dependencies { classpath 'org.ow2.asm:asm:6.0' } } apply plugin: 'net.minecraftforge.gradle.forge' apply plugin: 'org.spongepowered.mixin' sourceCompatibility = 1.8 targetCompatibility = 1.8 version = gitDescribe() group= "com.replaymod" archivesBaseName = "replaymod" minecraft { coreMod = 'com.replaymod.core.LoadingPlugin' runDir = "../../eclipse" replace '@MOD_VERSION@', project.version } afterEvaluate { // 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) minecraft.replace '@MC_VERSION@', "[ ${project.minecraft.version} ]" } repositories { maven { name = "SpongePowered Repo" url = "http://repo.spongepowered.org/maven/" } maven { url 'https://jitpack.io' } } configurations { shade compile.extendsFrom shade } dependencies { compile 'org.projectlombok:lombok:1.16.4' 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' 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' } 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] + '-LICENSE.txt') } } } manifest { attributes 'TweakClass': 'org.spongepowered.asm.launch.MixinTweaker', 'TweakOrder': '0', 'FMLCorePluginContainsFMLMod': 'true', 'FMLAT': 'replaymod_at.cfg' } } def gitDescribe() { try { def stdout = new ByteArrayOutputStream() exec { commandLine 'git', 'describe', '--always', '--dirty=*' standardOutput = stdout } return stdout.toString().trim() } catch (e) { return "unknown" } } 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) { include 'mcmod.info' // replace version and mcversion 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 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'