Skip to content

Commit

Permalink
0.2.3
Browse files Browse the repository at this point in the history
  • Loading branch information
Juuxel committed Sep 6, 2020
1 parent 69ad8a3 commit f68217d
Show file tree
Hide file tree
Showing 40 changed files with 3,923 additions and 277 deletions.
21 changes: 20 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ buildscript {
import juuxel.fc0.tools.bytecodetweaker.BytecodeTweaker
import net.fabricmc.stitch.commands.CommandFixNesting

import java.nio.file.Files

plugins {
id 'java'
id 'application'
Expand All @@ -29,7 +31,7 @@ mainClassName = 'tk.valoeghese.fc0.client.Main'
sourceCompatibility = JavaVersion.VERSION_1_8

group 'tk.valoeghese'
version '0.2.2'
version '0.2.3'

repositories {
mavenCentral()
Expand All @@ -55,6 +57,23 @@ def mappingsDir = project.file('mappings')
def intermediaryJar = project.file("build/intermediary-${gameJar.name}")
def runDirectory = project.file('run')

if (!gameJar.exists()) {
def url = new URL("https://github.com/valoeghese/2fc-early-releases/raw/master/2fc0f18-${version}.jar")
try {
println "Downloading 2fc0f18 v$version"

def stream = url.openStream()
try {
Files.copy(stream, gameJar.toPath())
} finally {
stream.close()
}
} catch (IOException e) {
System.err.println "Could not download 2fc0f18 v$version"
e.printStackTrace()
}
}

if (!runDirectory.exists()) {
runDirectory.mkdir()
}
Expand Down
1 change: 1 addition & 0 deletions buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ dependencies {
implementation "com.google.guava:guava:$guava" // for t-m-p
implementation "commons-io:commons-io:$commons_io" // for CommandFixNesting
implementation "com.github.Juuxel:fc0-tools:$fc0_tools"
implementation "net.fabricmc:procyon-fabric-compilertools:$procyon"
}
1 change: 1 addition & 0 deletions buildSrc/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ tiny_mappings_parser = 0.2.1.13
guava = 28.2-jre
commons_io = 2.7
fc0_tools = 1.1.4
procyon = +
69 changes: 69 additions & 0 deletions buildSrc/src/main/groovy/CfrDecompiler.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import juuxel.fc0.tools.source.EnumFixer
import org.benf.cfr.reader.api.CfrDriver
import org.benf.cfr.reader.api.OutputSinkFactory
import org.benf.cfr.reader.api.SinkReturns
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Input

import java.nio.charset.StandardCharsets
import java.nio.file.Files

class CfrDecompiler implements Decompiler {
@Input
@Override
String getName() {
return "CFR"
}

@Override
void decompile(File input, FileCollection libraries, File output) {
def driver = new CfrDriver.Builder()
.withOptions(
usenametable: 'false',
sugarenums: 'true',
extraclasspath: libraries.collect { it.absolutePath }.join(File.pathSeparator)
)
.withOutputSink(new SinkFactory(output))
.build()
driver.analyse([input.getAbsolutePath()])

Files.walk(output.toPath())
.filter { Files.isRegularFile(it) && it.toString().endsWith(".java") }
.forEach {
def lines = Files.readAllLines(it)
def newLines = EnumFixer.fixEnums(lines)

if (newLines != null) {
Files.write(it, newLines, StandardCharsets.UTF_8)
}
}
}

private static void accept(File output, SinkReturns.Decompiled decompiled) {
def dir = output.toPath().resolve(decompiled.packageName.replace('.', '/'))
Files.createDirectories(dir)
def sourceFile = dir.resolve(decompiled.className + ".java")

Files.write(sourceFile, decompiled.java.getBytes(StandardCharsets.UTF_8))
}

private class SinkFactory implements OutputSinkFactory {
private File output

SinkFactory(File output) {
this.output = output
}

@Override
List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> available) {
return [SinkClass.DECOMPILED]
}

@Override
<T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
return (sinkClass == SinkClass.DECOMPILED && sinkType == SinkType.JAVA)
? { data -> accept(output, data as SinkReturns.Decompiled) }
: null
}
}
}
54 changes: 5 additions & 49 deletions buildSrc/src/main/groovy/DecompileTask.groovy
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import juuxel.fc0.tools.source.EnumFixer
import org.benf.cfr.reader.api.CfrDriver
import org.benf.cfr.reader.api.OutputSinkFactory
import org.benf.cfr.reader.api.SinkReturns
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction

import java.nio.charset.StandardCharsets
import java.nio.file.Files

class DecompileTask extends DefaultTask {
@Nested
Decompiler decompiler = new CfrDecompiler()

@InputFile
File input

Expand All @@ -32,52 +29,11 @@ class DecompileTask extends DefaultTask {
cleanOutput.deleteDir()
cleanOutput.mkdirs()

def driver = new CfrDriver.Builder()
.withOptions(
usenametable: 'false',
sugarenums: 'true',
extraclasspath: libraries.collect { it.absolutePath }.join(File.pathSeparator)
)
.withOutputSink(new SinkFactory())
.build()
driver.analyse([input.getAbsolutePath()])

Files.walk(output.toPath())
.filter { Files.isRegularFile(it) && it.toString().endsWith(".java") }
.forEach {
def lines = Files.readAllLines(it)
def newLines = EnumFixer.fixEnums(lines)

if (newLines != null) {
Files.write(it, newLines, StandardCharsets.UTF_8)
}
}
decompiler.decompile(input, libraries, output)

// https://stackoverflow.com/a/6214823
new AntBuilder().copy(toDir: cleanOutput.absolutePath) {
fileset(dir: output.absolutePath)
}
}

private def accept(SinkReturns.Decompiled decompiled) {
def dir = output.toPath().resolve(decompiled.packageName.replace('.', '/'))
Files.createDirectories(dir)
def sourceFile = dir.resolve(decompiled.className + ".java")

Files.write(sourceFile, decompiled.java.getBytes(StandardCharsets.UTF_8))
}

private class SinkFactory implements OutputSinkFactory {
@Override
List<SinkClass> getSupportedSinks(SinkType sinkType, Collection<SinkClass> available) {
return [SinkClass.DECOMPILED]
}

@Override
<T> Sink<T> getSink(SinkType sinkType, SinkClass sinkClass) {
return (sinkClass == SinkClass.DECOMPILED && sinkType == SinkType.JAVA)
? { data -> accept(data as SinkReturns.Decompiled) }
: null
}
}
}
10 changes: 10 additions & 0 deletions buildSrc/src/main/groovy/Decompiler.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Input

@FunctionalInterface
interface Decompiler {
@Input
String getName()

void decompile(File input, FileCollection libraries, File output)
}
141 changes: 141 additions & 0 deletions buildSrc/src/main/groovy/ProcyonDecompiler.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import com.strobel.assembler.metadata.CompositeTypeLoader
import com.strobel.assembler.metadata.ITypeLoader
import com.strobel.assembler.metadata.JarTypeLoader
import com.strobel.assembler.metadata.MetadataSystem
import com.strobel.assembler.metadata.TypeDefinition
import com.strobel.assembler.metadata.TypeReference
import com.strobel.decompiler.DecompilationOptions
import com.strobel.decompiler.DecompilerSettings
import com.strobel.decompiler.PlainTextOutput
import com.strobel.decompiler.languages.java.BraceStyle
import com.strobel.decompiler.languages.java.JavaFormattingOptions
import cuchaz.enigma.source.procyon.typeloader.NoRetryMetadataSystem
import org.gradle.api.file.FileCollection

import java.nio.charset.StandardCharsets
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.util.jar.JarFile

class ProcyonDecompiler implements Decompiler {
@Override
String getName() {
return "Procyon"
}

@Override
void decompile(File input, FileCollection libraries, File output) {
JarFile inputJar = new JarFile(input)
List<ITypeLoader> typeLoaders = []
typeLoaders.add(new JarTypeLoader(inputJar))

for (File library : libraries) {
typeLoaders.add(new JarTypeLoader(new JarFile(library)))
}

ITypeLoader typeLoader = new CompositeTypeLoader(typeLoaders as ITypeLoader[])

DecompilerSettings settings = DecompilerSettings.javaDefaults()
settings.forceExplicitImports = true
settings.typeLoader = typeLoader

JavaFormattingOptions format = settings.javaFormattingOptions
format.ClassBraceStyle = BraceStyle.EndOfLine
format.InterfaceBraceStyle = BraceStyle.EndOfLine
format.EnumBraceStyle = BraceStyle.EndOfLine

MetadataSystem metadataSystem = new NoRetryMetadataSystem(typeLoader)
DecompilationOptions options = new DecompilationOptions()
options.settings = settings

Path out = output.toPath()
FileSystem inputFs = FileSystems.newFileSystem(URI.create("jar:" + input.toURI()), [create: "false"])
try {
for (Path rootDirectory : inputFs.rootDirectories) {
Files.find(rootDirectory, Integer.MAX_VALUE, { path, attributes -> attributes.isRegularFile() }).forEach {
Path relative = rootDirectory.relativize(it)

if (it.toString().endsWith(".class")) {
String relativePath = relative.toString()
String className = relativePath.substring(0, relativePath.length() - ".class".length())

Path target = out.resolve(className + ".java")
Path parent = target.parent

if (parent != null) {
Files.createDirectories(parent)
}

TypeReference type = metadataSystem.lookupType(className)
TypeDefinition resolvedType = type.resolve()

def stream = new ByteArrayOutputStream()
def writer = new OutputStreamWriter(stream)

try {
PlainTextOutput arrayOutput = new PlainTextOutput(writer)
settings.language.decompileType(resolvedType, arrayOutput, options)

writer.flush()
byte[] bytes = stream.toByteArray()
String code = new String(bytes, StandardCharsets.UTF_8)
String[] lines = code.split("\n")
Files.write(target, sortImports(lines), StandardCharsets.UTF_8)
} finally {
stream.close()
writer.close()
}
}
}
}
} finally {
inputFs.close()
}
}

private static List<String> sortImports(String[] lines) {
boolean foundImports = false
int importStart = -1 // inclusive
int importEnd = -1 // exclusive

for (int i = 0; i < lines.length; i++) {
String line = lines[i]

if (line.startsWith("import ")) {
if (!foundImports) {
foundImports = true
importStart = i
}
} else if (foundImports) {
importEnd = i
break
}
}

if (!foundImports) {
return lines.toList()
}

String[] imports = new String[importEnd - importStart]
System.arraycopy(lines, importStart, imports, 0, imports.length)
Arrays.sort(imports)

List<String> result = new ArrayList<>()

for (int i = 0; i < importStart; i++) {
result.add(lines[i])
}

for (String line : imports) {
result.add(line)
}

for (int i = importEnd; i < lines.length; i++) {
result.add(lines[i])
}

return result
}
}
10 changes: 10 additions & 0 deletions bytecode_tweaks/0.2.3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"bridges": {
"tk/valoeghese/fc0/class_34": [
"apply(Ljava/lang/Object;)Ljava/lang/Object;"
],
"tk/valoeghese/fc0/class_91": [
"next()Ljava/lang/Object;"
]
}
}
Loading

0 comments on commit f68217d

Please sign in to comment.