From db6ab2a19e2eff692b57efd7989d0699b59846c1 Mon Sep 17 00:00:00 2001 From: LexManos Date: Sun, 23 Feb 2020 23:17:23 -0800 Subject: [PATCH] Migrate to FG3 --- .gitignore | 11 + Jenkinsfile | 2 +- build.gradle | 1329 +++++++++++------ gradle/wrapper/gradle-wrapper.jar | Bin 52271 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 110 +- gradlew.bat | 14 +- mdk/README.txt | 33 +- mdk/build.gradle | 143 +- .../.projects/MDKExample/.location | 0 .../org.eclipse.core.resources/.root/0.tree | Bin 468 -> 0 bytes .../org.eclipse.core.resources.prefs | 4 - .../.settings/org.eclipse.debug.ui.prefs | 7 - .../org.eclipse.epp.usagedata.gathering.prefs | 3 - .../.settings/org.eclipse.jdt.core.prefs | 14 - .../.settings/org.eclipse.ui.editors.prefs | 4 - .../.settings/org.eclipse.ui.ide.prefs | 9 - .../.settings/org.eclipse.ui.prefs | 3 - .../.launches/Client.launch | 13 - .../.launches/Server.launch | 13 - .../launchConfigurationHistory.xml | 25 - mdk/gitignore.txt | 3 + mdk/gradle.properties | 1 + .../entity/monster/EntityEvoker.java.patch | 2 +- settings.gradle | 10 +- 25 files changed, 1106 insertions(+), 650 deletions(-) delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.resources/.projects/MDKExample/.location delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.resources/.root/0.tree delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.epp.usagedata.gathering.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.editors.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Client.launch delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Server.launch delete mode 100644 mdk/eclipse/.metadata/.plugins/org.eclipse.debug.ui/launchConfigurationHistory.xml diff --git a/.gitignore b/.gitignore index 429a832e08..b866fbae95 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,14 @@ changelog.txt /patches_old_bak/ *.py *.7z +.project +/mdk/.gradle/ +/mdk/.settings/ +/mdk/bin/ +/mdk/build/ +/mdk/crash-reports/ +/mdk/logs/ +/mdk/resourcepacks/ +/mdk/run/ +*.launch +*.classpath diff --git a/Jenkinsfile b/Jenkinsfile index 18a3bf346c..75d0c553e8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -73,7 +73,7 @@ pipeline { KEYSTORE_STOREPASS = credentials('forge-jenkins-keystore-old-keypass') } steps { - sh './gradlew ${GRADLE_ARGS} uploadArchives -PforgeMavenUser=${FORGE_MAVEN_USR} -PforgeMavenPassword=${FORGE_MAVEN_PSW} -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}' + sh './gradlew ${GRADLE_ARGS} :forge:publish -PforgeMavenUser=${FORGE_MAVEN_USR} -PforgeMavenPassword=${FORGE_MAVEN_PSW} -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}' sh 'curl --user ${FORGE_MAVEN} http://files.minecraftforge.net/maven/manage/promote/latest/${MYGROUP}.${MYARTIFACT}/${MYVERSION}' } } diff --git a/build.gradle b/build.gradle index c9c79ef4ac..299decaf11 100644 --- a/build.gradle +++ b/build.gradle @@ -1,71 +1,57 @@ buildscript { repositories { mavenLocal() + maven { url = 'https://files.minecraftforge.net/maven' } + jcenter() mavenCentral() - maven { - name = "forge" - url = "https://files.minecraftforge.net/maven" - } - maven { - name = "sonatype" - url = "https://oss.sonatype.org/content/repositories/snapshots/" - } - maven { - url "https://plugins.gradle.org/m2/" - } } dependencies { - classpath 'edu.sc.seis.launch4j:launch4j:2.4.6' - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.+' + classpath 'org.ow2.asm:asm:7.1' + classpath 'org.ow2.asm:asm-tree:7.1' + classpath 'com.github.jponge:lzma-java:1.3' //Needed to compress deobf data } } +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.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.GenerateBinPatches +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 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: "maven" -def patcher_plugin = plugins.apply('net.minecraftforge.gradle.patcher') -apply plugin: 'edu.sc.seis.launch4j' - -minecraft.version = "1.12.2" - -minecraft { - mappings = 'snapshot_nodoc_20171003' - workspaceDir = "projects" - versionJson = "jsons/${minecraft.version}-dev.json" - buildUserdev = true - buildInstaller = true - installerVersion = "1.5" - - def common = { - patchPrefixOriginal "../src-base/minecraft" - patchPrefixChanged "../src-work/minecraft" - mainClassClient "net.minecraft.launchwrapper.Launch" - tweakClassClient "net.minecraftforge.fml.common.launcher.FMLTweaker" - mainClassServer "net.minecraft.launchwrapper.Launch" - tweakClassServer "net.minecraftforge.fml.common.launcher.FMLServerTweaker" - } - - projects { - forge { - rootDir "." - patchDir "patches/minecraft" - patchAfter "clean" - genPatchesFrom "clean" - genMcpPatches = false - applyMcpPatches = false - s2sKeepImports = true - with common - } - } -} +apply plugin: 'eclipse' ext { - //Dirty hack, but keeps our unique version system on new jenkins - BUILD_NUMBER = 2838 + (System.getenv('BUILD_NUMBER') ?: project.ext.properties.buildNumber ?: 0).toInteger() - - JAR_SIGNER = [:] + JAR_SIGNER = null if (project.hasProperty('keystore')) { JAR_SIGNER = [ storepass: project.properties.keystoreStorePass, @@ -73,416 +59,925 @@ ext { keystore: project.properties.keystore ] } + MAPPING_CHANNEL = 'snapshot' + MAPPING_VERSION = '20171003-1.12' + MC_VERSION = '1.12.2' + MCP_VERSION = '20200226.224830' + POST_PROCESSOR = [ + tool: 'net.minecraftforge:mcpcleanup:2.3.2:fatjar', + repo: 'https://files.minecraftforge.net/maven/', + args: ['--input', '{input}', '--output', '{output}'] + ] } -group = 'net.minecraftforge' -version = getVersionFromJava(file("src/main/java/net/minecraftforge/common/ForgeVersion.java")) - -extractForgeSources { exclude "**/SideOnly.java", "**/Side.java" } -extractForgeResources { exclude "**/log4j2.xml" } - -genGradleProjects { - addTestCompileDep "junit:junit:4.12" // TODO update unit tests to junit 5 and remove this - addTestCompileDep "org.junit.jupiter:junit-jupiter-api:5.0.0" - addTestCompileDep "org.opentest4j:opentest4j:1.0.0" // needed for junit 5 - addTestCompileDep "org.hamcrest:hamcrest-core:1.3" - filter { dep -> !dep.contains("scala") } +project(':mcp') { + apply plugin: 'net.minecraftforge.gradle.mcp' + mcp { + config = MC_VERSION + '-' + MCP_VERSION + pipeline = 'joined' + } } -processJson { - releaseJson = "jsons/${minecraft.version}-rel.json" - addReplacements([ - "@minecraft_version@": project.minecraft.version, - "@version@": project.version, - "@project@": "forge", - "@artifact@": "net.minecraftforge:forge:${project.version}", - "@universal_jar@": { outputJar.archiveName }, - "@timestamp@": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - ]) +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 { + mavenCentral() + } + + dependencies { + implementation 'net.minecraftforge:mergetool:0.2.3.3:forge' + } + + patcher { + parent = project(':mcp') + mcVersion = MC_VERSION + patchedSrc = file('src/main/java') + + mappings channel: MAPPING_CHANNEL, version: MAPPING_VERSION + processor = POST_PROCESSOR + + 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.MinecraftServer' + 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' -license { - header = project.file('LICENSE-header.txt') - - include 'net/minecraftforge/' - exclude 'net/minecraftforge/api/distmarker/' - exclude 'net/minecraftforge/fml/repackage/' - exclude 'net/minecraftforge/server/terminalconsole/' - 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 { + sourceSets { main { - files = project.files('src/main/java') + java { + srcDirs = ["$rootDir/src/main/java"] + } + resources { + srcDirs = ["$rootDir/src/main/resources"] + } } test { - files = project.files('src/test/java') + compileClasspath += sourceSets.main.runtimeClasspath + runtimeClasspath += sourceSets.main.runtimeClasspath + java { + srcDirs = ["$rootDir/src/test/java"] + } + resources { + srcDirs = ["$rootDir/src/test/resources"] + } + } + userdev { + compileClasspath += sourceSets.main.runtimeClasspath + runtimeClasspath += sourceSets.main.runtimeClasspath + java { + srcDirs = ["$rootDir/src/userdev/java"] + } + resources { + srcDirs = ["$rootDir/src/userdev/resources"] + } } } -} + //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() + } -task changelog() { ext { - changelog_old = rootProject.file('legacy_changelog.txt') - changelog_new = rootProject.file('build/changelog_new.txt') - output = rootProject.file('build/changelog.txt') + LEGACY_MAJOR = 14 //Legacy versions have a API change prefix + LEGACY_BUILD = 2848 //Base build number to not conflict with existing build numbers + BUILD_NUMBER = 0 // LEGACY_BUILD + commit offset, used to mimic unique build from old versions + + SPEC_VERSION = '23.5' // This is overwritten by git tag, but here so dev time doesnt explode + 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.1.1:fatjar' } - inputs.file changelog_old - if (changelog_new.exists()) - inputs.file changelog_new - outputs.file output - - doLast { - output.text = changelog_new.text + '\n' + changelog_old.text + + 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 + BUILD_NUMBER = LEGACY_BUILD + offset.toInteger() + return "${MC_VERSION}-${LEGACY_MAJOR}.${tag}.${BUILD_NUMBER}${t -> if (branch != null) t << '-' + branch}".toString() //Bake the response instead of making it dynamic } -} -task crowdin(type: CrowdinDownload) { - output = "build/crowdin.zip" - projectId = 'minecraft-forge' - extract = false // we wanna keep it as a zip. not extract it to a folder named "crowdin.zip" - - // task auomatically skips if this is null - if (project.hasProperty('crowdinKey')) - apiKey = project.crowdinKey -} + version = getVersion() -def extraTxts = [ - "CREDITS.txt", - "LICENSE.txt", - "LICENSE-Paulscode SoundSystem CodecIBXM.txt", - "LICENSE-Paulscode IBXM Library.txt", - changelog -] + patcher { + exc = file("$rootDir/src/main/resources/forge.exc") + parent = project(':clean') + patches = file("$rootDir/patches/minecraft") + patchedSrc = file('src/main/java') + srgPatches = true + notchObf = true + accessTransformer = file("$rootDir/src/main/resources/forge_at.cfg") + //sideAnnotationStripper = file("$rootDir/src/main/resources/forge.sas") + processor = POST_PROCESSOR -import groovy.json.JsonSlurper; -import groovy.json.JsonBuilder; + runs { + forge_client { + taskName 'forge_client' + main 'net.minecraftforge.legacydev.MainClient' -task extractAnnotationsVanilla(type: net.minecraftforge.gradle.tasks.TaskExtractAnnotationsText, dependsOn: deobfuscateJar) { - jar = deobfuscateJar.outJar - output = 'build/vanilla_annotations_raw.json' - doLast { //Re-dump it so it's in groovy's sorted order. Because I like being able to do diffs against things. - def json = new JsonSlurper().parseText(file(output).text) - file(output).write(new JsonBuilder(json).toPrettyString()) - } -} + environment 'tweakClass', 'net.minecraftforge.fml.common.launcher.FMLTweaker' + environment 'mainClass', 'net.minecraft.launchwrapper.Launch' + environment 'assetIndex', '{asset_index}' + environment 'assetDirectory', '{assets_root}' + environment 'nativesDirectory', '{natives}' + environment 'MC_VERSION', '${MC_VERSION}' + environment 'MCP_MAPPINGS', '{mcp_mappings}' + environment 'MCP_TO_SRG', '{mcp_to_srg}' + environment 'FORGE_GROUP', "${project.group}" + environment 'FORGE_VERSION', "${project.version.substring(MC_VERSION.length() + 1)}" + } -task reobfToSRG(type: net.minecraftforge.gradle.patcher.TaskReobfuscate, dependsOn: reobfuscate) { - srg = patcher_plugin.delayedFile('{CACHE_DIR}/de/oceanlabs/mcp/mcp_{MAPPING_CHANNEL}/{MAPPING_VERSION}/{MC_VERSION}/srgs/mcp-srg.srg') - exc = reobfuscate.exc - preFFJar = reobfuscate.preFFJar - methodsCsv = reobfuscate.methodsCsv - fieldsCsv = reobfuscate.fieldsCsv - addLibs reobfuscate.libs - inJar = patcher_plugin.delayedFile('{BUILD_DIR}/localCache/Forge/recompiled.jar') - outJar = 'build/forge_srg.jar' -} + forge_server { + taskName 'forge_server' + main 'net.minecraftforge.legacydev.MainServer' -task extractAnnotationsForgeSRG(type: net.minecraftforge.gradle.tasks.TaskExtractAnnotationsText, dependsOn: reobfToSRG) { - jar = reobfToSRG.outJar - output = 'build/forge_annotations.json' - doLast { //Re-dump it so it's in groovy's sorted order. Because I like being able to do diffs against things. - def json = new JsonSlurper().parseText(file(output).text) - json.entrySet().removeIf{e -> (!e.key.startsWith('net/minecraft/') && !e.key.startsWith('net/minecraftforge/')) || e.key.endsWith('/package-info')} - file(output).write(new JsonBuilder(json).toPrettyString()) - } -} - -task fixAnnotationsJson(dependsOn: [extractAnnotationsVanilla, extractAnnotationsForgeSRG, genPatches]) { - inputs.file(extractAnnotationsVanilla.output) - inputs.file(extractAnnotationsForgeSRG.output) - outputs.file('build/vanilla_annotations.json') - doLast { - def json_vanilla = new JsonSlurper().parseText(file(extractAnnotationsVanilla.output).text) as TreeMap - def json_forge = new JsonSlurper().parseText(file(extractAnnotationsForgeSRG.output).text) as TreeMap - def start = minecraft.projects.forge.patchDir.absolutePath.length() - file(minecraft.projects.forge.patchDir).traverse(type: groovy.io.FileType.FILES, nameFilter: {nf -> nf.endsWith('.java.patch')}) { f -> - def cls = f.absolutePath.substring(start+1).replace('\\', '/').replace('.java.patch', '') - json_vanilla.entrySet().removeIf{e -> e.key == cls || e.key.startsWith(cls + '$')} - json_forge.entrySet().stream().filter{e -> e.key == cls || e.key.startsWith(cls + '$')}.forEach{e -> json_vanilla.put(e.key, e.value)} + environment 'tweakClass', 'net.minecraftforge.fml.common.launcher.FMLServerTweaker' + environment 'mainClass', 'net.minecraft.launchwrapper.Launch' + environment 'MC_VERSION', '${MC_VERSION}' + environment 'MCP_MAPPINGS', '{mcp_mappings}' + environment 'MCP_TO_SRG', '{mcp_to_srg}' + environment 'FORGE_GROUP', "${project.group}" + environment 'FORGE_VERSION', "${project.version.substring(MC_VERSION.length() + 1)}" + } + } + } + + 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/common/': [ + '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 + ] + } + + applyPatches { + canonicalizeAccess true + canonicalizeWhitespace true + maxFuzz 3 + originalPrefix = '../src-base/minecraft/' + modifiedPrefix = '../src-work/minecraft/' + } + genPatches { + originalPrefix = '../src-base/minecraft/' + modifiedPrefix = '../src-work/minecraft/' + } + 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-debug-all:5.2' + installer 'net.minecraft:launchwrapper:1.12' + installer 'org.jline:jline:3.5.1' + installer 'com.typesafe.akka:akka-actor_2.11:2.3.3' + installer 'com.typesafe:config:1.2.1' + installer 'org.scala-lang:scala-actors-migration_2.11:1.1.0' + installer 'org.scala-lang:scala-compiler:2.11.1' + installer 'org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2_mc' //We change the version so old installs don't break, as our clone of the jar is different the maven central + installer 'org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2_mc' // --^ + installer 'org.scala-lang:scala-library:2.11.1' + installer 'org.scala-lang:scala-parser-combinators_2.11:1.0.1' + installer 'org.scala-lang:scala-reflect:2.11.1' + installer 'org.scala-lang:scala-swing_2.11:1.0.1' + installer 'org.scala-lang:scala-xml_2.11:1.0.2' + installer 'lzma:lzma:0.0.1' + installer 'java3d:vecmath:1.5.2' + installer 'net.sf.trove4j:trove4j:3.0.3' + installer 'org.apache.maven:maven-artifact:3.5.3' + + 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'), + rootProject.file('LICENSE-Paulscode IBXM Library.txt'), + rootProject.file('LICENSE-Paulscode SoundSystem CodecIBXM.txt') + ] + + def changelog = rootProject.file('build/changelog.txt') + if (changelog.exists()) + extraTxts += changelog + + // 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 + genJoinedBinPatches.tool = BINPATCH_TOOL + task genRuntimeBinPatches(type: GenerateBinPatches, dependsOn: [genClientBinPatches, genServerBinPatches]) { + tool = BINPATCH_TOOL + } + afterEvaluate { p -> + genRuntimeBinPatches { + cleanJar = genClientBinPatches.cleanJar + dirtyJar = genClientBinPatches.dirtyJar + srg = genClientBinPatches.srg + patchSets = genClientBinPatches.patchSets + args = [ + '--output', '{output}', + '--patches', '{patches}', + '--srg', '{srg}', + '--legacy', + + '--clean', '{clean}', + '--dirty', '{dirty}', + '--prefix', 'binpatch/client', + + '--clean', '{server}', + '--dirty', '{dirty}', + '--prefix', 'binpatch/server' + ] + addExtra('server', genServerBinPatches.cleanJar) + } + } + + 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]) { + 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: genJoinedBinPatches) { + inputs.file { genJoinedBinPatches.cleanJar } + inputs.files patcher.accessTransformers + doLast { + def vanilla = [:] + def zip = new java.util.zip.ZipFile(genJoinedBinPatches.cleanJar) + zip.entries().findAll { !it.directory && it.name.endsWith('.class') }.each { entry -> + new ClassReader(zip.getInputStream(entry)).accept(new org.objectweb.asm.ClassVisitor(org.objectweb.asm.Opcodes.ASM7) { + String name + void visit(int version, int access, String name, String sig, String superName, String[] interfaces) { + this.name = name + vanilla[name] = access + } + org.objectweb.asm.FieldVisitor visitField(int access, String name, String desc, String sig, Object value) { + vanilla[this.name + ' ' + name] = access + return null + } + org.objectweb.asm.MethodVisitor visitMethod(int access, String name, String desc, String sig, String[] excs) { + vanilla[this.name + ' ' + name + desc] = access + return null + } + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) + } + patcher.accessTransformers.each { f -> + TreeMap lines = [:] + f.eachLine { line -> + def idx = line.indexOf('#') + if (idx == 0 || line.isEmpty()) return + 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) + def access = vanilla[key.replace('.', '/')] + if (access == null) { + if ((desc.equals('*') || desc.equals('*()')) && vanilla[cls.replace('.', '/')] != null) + println('Warning: ' + line) + else { + println('Invalid: ' + line) + return + } + } + //TODO: Check access actually changes, and expand inheretence? + lines[key] = [modifier: modifier, comment: comment] + } + f.text = lines.collect{ it.value.modifier + ' ' + it.key + (it.value.comment == null ? '' : ' ' + it.value.comment) }.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 launcherJson(dependsOn: ['signUniversalJar']) { + 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: 'net.minecraft.launchwrapper.Launch', + inheritsFrom: MC_VERSION, + logging: {}, + minecraftArguments: [ + '--username', '${auth_player_name}', + '--version', '${version_name}', + '--gameDir', '${game_directory}', + '--assetsDir', '${assets_root}', + '--assetIndex', '${assets_index_name}', + '--uuid', '${auth_uuid}', + '--accessToken', '${auth_access_token}', + '--userType', '${user_type}', + '--tweakClass', 'net.minecraftforge.fml.common.launcher.FMLTweaker', + '--versionType', 'Forge' + ].join(' '), + libraries: [ + [ + //Package our universal 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(universalJar.archivePath), + size: universalJar.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/*, createClientSRG, createServerSRG*/]) { + ext { + output = file('build/install_profile.json') + INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.1.4' + } + inputs.file universalJar.archivePath + inputs.file genClientBinPatches.toolJar + inputs.file launcherJson.output + outputs.file output + doLast { + def libs = [ + "${project.group}:${project.name}:${project.version}": [ + 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(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: [ + ], + processors: [ + ] + ] + 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() + } + } + + task extractObf2Srg(type:net.minecraftforge.gradle.common.task.ExtractMCPData, dependsOn: [':mcp:downloadConfig']) { + config = project(':mcp').downloadConfig.output + } + + task deobfDataLzma(dependsOn: [extractObf2Srg]) { + ext { + output_srg = file('build/deobfDataLzma/data.srg') + output = file('build/deobfDataLzma/data.lzma') + } + inputs.file extractObf2Srg.output + outputs.file output + doLast { + net.minecraftforge.gradle.common.util.MappingFile.load(extractObf2Srg.output) + .write(net.minecraftforge.gradle.common.util.MappingFile.Format.SRG, output_srg) + + output_srg.withInputStream { ins -> + output.withOutputStream { outs -> + def lz = new lzma.streams.LzmaOutputStream.Builder(outs).useEndMarkerMode(true).build() + + def i = -1 + def buf = new byte[0x100] + while ((i = ins.read(buf)) != -1) + lz.write(buf, 0, i) + + lz.close() + } + } + } + } + + universalJar { + from(extraTxts) + dependsOn(deobfDataLzma) + from(deobfDataLzma.output){ + rename{"deobfuscation_data-${MC_VERSION}.lzma"} + } + dependsOn(genRuntimeBinPatches) + from(genRuntimeBinPatches.output) { + rename{'binpatches.pack.lzma'} + } + doFirst { + MANIFESTS.each{ pkg, values -> + if (pkg == '/') { + manifest.attributes(values) + } 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']) { + 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(universalJar) { + 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, 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('net.minecraftforge:legacydev:0.2.3.+:fatjar') + addUniversalFilter('^(?!binpatches\\.pack\\.lzma$).*$') + + runs { + client { + main 'net.minecraftforge.legacydev.MainClient' + + environment 'tweakClass', 'net.minecraftforge.fml.common.launcher.FMLTweaker' + environment 'mainClass', 'net.minecraft.launchwrapper.Launch' + environment 'assetIndex', '{asset_index}' + environment 'assetDirectory', '{assets_root}' + environment 'nativesDirectory', '{natives}' + environment 'MC_VERSION', '${MC_VERSION}' + environment 'MCP_MAPPINGS', '{mcp_mappings}' + environment 'MCP_TO_SRG', '{mcp_to_srg}' + environment 'FORGE_GROUP', "${project.group}" + environment 'FORGE_VERSION', "${project.version.substring(MC_VERSION.length() + 1)}" + } + + server { + main 'net.minecraftforge.legacydev.MainServer' + + environment 'tweakClass', 'net.minecraftforge.fml.common.launcher.FMLServerTweaker' + environment 'mainClass', 'net.minecraft.launchwrapper.Launch' + environment 'MC_VERSION', '${MC_VERSION}' + environment 'MCP_MAPPINGS', '{mcp_mappings}' + environment 'MCP_TO_SRG', '{mcp_to_srg}' + environment 'FORGE_GROUP', "${project.group}" + 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/' + } + classifier 'userdev3' + } + + 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 + + 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.12.x/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() + } + } } - json_forge.entrySet().stream().filter{e -> e.key.startsWith('net/minecraftforge/')}.forEach{e -> json_vanilla.put(e.key, e.value)} - outputs.files.singleFile.write(new JsonBuilder(json_vanilla).toPrettyString()) } } - -outputJar { - classifier = 'universal' - from extraTxts - from(fixAnnotationsJson){ - into 'META-INF' - } - dependsOn fixAnnotationsJson - - // add crowdin locales - from { crowdin.getDidWork() ? zipTree(crowdin.output) : null} - dependsOn 'crowdin' - - manifest.attributes([ - "Main-Class": "net.minecraftforge.fml.relauncher.ServerLaunchWrapper", - "TweakClass": "net.minecraftforge.fml.common.launcher.FMLTweaker", - "Class-Path": getServerClasspath(file("jsons/${minecraft.version}-rel.json")) - ]) +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] } -installer { - classifier = 'installer' - from extraTxts - from "src/main/resources/forge_logo.png" - from "src/main/resources/url.png" - rename "forge_logo\\.png", "big_logo.png" +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() } -task signUniversal(type: SignJar, dependsOn: 'outputJar') { - onlyIf { - project.hasProperty('jarsigner') - } - - alias = 'forge' - exclude "paulscode/**" - storePass = JAR_SIGNER.storepass - keyPass = JAR_SIGNER.keypass - keyStore = JAR_SIGNER.keystore - inputFile = outputJar.archivePath - outputFile = outputJar.archivePath +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) } -uploadArchives.dependsOn signUniversal -build.dependsOn signUniversal -installer.dependsOn signUniversal -// MDK package - -import org.apache.tools.ant.filters.ReplaceTokens -task makeMdk(type: Zip) { - baseName = project.name - classifier = "mdk" - version = project.version - destinationDir = file('build/distributions') - - from 'gradlew' - from 'gradlew.bat' - from extraTxts - into ('gradle') { - from 'gradle' - } - into ('eclipse') { - from 'mdk/eclipse' - } - from ('mdk') { - filter(ReplaceTokens, tokens: [ - VERSION: project.version, - MAPPINGS: minecraft.mappings.replace('nodoc_', '') - ]) - exclude 'eclipse' - rename 'gitignore\\.txt', '.gitignore' +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 } -tasks.build.dependsOn makeMdk -// launch4j - -launch4j { - jar = installer.archivePath.canonicalPath - outfile = "${project.name}-${project.version}-installer-win.exe" - icon = file('icon.ico').canonicalPath - manifest = file('l4jManifest.xml').canonicalPath - jreMinVersion = '1.8.0_101' - initialHeapPercent = 5 - maxHeapPercent = 100 -} -tasks.createExe.dependsOn installer -tasks.build.dependsOn 'launch4j' - -// MAVEN - -artifacts { - archives(changelog.outputs.files.singleFile) { - classifier = 'changelog' +def checkExists(url) { + def code = new URL(url).openConnection().with { + requestMethod = 'HEAD' + connect() + responseCode } - archives file('build/' + launch4j.outputDir + '/' + launch4j.outfile) - archives makeMdk + 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 } task ciWriteBuildNumber << { - def file = file("src/main/java/net/minecraftforge/common/ForgeVersion.java"); - def outfile = ""; - def ln = "\n"; //Linux line endings because we're on git! + def file = file('src/main/java/net/minecraftforge/common/ForgeVersion.java'); + def outfile = ''; + def ln = '\n'; //Linux line endings because we're on git! file.eachLine{ String s -> - if (s.matches("^ public static final int buildVersion = [\\d]+;\$")) - s = " public static final int buildVersion = ${BUILD_NUMBER};"; + if (s.matches('^ public static final int buildVersion = [\\d]+;\$')) + s = " public static final int buildVersion = ${project(':forge').BUILD_NUMBER};" if (s.matches('^ public static final String mcVersion = "[^\\"]+";')) - s = " public static final String mcVersion = \"${minecraft.version}\";"; + s = " public static final String mcVersion = \"${MC_VERSION}\";" outfile += (s+ln); } file.write(outfile); } -uploadArchives { - repositories.mavenDeployer { - - dependsOn 'build' - - if (project.hasProperty('forgeMavenPassword')) - { - repository(url: "https://files.minecraftforge.net/maven/manage/upload") { - authentication(userName: project.getProperty('forgeMavenUser'), password: project.getProperty('forgeMavenPassword')) - } - } - else - { - repository(url: 'file://localhost/' + project.file('repo').getAbsolutePath()) - } - - pom { - groupId = project.group - version = project.version - artifactId = project.archivesBaseName - project { - name project.archivesBaseName - packaging 'jar' - description 'Minecraft Forge API' - 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 'Forge Public License' - url 'https://raw.github.com/MinecraftForge/MinecraftForge/master/MinecraftForge-License.txt' - distribution 'repo' - } - } - - developers { - developer { - id 'cpw' - name 'cpw' - roles { role 'developer' } - } - developer { - id 'LexManos' - name 'Lex Manos' - roles { role 'developer' } - } - developer { - id 'AbrarSyed' - name 'Abrar Syed' - roles { role 'contributor' } - } - } - } - } - } +//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 } -// HELPER METHODS - -String getServerClasspath(File file) -{ - def node = new JsonSlurper().parse(file); - def out = new StringBuilder() - node.versionInfo.libraries.each { lib -> - if (lib.serverreq) - { - // group : artifact : version - def split = lib.name.split(':') - def group = split[0].replace('.', '/') - def artifact = split[1] - def version = split[2] - out += "libraries/$group/$artifact/$version/$artifact-${version}.jar " - } - } - out += "minecraft_server.${minecraft.version}.jar" - - return out.toString(); -} - -String getVersionFromJava(File file) -{ - String major = "0"; - String minor = "0"; - String revision = "0"; - String build = "0"; - - String prefix = "public static final int"; - file.eachLine{ String s -> - s = s.trim(); - if (s.startsWith(prefix)) - { - s = s.substring(prefix.length(), s.length() - 1); - s = s.replace('=', ' ').replace("Version", "").replaceAll(" +", " ").trim(); - String[] pts = s.split(" "); - - if (pts[0].equals("major")) major = pts[pts.length - 1]; - else if (pts[0] == "minor") minor = pts[pts.length - 1]; - else if (pts[0] == "revision") revision = pts[pts.length - 1]; - } - } - - build = BUILD_NUMBER - - String branch = null; - if (!System.getenv().containsKey("GIT_BRANCH")) - { - // TODO: use grgit - Tried to switch 07/07/16 - jgit broken on windows? - branch = "git rev-parse --abbrev-ref HEAD".execute().text.trim() - } - else - { - branch = System.getenv("GIT_BRANCH"); - branch = branch.substring(branch.lastIndexOf('/') + 1); - } - - def out = "${minecraft.version.replace('-', '_')}-$major.$minor.$revision.$build" - - if (branch && branch != 'master' && branch != 'HEAD' && branch != minecraft.version && branch != minecraft.version + '.0') - { - if (!(branch.endsWith('.x') && minecraft.version.startsWith(branch.substring(0, branch.length() -2)))) - out += "-$branch" - } - - return out; -} - -reobfuscate { - extraSrg = [ - 'MD: net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry/getKeys ()Ljava/util/Set; net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry/getKeys ()Ljava/util/Set;' - ] -} - -task resetBuildNumber << { - project.ext.properties.buildNumber = 0; - ciWriteBuildNumber.execute() -} -// re-add old tasks for jenkins compat -// should be removed, and the jenkins fixed when no longer building with FG 1.2 -task setupForge { dependsOn 'setup', 'ciWriteBuildNumber' } -task buildPackages { dependsOn 'build' } - -//Temporary hack to fix compile errors caused by mappings shading in Bootstrap -/* -task fixParams << { - logger.lifecycle('Fixing param names!') - def params = new File(extractMcpMappings.destinationDir, 'params.csv') - def text = params.text - text = text.replaceAll('p_180276_1_,biome,', 'p_180276_1_,biomeIn,') - params.write(text) -} -fixParams.dependsOn('extractMcpMappings') -extractMcpMappings.finalizedBy('fixParams') -*/ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 30d399d8d2bf522ff5de94bf434a7cc43a9a74b5..7a3265ee94c0ab25cf079ac8ccdf87f41d455d42 100644 GIT binary patch delta 29215 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e18cba72f4..949819d28a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Mon Sep 14 12:28:28 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip diff --git a/gradlew b/gradlew index 91a7e269e1..cccdd3d517 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,47 +6,6 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; -esac - -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" @@ -61,9 +20,49 @@ while [ -h "$PRG" ] ; do fi done SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- +cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" -cd "$SAVED" >&- +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282aa6..f9553162f1 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/mdk/README.txt b/mdk/README.txt index 82be8dcd24..6904b37735 100644 --- a/mdk/README.txt +++ b/mdk/README.txt @@ -19,35 +19,26 @@ http://mcforge.readthedocs.io/en/latest/gettingstarted/ Step 1: Open your command-line and browse to the folder where you extracted the zip file. -Step 2: Once you have a command window up in the folder that the downloaded material was placed, type: +Step 2: You're left with a choice. +If you prefer to use Eclipse: +1. Run the following command: "gradlew genEclipseRuns" (./gradlew genEclipseRuns if you are on Mac/Linux) +2. Open Eclipse, Import > Existing Gradle Project > Select Folder + or run "gradlew eclipse" to generate the project. +(Current Issue) +4. Open Project > Run/Debug Settings > Edit runClient and runServer > Environment +5. Edit MOD_CLASSES to show [modid]%%[Path]; 2 times rather then the generated 4. -Windows: "gradlew setupDecompWorkspace" -Linux/Mac OS: "./gradlew setupDecompWorkspace" - -Step 3: After all that finished, you're left with a choice. -For eclipse, run "gradlew eclipse" (./gradlew eclipse if you are on Mac/Linux) - -If you prefer to use IntelliJ, steps are a little different. +If you prefer to use IntelliJ: 1. Open IDEA, and import project. 2. Select your build.gradle file and have it import. -3. Once it's finished you must close IntelliJ and run the following command: - -"gradlew genIntellijRuns" (./gradlew genIntellijRuns if you are on Mac/Linux) - -Step 4: The final step is to open Eclipse and switch your workspace to /eclipse/ (if you use IDEA, it should automatically start on your project) +3. Run the following command: "gradlew genIntellijRuns" (./gradlew genIntellijRuns if you are on Mac/Linux) +4. Refresh the Gradle Project in IDEA if required. If at any point you are missing libraries in your IDE, or you've run into problems you can run "gradlew --refresh-dependencies" to refresh the local cache. "gradlew clean" to reset everything {this does not affect your code} and then start the processs again. Should it still not work, Refer to #ForgeGradle on EsperNet for more information about the gradle environment. - -Tip: -If you do not care about seeing Minecraft's source code you can replace "setupDecompWorkspace" with one of the following: -"setupDevWorkspace": Will patch, deobfuscate, and gather required assets to run minecraft, but will not generate human readable source code. -"setupCIWorkspace": Same as Dev but will not download any assets. This is useful in build servers as it is the fastest because it does the least work. - -Tip: -When using Decomp workspace, the Minecraft source code is NOT added to your workspace in a editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes and usually can be accessed under the 'referenced libraries' section of your IDE. +or the Forge Project Discord discord.gg/UvedJ9m Forge source installation ========================= diff --git a/mdk/build.gradle b/mdk/build.gradle index 6f2e0a9097..f41cdad391 100644 --- a/mdk/build.gradle +++ b/mdk/build.gradle @@ -1,77 +1,118 @@ buildscript { repositories { + maven { url = 'https://files.minecraftforge.net/maven' } jcenter() - maven { url = "https://files.minecraftforge.net/maven" } + mavenCentral() } dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.+' } } -apply plugin: 'net.minecraftforge.gradle.forge' -//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. + +apply plugin: 'net.minecraftforge.gradle' +// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. +apply plugin: 'eclipse' +apply plugin: 'maven-publish' +version = '1.0' +group = 'com.yourname.modid' // http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = 'modid' -version = "1.0" -group = "com.yourname.modid" // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = "modid" - -sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. -compileJava { - sourceCompatibility = targetCompatibility = '1.8' -} +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. minecraft { - version = "@VERSION@" - runDir = "run" - - // the mappings can be changed at any time, and must be in the following format. - // snapshot_YYYYMMDD snapshot are built nightly. - // stable_# stables are built at the discretion of the MCP team. + // The mappings can be changed at any time, and must be in the following format. + // snapshot_YYYYMMDD Snapshot are built nightly. + // stable_# Stables are built at the discretion of the MCP team. // Use non-default mappings at your own risk. they may not always work. - // simply re-run your setup task after changing the mappings to update your workspace. - mappings = "@MAPPINGS@" + // Simply re-run your setup task after changing the mappings to update your workspace. + //mappings channel: '@MAPPING_CHANNEL@', version: '@MAPPING_VERSION@' + mappings channel: 'snapshot', version: '20171003-1.12' // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. + + // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + client { + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + + // Recommended logging level for the console + property 'forge.logging.console.level', 'debug' + } + + server { + + // Recommended logging data for a userdev environment + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + + // Recommended logging level for the console + property 'forge.logging.console.level', 'debug' + } + } } dependencies { - // you may put jars on which you depend on in ./libs - // or you may define them like so.. - //compile "some.group:artifact:version:classifier" - //compile "some.group:artifact:version" - - // real examples - //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env - //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env + // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed + // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. + // The userdev artifact is a special name and will get all sorts of transformations applied to it. + //minecraft '@FORGE_GROUP@:@FORGE_NAME@:@FORGE_VERSION@' + minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2849' - // the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. - //provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' + // You may put jars on which you depend on in ./libs or you may define them like so.. + // compile "some.group:artifact:version:classifier" + // compile "some.group:artifact:version" - // the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided, - // except that these dependencies get remapped to your current MCP mappings - //deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev' - //deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev' + // Real examples + // compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env + // compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env - // for more info... + // The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. + // provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' + + // These dependencies get remapped to your current MCP mappings + // deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev' + + // For more info... // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/dependency_management.html } -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 except the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' +// Example for how to get properties into the manifest for reading by the runtime.. +jar { + manifest { + attributes([ + "Specification-Title": "examplemod", + "Specification-Vendor": "examplemodsareus", + "Specification-Version": "1", // We are version 1 of ourselves + "Implementation-Title": project.name, + "Implementation-Version": "${version}", + "Implementation-Vendor" :"examplemodsareus", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") + ]) } } + +// Example configuration to allow publishing using the maven-publish task +// This is the preferred method to reobfuscate your jar file +jar.finalizedBy('reobfJar') +// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing +//publish.dependsOn('reobfJar') + +publishing { + publications { + mavenJava(MavenPublication) { + artifact jar + } + } + repositories { + maven { + url "file:///${project.projectDir}/mcmodsrepo" + } + } +} \ No newline at end of file diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.resources/.projects/MDKExample/.location b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.resources/.projects/MDKExample/.location deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.resources/.root/0.tree b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.resources/.root/0.tree deleted file mode 100644 index c64a62aa3537107ea026c463518787dbbe4a2b58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 468 zcmZvYK@x&63`J8a3T$=diWBq@j;uVDvuj!B+R{A617I{6 zk6|-DE#~;TKRuo)ff!`0GZ%!A2vtkxjPyrT28N|CJVLzloB%|^*rw9TkHUN~dkPQ> zr@b#Pg(I3)@--TXK4uJ-qdzrPAKLamXS0DAI^$V+A(_>$OxTM6pd@!zjoO(ExR3}= JN4r+4yZ}thLN)*Z diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 466d7f93a1..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,4 +0,0 @@ -#Sun Jun 05 18:58:07 CEST 2011 -version=1 -eclipse.preferences.version=1 -refresh.enabled=true diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs deleted file mode 100644 index 94c56761d3..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.debug.ui.prefs +++ /dev/null @@ -1,7 +0,0 @@ -#Sun Jun 05 19:03:53 CEST 2011 -eclipse.preferences.version=1 -org.eclipse.debug.ui.UseContextualLaunch=false -Console.highWaterMark=88000 -org.eclipse.debug.ui.PREF_LAUNCH_PERSPECTIVES=\r\n\r\n -org.eclipse.debug.ui.user_view_bindings=\r\n\r\n\r\n\r\n\r\n\r\n -StringVariablePreferencePage=130,107,107,86, diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.epp.usagedata.gathering.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.epp.usagedata.gathering.prefs deleted file mode 100644 index 333b991531..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.epp.usagedata.gathering.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Sun Jun 05 18:58:07 CEST 2011 -eclipse.preferences.version=1 -org.eclipse.epp.usagedata.gathering.enabled=false diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 12ec368903..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,14 +0,0 @@ -#Sun Sep 18 16:44:39 NZST 2011 -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=ignore -org.eclipse.jdt.core.compiler.problem.deprecation=ignore -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore -org.eclipse.jdt.core.compiler.problem.unusedImport=ignore -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore -org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore -org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore -org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.editors.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.editors.prefs deleted file mode 100644 index 316ef6f309..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.editors.prefs +++ /dev/null @@ -1,4 +0,0 @@ -#Sun Jun 05 18:58:05 CEST 2011 -spacesForTabs=true -eclipse.preferences.version=1 -overviewRuler_migration=migrated_3.1 diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs deleted file mode 100644 index ae368abb9e..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Sun Jun 05 18:58:07 CEST 2011 -IMPORT_FILES_AND_FOLDERS_MODE=prompt -IMPORT_FILES_AND_FOLDERS_VIRTUAL_FOLDER_MODE=prompt -SAVE_ALL_BEFORE_BUILD=true -eclipse.preferences.version=1 -tipsAndTricks=true -platformState=1287081747687 -quickStart=false -PROBLEMS_FILTERS_MIGRATE=true diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs b/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs deleted file mode 100644 index cbc59537b0..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Sun Jun 05 18:50:08 CEST 2011 -eclipse.preferences.version=1 -showIntro=false diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Client.launch b/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Client.launch deleted file mode 100644 index 61b8b47f37..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Client.launch +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Server.launch b/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Server.launch deleted file mode 100644 index c34d27ae57..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.core/.launches/Server.launch +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.ui/launchConfigurationHistory.xml b/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.ui/launchConfigurationHistory.xml deleted file mode 100644 index 1208f602e5..0000000000 --- a/mdk/eclipse/.metadata/.plugins/org.eclipse.debug.ui/launchConfigurationHistory.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mdk/gitignore.txt b/mdk/gitignore.txt index 2c770e09fe..12f864471f 100644 --- a/mdk/gitignore.txt +++ b/mdk/gitignore.txt @@ -20,3 +20,6 @@ build # other eclipse run + +# Files from Forge MDK +forge*changelog.txt diff --git a/mdk/gradle.properties b/mdk/gradle.properties index e9b9fd5ac1..878bf1f7ec 100644 --- a/mdk/gradle.properties +++ b/mdk/gradle.properties @@ -1,3 +1,4 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false \ No newline at end of file diff --git a/patches/minecraft/net/minecraft/entity/monster/EntityEvoker.java.patch b/patches/minecraft/net/minecraft/entity/monster/EntityEvoker.java.patch index f30aa06996..b3a8372cbf 100644 --- a/patches/minecraft/net/minecraft/entity/monster/EntityEvoker.java.patch +++ b/patches/minecraft/net/minecraft/entity/monster/EntityEvoker.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft/net/minecraft/entity/monster/EntityEvoker.java +++ ../src-work/minecraft/net/minecraft/entity/monster/EntityEvoker.java -@@ -369,7 +369,7 @@ +@@ -365,7 +365,7 @@ { return false; } diff --git a/settings.gradle b/settings.gradle index 74046b5b85..2acad82fc7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,9 @@ -rootProject.name = 'forge' \ No newline at end of file +rootProject.name = 'forge' + +include ':mcp' +include ':clean' +include ':forge' + +project(":mcp").projectDir = file("projects/mcp") +project(":clean").projectDir = file("projects/clean") +project(":forge").projectDir = file("projects/forge") \ No newline at end of file