Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 133 additions & 29 deletions src/main/java/com/shanebeestudios/mcdeob/Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.FileOutputStream;
import javax.swing.SwingUtilities;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

Expand Down Expand Up @@ -114,40 +116,95 @@ public void init() {
public void downloadJar() throws IOException {
long start = System.currentTimeMillis();
Logger.info("Downloading JAR file from Mojang.");

this.jarPath = this.dataFolderPath.resolve(this.minecraftJarName);
final URL jarURL = new URL(this.version.getJarURL());
final HttpURLConnection connection = (HttpURLConnection) jarURL.openConnection();
final long contentLength = connection.getContentLengthLong();

if (this.app != null) {
this.app.updateStatusBox("Downloading JAR...");
this.app.updateButton("Downloading JAR...", Color.BLUE);
}

this.jarPath = this.dataFolderPath.resolve(this.minecraftJarName);
final URL jarURL = new URL(this.version.getJarURL());
final HttpURLConnection connection = (HttpURLConnection) jarURL.openConnection();
final long length = connection.getContentLengthLong();
if (Files.exists(jarPath) && Files.size(jarPath) == length) {
if (Files.exists(jarPath) && Files.size(jarPath) == contentLength) {
Logger.info("Already have JAR, skipping download.");
} else try (final InputStream inputStream = connection.getInputStream()) {
Files.copy(inputStream, jarPath, REPLACE_EXISTING);
if (this.app != null) {
this.app.resetProgressBar();
}
return;
}

try (final InputStream inputStream = connection.getInputStream()) {
// Create a buffered output stream
try (FileOutputStream outputStream = new FileOutputStream(this.jarPath.toFile())) {
byte[] buffer = new byte[4096];
long downloadedBytes = 0;
int bytesRead;

while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
downloadedBytes += bytesRead;

// Update progress
if (this.app != null) {
int progress = (int) ((downloadedBytes * 100) / contentLength);
this.app.updateProgressBar(progress, 100, "Downloading JAR...");
}
}
}
}

if (this.app != null) {
this.app.resetProgressBar();
}


TimeStamp timeStamp = TimeStamp.fromNow(start);
Logger.info("Successfully downloaded JAR file in %s!", timeStamp);
}

public void downloadMappings() throws IOException {
long start = System.currentTimeMillis();
Logger.info("Downloading mappings file from Mojang...");
if (this.app != null) {
this.app.updateStatusBox("Downloading mappings...");
this.app.updateButton("Downloading mappings...", Color.BLUE);
}

final URL mappingURL = new URL(this.version.getMapURL());
final HttpURLConnection connection = (HttpURLConnection) mappingURL.openConnection();
final long length = connection.getContentLengthLong();
final long contentLength = connection.getContentLengthLong();
this.mappingsPath = this.dataFolderPath.resolve(this.mappingsName);
if (Files.exists(this.mappingsPath) && Files.size(this.mappingsPath) == length) {

if (this.app != null) {
this.app.updateButton("Downloading mappings...", Color.BLUE);
}

if (Files.exists(this.mappingsPath) && Files.size(this.mappingsPath) == contentLength) {
Logger.info("Already have mappings, skipping download.");
} else try (final InputStream inputStream = connection.getInputStream()) {
Files.copy(inputStream, this.mappingsPath, REPLACE_EXISTING);
if (this.app != null) {
this.app.resetProgressBar();
}
return;
}

try (final InputStream inputStream = connection.getInputStream()) {
// Create a buffered output stream
try (FileOutputStream outputStream = new FileOutputStream(this.mappingsPath.toFile())) {
byte[] buffer = new byte[4096];
long downloadedBytes = 0;
int bytesRead;

while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
downloadedBytes += bytesRead;

if (this.app != null) {
int progress = (int) ((downloadedBytes * 100) / contentLength);
this.app.updateProgressBar(progress, 100, "Downloading mappings...");
}
}
}
}

if (this.app != null) {
this.app.resetProgressBar();
}

TimeStamp timeStamp = TimeStamp.fromNow(start);
Expand All @@ -157,7 +214,6 @@ public void downloadMappings() throws IOException {
public void remapJar() {
long start = System.currentTimeMillis();
if (this.app != null) {
this.app.updateStatusBox("Remapping...");
this.app.updateButton("Remapping...", Color.BLUE);
}
this.remappedJar = this.dataFolderPath.resolve(this.mappedJarName);
Expand All @@ -166,34 +222,69 @@ public void remapJar() {
Logger.info("Remapping %s file...", this.minecraftJarName);

try {
// SpecialSource remapping
if (this.app != null) {
this.app.updateStatusBox("Moving to Remapping");
}

JarMapping jarMapping = new JarMapping();

if (this.app != null) {
this.app.updateProgressBar(10, 100, "Preparing mappings...");
}
jarMapping.loadMappings(new File(this.mappingsPath.toUri()));

if (this.app != null) {
this.app.updateProgressBar(30, 100, "Setting up inheritance...");
}
JointProvider inheritanceProvider = new JointProvider();
jarMapping.setFallbackInheritanceProvider(inheritanceProvider);

SpecialSource.kill_lvt = true;
JarRemapper jarRemapper = new JarRemapper(jarMapping);

if (this.app != null) {
this.app.updateProgressBar(50, 100, "Loading internal jars...");
}
Jar internalJars = Util.getInternalJars(this);

inheritanceProvider.add(new JarProvider(internalJars));

if (this.app != null) {
this.app.updateProgressBar(70, 100, "Remapping JAR...");
}
jarRemapper.remapJar(internalJars, new File(this.remappedJar.toUri()));

if (this.app != null) {
this.app.updateProgressBar(90, 100, "Finalizing...");

SwingUtilities.invokeLater(() -> {
this.app.resetProgressBar();
this.app.updateStatusBox("Remapping Complete");
});
}
internalJars.close();

if (this.version.getMappingType() == Version.MappingType.SEARGE) {
// Some versions like 1.12.2 include this nasty giant package
Util.stripFileFromJar(this.remappedJar, "it/*");
}

if (this.app != null) {
this.app.updateStatusBox("Remapping Complete");
}
} catch (IOException e) {
if (this.app != null) {
this.app.updateStatusBox("Remapping Failed");
}
throw new RuntimeException(e);
}

TimeStamp timeStamp = TimeStamp.fromNow(start);
Logger.info("Remapping completed in %s!", timeStamp);
} else {
Logger.info("%s already remapped... skipping mapping.", this.mappedJarName);
if (this.app != null) {
this.app.resetProgressBar();
}
}
}

Expand All @@ -207,18 +298,31 @@ public void decompileJar() throws IOException {
}
final Path decompileDir = Files.createDirectories(this.dataFolderPath.resolve("final-decompile"));

// Setup and run FernFlower
AppLogger appLogger = new AppLogger(this.app);
ConsoleDecompiler decompiler = new ConsoleDecompiler(new File(decompileDir.toUri()), Util.getDecompilerParams(), appLogger);
decompiler.addSource(new File(this.remappedJar.toUri()));
decompiler.decompileContext();
appLogger.stopLogging();
try {
if (this.app != null) {
this.app.updateStatusBox("Starting Decompilation");
}
// Setup and run FernFlower
AppLogger appLogger = new AppLogger(this.app);
ConsoleDecompiler decompiler = new ConsoleDecompiler(new File(decompileDir.toUri()), Util.getDecompilerParams(), appLogger);
decompiler.addSource(new File(this.remappedJar.toUri()));
decompiler.decompileContext();
appLogger.stopLogging();

// Rename jar file to zip
Util.renameJarsToZips(decompileDir);
// Rename jar file to zip
Util.renameJarsToZips(decompileDir);

TimeStamp timeStamp = TimeStamp.fromNow(start);
Logger.info("Decompiling completed in %s!", timeStamp);
TimeStamp timeStamp = TimeStamp.fromNow(start);
Logger.info("Decompiling completed in %s!", timeStamp);
if (this.app != null) {
this.app.updateStatusBox("Decompilation Complete");
}
} catch (Exception e) {
if (this.app != null) {
this.app.updateStatusBox("Decompilation Failed");
}
throw e;
}
}

private void cleanup() {
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/com/shanebeestudios/mcdeob/app/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

public class App extends JFrame {


private JLabel titleLabel;
private JButton startButton;
private JRadioButton serverRadioButton;
private JRadioButton clientRadioButton;
private JToggleButton snapshotToggleButton;
private JCheckBox decompileCheckbox;
private JComboBox<Version> versionBox;
private JProgressBar progressBar;
private JTextField statusBox;

public App() {
Expand All @@ -36,6 +38,35 @@ public App() {
finishSetup();
}

private void createProgressBar() {
this.progressBar = new JProgressBar(0, 100);
this.progressBar.setValue(0);
this.progressBar.setStringPainted(true);
hookSize(() -> {
int width = (int) (getSize().width * 0.90);
this.progressBar.setBounds((getSize().width / 2) - (width / 2), 200, width, 30);
});
this.progressBar.setVisible(false);
add(this.progressBar);
}

public void updateProgressBar(int current, int total, String message) {
SwingUtilities.invokeLater(() -> {
this.progressBar.setValue(current);
this.progressBar.setMaximum(total);
this.progressBar.setString(String.format("%s (%d%%)", message, current));
this.progressBar.setVisible(true);
this.statusBox.setVisible(false);
});
}
public void resetProgressBar() {
SwingUtilities.invokeLater(() -> {
this.progressBar.setValue(0);
this.progressBar.setVisible(false);
this.statusBox.setVisible(true);
});
}

private void startSetup() {
if (Util.isRunningMacOS()) {
// If we're running on Mac, set the logo
Expand All @@ -54,6 +85,7 @@ private void startSetup() {
createStartButton();
setVisible(true);
toggleControls();
createProgressBar();
}

private void setupWindow() {
Expand Down
29 changes: 20 additions & 9 deletions src/main/java/com/shanebeestudios/mcdeob/util/AppLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
* Custom logger for FernFlower
* <p>Copied/Modifier from {@link org.jetbrains.java.decompiler.main.decompiler.ThreadedPrintStreamLogger}</p>
*/

public class AppLogger extends IFernflowerLogger {

private App app;
private Thread statusThread;
private int processedCount = 0;
private int decompiledCount = 0;
private int totalClasses = 0;

public AppLogger(App app) {
this.app = app;
Expand All @@ -25,17 +27,25 @@ public AppLogger(App app) {
private void startTimer() {
this.statusThread = new Thread(() -> {
while (this.app != null) {
if (this.processedCount != 0) {
if (this.decompiledCount == 0) {
this.app.updateStatusBox("PreProcessing... (" + this.processedCount + " classes)");
if (totalClasses > 0) {
if (processedCount < totalClasses) {
// Preprocessing stage
int progress = Math.min(99, (int)((processedCount / (double)totalClasses) * 100));
this.app.updateProgressBar(progress, 100, "PreProcessing...");
} else if (decompiledCount < totalClasses) {
// Decompiling stage
int progress = Math.min(99, (int)((decompiledCount / (double)totalClasses) * 100));
this.app.updateProgressBar(progress, 100, "Decompiling...");
} else {
this.app.updateStatusBox("Decompiling... (" + this.decompiledCount + " / " + this.processedCount + " classes)");
// Completed
this.app.updateProgressBar(100, 100, "Decompilation Complete");
}
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
Thread.currentThread().interrupt();
break;
}
}
});
Expand All @@ -44,10 +54,13 @@ private void startTimer() {

public void stopLogging() {
if (this.app == null) return;
this.app.resetProgressBar();
this.app = null;
this.statusThread = null;
}



public void writeMessage(String message, Severity severity) {
if (this.accepts(severity)) {
switch (severity) {
Expand All @@ -70,33 +83,31 @@ public void writeMessage(String message, Severity severity, Throwable t) {
public void startProcessingClass(String className) {
if (this.accepts(Severity.INFO)) {
this.writeMessage("PreProcessing class " + className, Severity.INFO);
totalClasses++;
}

}

public void endProcessingClass() {
if (this.accepts(Severity.INFO)) {
this.writeMessage("... done", Severity.INFO);
this.processedCount++;
}

}

public void startReadingClass(String className) {
if (this.accepts(Severity.INFO)) {
this.writeMessage("Decompiling class " + className, Severity.INFO);
}

}

public void endReadingClass() {
if (this.accepts(Severity.INFO)) {
this.writeMessage("... done", Severity.INFO);
this.decompiledCount++;
}

}


public void startClass(String className) {
if (this.accepts(Severity.INFO)) {
this.writeMessage("Processing class " + className, Severity.TRACE);
Expand Down