@@ -7,6 +7,8 @@ buildscript {
77 dependencies {
88 classpath " com.gradle.publish:plugin-publish-plugin:0.9.1"
99 classpath ' nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0'
10+ classpath ' org.ow2.asm:asm:6.2.1'
11+ classpath ' org.ow2.asm:asm-tree:6.2.1'
1012 }
1113}
1214
@@ -87,9 +89,10 @@ dependencies {
8789 shade(' de.oceanlabs.mcp:mcinjector:3.4-SNAPSHOT' ){
8890 exclude group : ' org.ow2.asm' , module : ' asm-debug-all'
8991 }
90- shade(' net.minecraftforge.srg2source :Srg2Source:4.0-SNAPSHOT ' ){
92+ shade(' net.minecraftforge:Srg2Source:5.0.+ ' ){
9193 exclude group : ' org.ow2.asm' , module : ' asm-debug-all'
9294 exclude group : ' org.eclipse.equinox' , module : ' org.eclipse.equinox.common'
95+ exclude group : ' cpw.mods' , module : ' modlauncher'
9396 }
9497
9598 // Stuff used in the GradleStart classes
@@ -129,7 +132,118 @@ processResources {
129132 }
130133}
131134
135+ import java.util.zip.*
136+ import org.objectweb.asm.*
137+ import org.objectweb.asm.tree.*
138+
139+ // TODO: Eclipse complains about unused messages. Find a way to make it shut up.
140+ class PatchJDTClasses extends DefaultTask {
141+ static def COMPILATION_UNIT_RESOLVER = ' org/eclipse/jdt/core/dom/CompilationUnitResolver'
142+ static def RANGE_EXTRACTOR = ' net/minecraftforge/srg2source/ast/RangeExtractor'
143+ def RESOLVE_METHOD = ' resolve([Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Lorg/eclipse/jdt/core/dom/FileASTRequestor;ILjava/util/Map;I)V'
144+ def GET_CONTENTS = ' org/eclipse/jdt/internal/compiler/util/Util.getFileCharContent(Ljava/io/File;Ljava/lang/String;)[C'
145+ def HOOK_DESC_RESOLVE = ' (Ljava/lang/String;Ljava/lang/String;)[C'
146+
147+ @Input def targets = [] as Set
148+ @Input def libraries = [] as Set
149+ @OutputFile File output
150+
151+ void target (String value ) {
152+ targets. add(value)
153+ }
154+
155+ void library (File value ) {
156+ libraries. add(value)
157+ }
158+
159+ @TaskAction
160+ void patchClass () {
161+ def toProcess = targets. collect()
162+ new ZipOutputStream (new FileOutputStream (output)). withCloseable{ zout ->
163+ libraries. stream(). filter{ ! it. isDirectory() }. each { lib ->
164+ new ZipFile (lib). withCloseable { zin ->
165+ def remove = []
166+ toProcess. each{ target ->
167+ def entry = zin. getEntry(target+ ' .class' )
168+ if (entry == null )
169+ return
170+
171+ def node = new ClassNode ()
172+ def reader = new ClassReader (zin. getInputStream(entry))
173+ reader. accept(node, 0 )
174+
175+ // CompilationUnitResolver allows batch compiling, the problem is it is hardcoded to read the contents from a File.
176+ // So we patch this call to redirect to us, so we can get the contents from our InputSupplier
177+ if (COMPILATION_UNIT_RESOLVER . equals(target)) {
178+ logger. lifecycle(' Transforming: ' + target + ' From: ' + lib)
179+ def resolve = node. methods. find{ RESOLVE_METHOD . equals(it. name + it. desc) }
180+ if (resolve == null )
181+ throw new RuntimeException (' Failed to patch ' + target + ' : Could not find method ' + RESOLVE_METHOD )
182+ for (int x = 0 ; x < resolve. instructions. size(); x++ ) {
183+ def insn = resolve. instructions. get(x)
184+ if (insn. type == AbstractInsnNode . METHOD_INSN ) {
185+ if (GET_CONTENTS . equals(insn. owner + ' .' + insn. name + insn. desc)) {
186+ if (
187+ resolve. instructions. get(x - 5 ). opcode == Opcodes . NEW &&
188+ resolve. instructions. get(x - 4 ). opcode == Opcodes . DUP &&
189+ resolve. instructions. get(x - 3 ). opcode == Opcodes . ALOAD &&
190+ resolve. instructions. get(x - 2 ). opcode == Opcodes . INVOKESPECIAL &&
191+ resolve. instructions. get(x - 1 ). opcode == Opcodes . ALOAD
192+ ) {
193+ resolve. instructions. set(resolve. instructions. get(x - 5 ), new InsnNode (Opcodes . NOP )); // NEW File
194+ resolve. instructions. set(resolve. instructions. get(x - 4 ), new InsnNode (Opcodes . NOP )); // DUP
195+ resolve. instructions. set(resolve. instructions. get(x - 2 ), new InsnNode (Opcodes . NOP )); // INVOKESTATIC <init>
196+ insn. owner = RANGE_EXTRACTOR
197+ insn. desc = HOOK_DESC_RESOLVE
198+ logger. lifecycle(' Patched ' + node. name)
199+ } else {
200+ throw new IllegalStateException (' Found Util.getFileCharContents call, with unexpected context' )
201+ }
202+ }
203+ }
204+ }
205+ } else if (RANGE_EXTRACTOR . equals(target)) {
206+ logger. lifecycle(' Tansforming: ' + target + ' From: ' + lib)
207+ def marker = node. methods. find{ ' hasBeenASMPatched()Z' . equals(it. name + it. desc) }
208+ if (marker == null )
209+ throw new RuntimeException (' Failed to patch ' + target + ' : Could not find method hasBeenASMPatched()Z' )
210+ marker. instructions. clear()
211+ marker. instructions. add(new InsnNode (Opcodes . ICONST_1 ))
212+ marker. instructions. add(new InsnNode (Opcodes . IRETURN ))
213+ logger. lifecycle(' Patched: ' + node. name)
214+ }
215+
216+ def writer = new ClassWriter (0 )
217+ node. accept(writer)
218+
219+ remove. add(target)
220+ def nentry = new ZipEntry (entry. name)
221+ nentry. time = 0
222+ zout. putNextEntry(nentry)
223+ zout. write(writer. toByteArray())
224+ zout. closeEntry()
225+ }
226+ toProcess. removeAll(remove)
227+ }
228+ }
229+ if (! toProcess. isEmpty())
230+ throw new IllegalStateException (' Patching class failed: ' + toProcess)
231+ }
232+ }
233+ }
234+
235+ task patchJDT (type : PatchJDTClasses ) {
236+ target PatchJDTClasses . COMPILATION_UNIT_RESOLVER
237+ target PatchJDTClasses . RANGE_EXTRACTOR
238+ configurations. shade. resolvedConfiguration. resolvedArtifacts. stream(). filter { dep ->
239+ dep. name. equals(' org.eclipse.jdt.core' ) || dep. name. equals(' Srg2Source' )
240+ }
241+ .forEach { dep -> library dep. file }
242+ output file(' build/patchJDT/patch_jdt.jar' )
243+ }
244+
132245jar {
246+ dependsOn(' patchJDT' )
133247
134248 configurations. shade. each { dep ->
135249 /* I can use this again to find where dupes come from, so.. gunna just keep it here.
@@ -148,6 +262,10 @@ jar {
148262 }
149263 }
150264
265+ from(zipTree(patchJDT. output)){
266+ duplicatesStrategy ' include'
267+ }
268+
151269 manifest {
152270 attributes ' version' :project. version
153271 attributes ' javaCompliance' : project. targetCompatibility
0 commit comments