Update #0 - First Release

This commit is contained in:
LAX1DUDE
2022-12-25 01:12:28 -08:00
commit e7179fad45
2154 changed files with 256324 additions and 0 deletions

View File

@ -0,0 +1,167 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.MergePullRequest;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.PullRequestTask;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CreateUnpatched;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InitTask;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.SetupWorkspace;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.TaskClean;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EaglerBuildTools {
public static File repositoryRoot = new File(".");
public static void main(String[] args) {
System.out.println("Eaglercraft 1.8 Build Tools");
System.out.println("Copyright (c) 2022 LAX1DUDE");
System.out.println();
if(!System.getProperty("eaglercraft.isJava11", "false").equalsIgnoreCase("true")) {
try {
if (!(boolean) Class
.forName("net.lax1dude.eaglercraft.v1_8.buildtools.Java11Check", true,
new URLClassLoader(new URL[] { (new File("buildtools/Java11Check.jar")).toURI().toURL() }))
.getMethod("classLoadCheck").invoke(null)) {
throw new RuntimeException("wtf?");
}
}catch(Throwable t) {
System.err.println("ERROR: A minimum of Java 11 is required to run this tool!");
System.err.println();
System.err.println("You are using Java " + System.getProperty("java.version"));
System.err.println();
return;
}
}
if(args.length == 0 || (args.length == 1 && args[0].equalsIgnoreCase("help"))) {
System.out.println("Options:");
System.out.println(" help - displays this message");
System.out.println(" init - decompiles 1.8.8 and applies the main repo's patch files");
System.out.println(" workspace - creates a dev workspace with a gradle project to compile the source");
System.out.println(" pullrequest - scans changes in the dev workspace and creates patch files for pull requests");
System.out.println(" pullrequest_test - makes new workspace and re-applies the patches in 'pullrequest'");
System.out.println(" unpatched - creates a zip file with the vanilla minecraft source without patches");
System.out.println(" merge - merges the patch files in the pullrequest folder with the repo's main patch files");
System.out.println(" merge_direct - merges changes in the dev workspace with the repo's main patch files");
System.out.println(" clean - delete init and pullrequest directories, keeps dev workspace");
System.out.println();
}else if(args.length == 1 && args[0].equalsIgnoreCase("init")) {
LicensePrompt.display();
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(InitTask.initTask()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("workspace")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(SetupWorkspace.setupWorkspace()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("pullrequest")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(PullRequestTask.pullRequest()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("pullrequest_test")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(SetupWorkspace.pullRequestTest()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("unpatched")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(CreateUnpatched.createUnpatched()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("merge")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(MergePullRequest.mergeTask()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("merge_direct")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(MergePullRequest.mergeDirect()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("clean")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(TaskClean.taskClean()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else {
System.err.println("Invalid arguments!");
}
}
}

View File

@ -0,0 +1,183 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.json.JSONObject;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EaglerBuildToolsConfig {
public static File temporary_directory = new File(System.getProperty("user.home"), ".eaglercraft_1.8_buildtools");
private static boolean temporary_directory_isInit = false;
private static boolean temporary_directory_mentioned = false;
public static File workspace_directory = new File("../eaglercraft_1.8_workspace");
private static boolean workspace_directory_isInit = false;
private static boolean workspace_directory_mentioned = false;
private static boolean config_file_loaded = false;
public static final File configFile = new File("./buildtools_config.json");
public static void load() {
if(configFile.exists()) {
try(FileInputStream is = new FileInputStream(configFile)) {
byte[] r = new byte[(int)configFile.length()];
is.read(r);
is.close();
String jsonTxt = new String(r, StandardCharsets.UTF_8);
JSONObject obj = new JSONObject(jsonTxt);
String path = obj.optString("temporary_directory", null);
if(path != null) {
temporary_directory = new File(path);
temporary_directory_isInit = true;
}
path = obj.optString("workspace_directory", null);
if(path != null) {
workspace_directory = new File(path);
workspace_directory_isInit = true;
}
}catch(Throwable ex) {
System.err.println("Failed to read config!");
ex.printStackTrace();
}
}
}
public static void save() {
JSONObject obj = new JSONObject();
if(temporary_directory_isInit) obj.put("temporary_directory", temporary_directory.getAbsolutePath());
if(workspace_directory_isInit) obj.put("workspace_directory", workspace_directory.getAbsoluteFile());
try(FileOutputStream os = new FileOutputStream(configFile)) {
os.write(obj.toString(4).getBytes(StandardCharsets.UTF_8));
os.close();
}catch(IOException e) {
System.err.println("Failed to write config!");
e.printStackTrace();
}
}
private static void mentionConfigPath() {
System.out.println("Edit '" + configFile.getName() + "' to change");
}
public static File getTemporaryDirectory() {
if(!config_file_loaded) {
load();
config_file_loaded = true;
}
if(!temporary_directory_isInit) {
File f = temporary_directory;
System.out.println();
System.out.println("Using temporary directory: " + f.getAbsolutePath());
temporary_directory_mentioned = true;
f = askIfChangeIsWanted(f);
temporary_directory = f;
temporary_directory_isInit = true;
while(!temporary_directory.isDirectory() && !temporary_directory.mkdirs()) {
System.err.println("Failed to create: " + f.getAbsolutePath());
temporary_directory = askIfChangeIsWanted(f);
}
save();
System.out.println();
return temporary_directory;
}else {
if(!temporary_directory_mentioned) {
System.out.println("Using temporary directory: " + temporary_directory.getAbsolutePath());
temporary_directory_mentioned = true;
while(!temporary_directory.isDirectory() && !temporary_directory.mkdirs()) {
System.err.println("Failed to create: " + temporary_directory.getAbsolutePath());
temporary_directory = askIfChangeIsWanted(temporary_directory);
}
mentionConfigPath();
}
return temporary_directory;
}
}
public static File getWorkspaceDirectory() {
if(!config_file_loaded) {
load();
config_file_loaded = true;
}
if(!workspace_directory_isInit) {
File f = workspace_directory;
System.out.println();
System.out.println("Using workspace directory: " + f.getAbsolutePath());
workspace_directory_mentioned = true;
f = askIfChangeIsWanted(f);
workspace_directory = f;
workspace_directory_isInit = true;
while(!workspace_directory.isDirectory() && !workspace_directory.mkdirs()) {
System.err.println("Failed to create: " + f.getAbsolutePath());
workspace_directory = askIfChangeIsWanted(f);
}
save();
System.out.println();
return workspace_directory;
}else {
if(!workspace_directory_mentioned) {
System.out.println("Using workspace directory: " + workspace_directory.getAbsolutePath());
workspace_directory_mentioned = true;
while(!workspace_directory.isDirectory() && !workspace_directory.mkdirs()) {
System.err.println("Failed to create: " + workspace_directory.getAbsolutePath());
workspace_directory = askIfChangeIsWanted(workspace_directory);
}
mentionConfigPath();
}
return workspace_directory;
}
}
public static File askIfChangeIsWanted(File in) {
System.out.println("Would you like to change this directory?");
System.out.println("Enter 'Y' for yes or 'N' for no: ");
String l = "N";
try {
l = (new BufferedReader(new InputStreamReader(System.in))).readLine();
} catch (IOException e) {
}
if(l != null && ((l = l.trim()).equalsIgnoreCase("y") || l.equalsIgnoreCase("yes"))) {
System.out.println();
System.out.println("Type a new filename or hit 'Enter' to browse: ");
try {
l = (new BufferedReader(new InputStreamReader(System.in))).readLine();
} catch (IOException e) {
}
if(l != null && (l = l.trim()).length() > 0) {
in = new File(l);
}else {
File f = FileChooserTool.load(true);
if(f == null) {
System.out.println("You hit cancel on the file chooser, the directory '" + in.getAbsolutePath() + "' will be used.");
in = askIfChangeIsWanted(in);
}else {
in = f;
}
}
}
return in;
}
}

View File

@ -0,0 +1,46 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FileChooserTool {
public static final JFileChooser fc = new JFileChooser();
public static File load(boolean directory) {
fc.setFileSelectionMode(directory ? JFileChooser.DIRECTORIES_ONLY : JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.setFileHidingEnabled(false);
fc.setDialogTitle("Eaglercraft Buildtools");
JFrame parent = new JFrame();
parent.setBounds(0, 0, 50, 50);
parent.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
parent.setAlwaysOnTop(true);
parent.setTitle("File Chooser");
parent.setLocationRelativeTo(null);
parent.setVisible(true);
if(fc.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
parent.dispose();
return fc.getSelectedFile();
}else {
parent.dispose();
return null;
}
}
}

View File

@ -0,0 +1,64 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class LicensePrompt {
public static void main(String[] args) {
System.out.println();
display();
}
public static void display() {
System.out.println("WARNING: You must agree to the LICENSE before running this command");
System.out.println();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(LicensePrompt.class.getResourceAsStream("/lang/LICENSE_console_wrapped.txt"), StandardCharsets.UTF_8))) {
String line;
while((line = reader.readLine()) != null) {
if(line.equals("<press enter>")) {
pressEnter();
}else {
System.out.println(line);
}
}
}catch(IOException ex) {
System.err.println();
System.err.println("ERROR: could not display license text");
System.err.println("Please read the \"LICENSE\" file before using this software");
System.err.println();
pressEnter();
}
}
private static void pressEnter() {
System.out.println();
System.out.println("(press ENTER to continue)");
while(true) {
try {
if(System.in.read() == '\n') {
break;
}
}catch(IOException ex) {
throw new RuntimeException("Unexpected IOException reading STDIN", ex);
}
}
}
}

View File

@ -0,0 +1,447 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.decompiler;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class LocalVariableGenerator extends SignatureVisitor {
public static final Map<Character,String> primitiveNames = new HashMap();
public static final Set<String> illegalVariableNames = new HashSet();
static {
primitiveNames.put('Z', "Flag");
primitiveNames.put('C', "Char");
primitiveNames.put('B', "Byte");
primitiveNames.put('S', "Short");
primitiveNames.put('I', "Int");
primitiveNames.put('F', "Float");
primitiveNames.put('J', "Long");
primitiveNames.put('D', "Double");
primitiveNames.put('V', "Void");
illegalVariableNames.addAll(Arrays.asList(
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
"continue", "const", "default", "do", "double", "else", "enum", "exports", "extends",
"final", "finally", "float", "for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native", "new", "package", "private",
"protected", "public", "return", "short", "static", "strictfp", "super", "switch",
"synchronized", "this", "throw", "throws", "transient", "try", "var", "void",
"volatile", "while", "string"
));
}
private String baseClass = null;
private boolean isArray = false;
private String typeParam1 = null;
private boolean typeParam1IsArray = false;
private String typeParam2 = null;
private boolean typeParam2IsArray = false;
public static final SignatureVisitor nopVisitor = new SignatureVisitor(Opcodes.ASM5) {};
LocalVariableGenerator() {
super(Opcodes.ASM5);
}
public static String createName(String sig) {
SignatureReader rd = new SignatureReader(sig);
LocalVariableGenerator gen = new LocalVariableGenerator();
rd.acceptType(gen);
return gen.getResult();
}
private String removePath(String in) {
int idx = in.lastIndexOf('/');
int idx2 = in.lastIndexOf('$');
if(idx2 > idx && idx2 != in.length() - 1) {
idx = idx2;
}
if(idx != -1) {
in = in.substring(idx + 1);
}
if(in.length() == 0 || Character.isDigit(in.charAt(0))) {
in = "obj" + in;
}
return in;
}
String getResult() {
String rt;
if(baseClass == null) {
rt = "Object";
}else {
rt = removePath(baseClass);
}
if(typeParam1 == null && typeParam2 == null) {
if(isArray) {
rt = "ArrayOf" + rt;
}
}else {
if(isArray) {
rt = rt + "Array";
}
}
if(typeParam1 != null && typeParam2 == null) {
if(typeParam1IsArray) {
typeParam1 = typeParam1 + "Array";
}
rt = rt + "Of" + removePath(typeParam1);
}else if(typeParam1 != null && typeParam2 != null) {
if(typeParam1IsArray) {
typeParam1 = typeParam1 + "Array";
}
if(typeParam2IsArray) {
typeParam2 = typeParam2 + "Array";
}
rt = rt + "Of" + removePath(typeParam1) + "And" + removePath(typeParam2);
}
return rt;
}
@Override
public SignatureVisitor visitArrayType() {
if(baseClass == null) {
isArray = true;
return new ArrayTypeVisitor();
}else {
return nopVisitor;
}
}
private class ArrayTypeVisitor extends SignatureVisitor {
protected ArrayTypeVisitor() {
super(Opcodes.ASM5);
}
@Override
public void visitBaseType(char descriptor) {
if(baseClass == null) {
baseClass = primitiveNames.get(descriptor);
}
}
@Override
public void visitClassType(String name) {
if(baseClass == null) {
baseClass = name;
}
}
@Override
public SignatureVisitor visitArrayType() {
if(baseClass == null) {
baseClass = "array";
}
return nopVisitor;
}
@Override public SignatureVisitor visitClassBound() { return nopVisitor; }
@Override public SignatureVisitor visitExceptionType() { return nopVisitor; }
@Override public SignatureVisitor visitInterface() { return nopVisitor; }
@Override public SignatureVisitor visitInterfaceBound() { return nopVisitor; }
@Override public SignatureVisitor visitParameterType() { return nopVisitor; }
@Override public SignatureVisitor visitTypeArgument(char wildcard) { return nopVisitor; }
@Override public SignatureVisitor visitReturnType() { return nopVisitor; }
}
@Override
public void visitBaseType(char descriptor) {
if(baseClass == null) {
baseClass = primitiveNames.get(descriptor);
}
}
@Override
public SignatureVisitor visitClassBound() {
//System.out.println("class: " + this);
return nopVisitor;
}
@Override
public void visitClassType(String name) {
//System.out.println("classType: " + name);
if(baseClass == null) {
baseClass = name;
}
}
@Override
public void visitEnd() {
}
@Override
public SignatureVisitor visitExceptionType() {
return nopVisitor;
}
@Override
public void visitFormalTypeParameter(String name) {
//System.out.println("formalTypeParam: " + name);
}
@Override
public void visitInnerClassType(String name) {
//System.out.println("innerClassType: " + name);
}
@Override
public SignatureVisitor visitInterface() {
return nopVisitor;
}
@Override
public SignatureVisitor visitInterfaceBound() {
return nopVisitor;
}
@Override
public SignatureVisitor visitParameterType() {
return nopVisitor;
}
private class TypeParamVisitor extends SignatureVisitor {
private boolean hasVisited = false;
private final int firstOrSecond;
protected TypeParamVisitor(int firstOrSecond) {
super(Opcodes.ASM5);
this.firstOrSecond = firstOrSecond;
}
@Override
public void visitBaseType(char descriptor) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = primitiveNames.get(descriptor);
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = primitiveNames.get(descriptor);
}
}
hasVisited = true;
}
}
@Override
public void visitClassType(String name) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = name;
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = name;
}
}
hasVisited = true;
}
}
@Override
public SignatureVisitor visitArrayType() {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1IsArray = true;
return new TypeParamArrayVisitor();
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2IsArray = true;
return new TypeParamArrayVisitor();
}
}
}
return nopVisitor;
}
private class TypeParamArrayVisitor extends SignatureVisitor {
protected TypeParamArrayVisitor() {
super(Opcodes.ASM5);
}
@Override
public void visitBaseType(char descriptor) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = primitiveNames.get(descriptor);
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = primitiveNames.get(descriptor);
}
}
hasVisited = true;
}
}
@Override
public void visitClassType(String name) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = name;
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = name;
}
}
hasVisited = true;
}
}
@Override
public SignatureVisitor visitArrayType() {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = "array";
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = "array";
}
}
hasVisited = true;
}
return nopVisitor;
}
@Override public SignatureVisitor visitClassBound() { return nopVisitor; }
@Override public SignatureVisitor visitExceptionType() { return nopVisitor; }
@Override public SignatureVisitor visitInterface() { return nopVisitor; }
@Override public SignatureVisitor visitInterfaceBound() { return nopVisitor; }
@Override public SignatureVisitor visitParameterType() { return nopVisitor; }
@Override public SignatureVisitor visitTypeArgument(char wildcard) { return nopVisitor; }
@Override public SignatureVisitor visitReturnType() { return nopVisitor; }
}
}
@Override
public SignatureVisitor visitReturnType() {
return nopVisitor;
}
@Override
public SignatureVisitor visitSuperclass() {
return nopVisitor;
}
@Override
public void visitTypeArgument() {
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
if(typeParam1 == null) {
return new TypeParamVisitor(1);
}else if(typeParam2 == null) {
return new TypeParamVisitor(2);
}else {
return nopVisitor;
}
}
@Override
public void visitTypeVariable(String name) {
}
public static String nextLocalVariableNameFromString(Map<String,Integer> tmpLocalsMap, String signature, String pfx) {
String str = signature.length() == 1 ? primitiveNames.get(signature.charAt(0)) : null;
if(str == null) {
str = LocalVariableGenerator.createName(signature);
}
String ls = str.toLowerCase();
Integer i = tmpLocalsMap.get(ls);
if(i == null) {
tmpLocalsMap.put(ls, 1);
if(Character.isDigit(str.charAt(str.length() - 1))) {
str = str + "_1";
}else {
str = illegalVariableNames.contains(str.toLowerCase()) ? str + "1" : str;
}
}else {
int ii = i.intValue() + 1;
tmpLocalsMap.put(ls, ii);
if(Character.isDigit(str.charAt(str.length() - 1)) || str.contains("And") || str.length() > 16) {
str = str + "_" + ii;
}else {
str = str + ii;
}
}
return pfx == null ? camelCase(str) : pfx + str;
}
public static String nextLocalVariableName(Map<String,Integer> tmpLocalsMap, LocalVariableGenerator signature, String pfx) {
String str = signature.getResult();
String ls = str.toLowerCase();
Integer i = tmpLocalsMap.get(ls);
if(i == null) {
tmpLocalsMap.put(ls, 1);
if(Character.isDigit(str.charAt(str.length() - 1))) {
str = str + "_1";
}else {
str = illegalVariableNames.contains(str.toLowerCase()) ? str + "1" : str;
}
}else {
int ii = i.intValue() + 1;
tmpLocalsMap.put(ls, ii);
if(Character.isDigit(str.charAt(str.length() - 1)) || str.contains("And") || str.length() > 16) {
str = str + "_" + ii;
}else {
str = str + ii;
}
}
return pfx == null ? camelCase(str) : pfx + str;
}
public static String camelCase(String in) {
if(in == null || in.length() <= 0) {
return "name";
}else {
if(in.length() > 1 && Character.isUpperCase(in.charAt(0)) && Character.isUpperCase(in.charAt(1))) {
return "var" + in;
}else {
return in.substring(0, 1).toLowerCase() + in.substring(1);
}
}
}
}

View File

@ -0,0 +1,88 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.decompiler;
import java.util.ArrayList;
import java.util.HashMap;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ParameterSplitter extends SignatureVisitor {
protected ParameterSplitter() {
super(Opcodes.ASM5);
}
protected static final ArrayList<LocalVariableGenerator> ret = new ArrayList();
protected static final HashMap<String,Integer> usedLocals = new HashMap();
public static int getParameterArray(String sig, String[] input) {
SignatureReader rd = new SignatureReader(sig);
ParameterSplitter pms = new ParameterSplitter();
ret.clear();
usedLocals.clear();
rd.accept(pms);
int l = ret.size();
if(l > input.length) {
l = input.length;
}
int c = 0;
for(int i = 0; i < l; ++i) {
if(input[i] == null) {
input[i] = LocalVariableGenerator.nextLocalVariableName(usedLocals, ret.get(i), "par");
++c;
}
}
return c;
}
public static String[] getParameterSigArray(String sig, String pfx) {
SignatureReader rd = new SignatureReader(sig);
ParameterSplitter pms = new ParameterSplitter();
ret.clear();
usedLocals.clear();
rd.accept(pms);
String[] r = new String[ret.size()];
for(int i = 0; i < r.length; ++i) {
r[i] = LocalVariableGenerator.nextLocalVariableName(usedLocals, ret.get(i), pfx);
}
return r;
}
@Override
public SignatureVisitor visitParameterType() {
LocalVariableGenerator lv = new LocalVariableGenerator();
ret.add(lv);
return lv;
}
@Override public SignatureVisitor visitClassBound() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitExceptionType() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitInterface() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitInterfaceBound() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitTypeArgument(char wildcard) { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitReturnType() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitArrayType() { return LocalVariableGenerator.nopVisitor; }
@Override public void visitBaseType(char descriptor) { }
@Override public void visitClassType(String name) { }
@Override public void visitEnd() { }
@Override public void visitFormalTypeParameter(String name) { }
@Override public void visitInnerClassType(String name) { }
@Override public SignatureVisitor visitSuperclass() { return LocalVariableGenerator.nopVisitor; }
@Override public void visitTypeArgument() { }
@Override public void visitTypeVariable(String name) { }
}

View File

@ -0,0 +1,416 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.commons.io.FileUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries.MissingJARsException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.DecompileMinecraft;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.FFMPEG;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InitMCP;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMClassLoadException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMRuntimeException;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CompileLatestClientGUI {
public static CompileLatestClientFrame frame = null;
public static void main(String[] args) {
System.out.println();
System.out.println("Launching client compiler wizard...");
System.out.println("Copyright (c) 2022 lax1dude");
System.out.println();
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e) {
System.err.println("Could not set system look and feel: " + e.toString());
}
if(!System.getProperty("eaglercraft.isJava11", "false").equalsIgnoreCase("true")) {
try {
if (!(boolean) Class
.forName("net.lax1dude.eaglercraft.v1_8.buildtools.Java11Check", true,
new URLClassLoader(new URL[] { (new File("buildtools/Java11Check.jar")).toURI().toURL() }))
.getMethod("classLoadCheck").invoke(null)) {
throw new RuntimeException("wtf?");
}
}catch(Throwable t) {
JOptionPane.showMessageDialog(null, "Error: Java 11 is required to run this program", "Unsupported JRE", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
return;
}
}
frame = new CompileLatestClientFrame();
frame.frmCompileLatestClient.setLocationRelativeTo(null);
frame.frmCompileLatestClient.setVisible(true);
System.out.println("you eagler");
System.out.println();
frame.launchLogUpdateThread();
System.setOut(new PrintStream(new ConsoleRedirector(false)));
System.setErr(new PrintStream(new ConsoleRedirector(true)));
if(JavaC.jdkHome == null) {
if(JOptionPane.showConfirmDialog(frame.frmCompileLatestClient, "Error: A JDK is required to run this program!\nYou are currently running on a JRE\nDo you have a JDK installed that you would like to use instead?", "Unsupported JRE", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "You need at least JDK 8 to compile EaglercraftX 1.8!\nSelect the path to the installation you want to use", "Unsupported JRE", JOptionPane.INFORMATION_MESSAGE);
JFileChooser fileChooser = new JFileChooser((new File(System.getProperty("java.home"))).getParentFile());
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setFileHidingEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
while(true) {
if(fileChooser.showOpenDialog(frame.frmCompileLatestClient) == JFileChooser.APPROVE_OPTION) {
File f = fileChooser.getSelectedFile();
if(JavaC.windows ? (new File(f, "bin/javac.exe")).exists() : (new File(f, "bin/javac")).canExecute()) {
break;
}else {
if(JOptionPane.showConfirmDialog(frame.frmCompileLatestClient, "Could not find a java compiler in this directory!\nWould you like to try again?", "Unsupported JRE", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
continue;
}
}
}
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "Please install JDK 8 or newer to continue", "Unsupported JRE", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
return;
}
JavaC.jdkHome = fileChooser.getSelectedFile();
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "The JDK \"" + JavaC.jdkHome.getAbsolutePath() + "\" will be used to compile EaglercraftX", "Unsupported JRE", JOptionPane.INFORMATION_MESSAGE);
}else {
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "Please install a JDK and re-launch this program", "Unsupported JRE", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
}
EventQueue.invokeLater(new Runnable() {
public void run() {
frame.scrollPane_LicenseText.getVerticalScrollBar().setValue(0);
}
});
}
});
}
public static class CompileFailureException extends RuntimeException {
public CompileFailureException(String msg) {
super(msg);
}
public CompileFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}
public static void runCompiler() {
try {
runCompiler0();
}catch(CompileFailureException t) {
System.out.println();
System.err.println("Error: " + t.getMessage());
t.printStackTrace();
frame.finishCompiling(true, t.getMessage());
return;
}catch(Throwable t) {
System.out.println();
System.err.println("Error: unhandled exception caught while compiling!");
t.printStackTrace();
frame.finishCompiling(true, t.toString());
return;
}
if(!frame.finished) {
System.out.println();
System.err.println("Error: compilation finished with unknown status!");
frame.finishCompiling(true, "Compilation finished with unknown status");
}
}
private static void runCompiler0() throws Throwable {
File repositoryFolder = new File(frame.textField_RepositoryPath.getText().trim());
EaglerBuildTools.repositoryRoot = repositoryFolder;
File modCoderPack = new File(frame.textField_ModCoderPack.getText().trim());
File minecraftJar = new File(frame.textField_JarFilePath.getText().trim());
File assetsIndex = new File(frame.textField_AssetsIndexJSON.getText().trim());
File outputDirectory = new File(frame.textField_OutputDirectory.getText().trim());
File temporaryDirectory = new File(outputDirectory, "build");
File[] existingOutput = outputDirectory.listFiles();
if(existingOutput.length > 0) {
System.out.println("Deleting existing files from the output directory...");
try {
for(int i = 0; i < existingOutput.length; ++i) {
File f = existingOutput[i];
if(f.isDirectory()) {
FileUtils.deleteDirectory(f);
}else {
if(!f.delete()) {
throw new IOException("Could not delete: " + f.getAbsolutePath());
}
}
}
}catch(IOException t) {
throw new CompileFailureException("Could not delete old output directory: " + t.getMessage());
}
}
File mcpDataTMP = new File(temporaryDirectory, "ModCoderPack");
File minecraftSrcTmp = new File(temporaryDirectory, "MinecraftSrc");
String ffmpeg = frame.chckbxUsePathFFmpeg.isSelected() ? "" : frame.textField_pathToFFmpeg.getText().trim();
if(ffmpeg.length() == 0) {
FFMPEG.foundFFMPEG = "ffmpeg";
}else {
FFMPEG.foundFFMPEG = ffmpeg;
}
String mavenRepositoryURL = frame.getRepositoryURL();
File mavenRepositoryFolder = null;
if(mavenRepositoryURL == null) {
mavenRepositoryFolder = new File(frame.textField_MavenRepoLocal.getText().trim());
}
boolean generateOfflineDownload = frame.chckbxOutputOfflineDownload.isSelected();
boolean keepTemporaryFiles = frame.chckbxKeepTemporaryFiles.isSelected();
if(!mcpDataTMP.isDirectory() && !mcpDataTMP.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + mcpDataTMP.getAbsolutePath() + "\"!");
}
if(!InitMCP.initTask(modCoderPack, mcpDataTMP)) {
throw new CompileFailureException("Error: could not initialize MCP from \"" + modCoderPack.getAbsolutePath() + "\"!");
}
if(!minecraftSrcTmp.isDirectory() && !minecraftSrcTmp.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + minecraftSrcTmp.getAbsolutePath() + "\"!");
}
if(!DecompileMinecraft.decompileMinecraft(mcpDataTMP, minecraftJar, minecraftSrcTmp, assetsIndex, false)) {
throw new CompileFailureException("Error: could not decompile and patch 1.8.8.jar from \"" + minecraftJar.getAbsolutePath() + "\"!");
}
try {
FileUtils.copyFile(new File(repositoryFolder, "patches/minecraft/output_license.txt"), new File(temporaryDirectory, "MinecraftSrc/LICENSE"));
}catch(IOException ex) {
System.err.println("Error: failed to write LICENSE in temporary directory!");
ex.printStackTrace();
}
System.out.println();
if(frame.rdbtnMavenRepoLocal.isSelected()) {
System.out.println("TeaVM JARs will be loaded from: " + frame.textField_MavenRepoLocal.getText());
}else {
String url = frame.getRepositoryURL();
System.out.println("TeaVM JARs will be downloaded from repository: " + url);
System.out.println();
try {
TeaVMBinaries.downloadFromMaven(url, new File("##TEAVM.TMP##"));
}catch(MissingJARsException ex) {
throw new CompileFailureException(ex.getMessage());
}
}
System.out.println();
int compileResultCode;
File compiledResultClasses = new File(temporaryDirectory, "classes");
try {
try {
compileResultCode = JavaC.runJavaC(new File(minecraftSrcTmp, "minecraft_src_javadoc.jar"),
compiledResultClasses, temporaryDirectory, TeaVMBinaries.getTeaVMRuntimeClasspath(),
new File(repositoryFolder, "sources/main/java"), new File(repositoryFolder, "sources/teavm/java"));
}catch(IOException ex) {
throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex);
}
System.out.println();
if(compileResultCode == 0) {
System.out.println("Java compiler completed successfully");
}else {
throw new CompileFailureException("failed to run javac compiler! exit code " + compileResultCode + ", check log");
}
}finally {
File extractedSrcTmp = new File(temporaryDirectory, "MinecraftSrc/src_javadoc_tmp");
if(extractedSrcTmp.exists()) {
System.out.println();
System.out.println("Deleting temporary directory: " + extractedSrcTmp.getAbsolutePath());
try {
FileUtils.deleteDirectory(extractedSrcTmp);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory!");
ex.printStackTrace();
}
}
}
System.out.println();
System.out.println("Preparing arguments for TeaVM...");
if(!TeaVMBinaries.tryLoadTeaVMBridge()) {
System.err.println("Failed to locate TeaVMBridge.jar, you can specify it's path manually by adding the JVM argument \"-Deaglercraft.TeaVMBridge=<path>\"");
throw new CompileFailureException("Failed to locate TeaVMBridge.jar!");
}
Map<String, Object> teavmArgs = new HashMap();
List<String> teavmClassPath = new ArrayList();
teavmClassPath.add(compiledResultClasses.getAbsolutePath());
teavmClassPath.addAll(Arrays.asList(TeaVMBinaries.getTeaVMRuntimeClasspath()));
teavmArgs.put("classPathEntries", teavmClassPath);
teavmArgs.put("entryPointName", "main");
teavmArgs.put("mainClass", "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass");
teavmArgs.put("minifying", true);
teavmArgs.put("optimizationLevel", "ADVANCED");
teavmArgs.put("targetDirectory", outputDirectory.getAbsolutePath());
teavmArgs.put("generateSourceMaps", true);
teavmArgs.put("targetFileName", "classes.js");
System.out.println();
boolean teavmStatus;
try {
teavmStatus = TeaVMBridge.compileTeaVM(teavmArgs);
}catch(TeaVMClassLoadException ex) {
throw new CompileFailureException("Failed to link TeaVM jar files! Did you select the wrong jar?", ex);
}catch(TeaVMRuntimeException ex) {
throw new CompileFailureException("Failed to run TeaVM! Check log", ex);
}
if(!teavmStatus) {
frame.finishCompiling(true, "TeaVM reported problems, check the log");
return;
}
File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar");
if(!epkCompiler.exists()) {
throw new CompileFailureException("EPKCompiler JAR file is missing: " + epkCompiler.getAbsolutePath());
}
System.out.println();
System.out.println("Writing default index.html...");
FileUtils.copyFile(new File(repositoryFolder, "buildtools/production-index.html"), new File(outputDirectory, "index.html"));
FileUtils.copyFile(new File(repositoryFolder, "buildtools/production-favicon.png"), new File(outputDirectory, "favicon.png"));
FileUtils.copyFile(new File(repositoryFolder, "sources/setup/workspace_template/javascript/fix-webm-duration.js"), new File(outputDirectory, "fix-webm-duration.js"));
System.out.println();
System.out.println("Running EPKCompiler on assets...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
((new File(minecraftSrcTmp, "minecraft_res_patch.jar")).getAbsolutePath() + System.getProperty("path.separator") +
(new File(repositoryFolder, "sources/resources")).getAbsolutePath()), (new File(outputDirectory, "assets.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Running EPKCompiler on languages.zip...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
(new File(minecraftSrcTmp, "minecraft_languages.zip")).getAbsolutePath(),
(new File(temporaryDirectory, "languages.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Creating languages directory...");
File langDirectory = new File(outputDirectory, "lang");
byte[] copyBuffer = new byte[16384];
int i;
try(ZipInputStream zis = new ZipInputStream(new FileInputStream(new File(minecraftSrcTmp, "minecraft_languages.zip")))) {
ZipEntry etr;
while((etr = zis.getNextEntry()) != null) {
if(!etr.isDirectory()) {
File phile = new File(langDirectory, etr.getName());
File parent = phile.getParentFile();
if(!parent.exists() && !parent.mkdirs()) {
throw new IOException("Could not create directory: " + parent.getAbsolutePath());
}
try(FileOutputStream os = new FileOutputStream(phile)) {
while((i = zis.read(copyBuffer)) != -1) {
os.write(copyBuffer, 0, i);
}
}
}
}
}
System.out.println();
if(generateOfflineDownload) {
System.out.println("Running offline download generator...");
System.out.println();
File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar");
MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] {
(new File(repositoryFolder, "sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt")).getAbsolutePath(),
(new File(outputDirectory, "classes.js")).getAbsolutePath() + System.getProperty("path.separator")
+ (new File(outputDirectory, "fix-webm-duration.js")).getAbsolutePath(),
(new File(outputDirectory, "assets.epk")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(),
(new File(outputDirectory, "build/languages.epk")).getAbsolutePath()
});
}
System.out.println("Releasing external ClassLoader(s)...");
System.out.println();
TeaVMBridge.free();
EPKCompiler.free();
if(generateOfflineDownload) {
MakeOfflineDownload.free();
}
if(!keepTemporaryFiles) {
System.out.println("Cleaning up temporary files...");
try {
FileUtils.deleteDirectory(temporaryDirectory);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory: " + temporaryDirectory.getAbsolutePath());
ex.printStackTrace();
}
}
System.out.println();
System.out.println("Client build successful! Check the output directory for your files");
try {
Desktop.getDesktop().open(outputDirectory);
}catch(Throwable t) {
}
frame.finishCompiling(false, "");
}
}

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ConsoleRedirector extends OutputStream {
private final OutputStream stdout;
private final boolean err;
public ConsoleRedirector(boolean err) {
stdout = err ? System.err : System.out;
this.err = err;
}
@Override
public void write(byte[] b, int o, int l) throws IOException {
stdout.write(b, o, l);
String append = new String(b, o, l, StandardCharsets.US_ASCII);
if(err) {
CompileLatestClientGUI.frame.logError(append);
}else {
CompileLatestClientGUI.frame.logInfo(append);
}
}
@Override
public void write(int b) throws IOException {
stdout.write(b);
write0(b);
}
private void write0(int b) throws IOException {
char c = (char)b;
if(c != '\r') {
if(err && c != '\n') {
CompileLatestClientGUI.frame.logError(new String(new char[] { c }));
}else {
CompileLatestClientGUI.frame.logInfo(new String(new char[] { c }));
}
}
}
}

View File

@ -0,0 +1,67 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EPKCompiler {
private static File currentJarFile = null;
private static URLClassLoader classLoader = null;
private static Method mainMethod = null;
public static void compilerMain(File jarFile, String[] args) throws InvocationTargetException {
if(currentJarFile != null && !currentJarFile.equals(jarFile)) {
throw new IllegalArgumentException("Cannot load two different EPKCompiler versions into the same runtime");
}
if(mainMethod == null) {
currentJarFile = jarFile;
try {
if(classLoader == null) {
classLoader = new URLClassLoader(new URL[] { jarFile.toURI().toURL() }, ClassLoader.getSystemClassLoader());
}
Class epkCompilerMain = classLoader.loadClass("CompilePackage");
mainMethod = epkCompilerMain.getDeclaredMethod("main", String[].class);
} catch (MalformedURLException | SecurityException e) {
throw new IllegalArgumentException("Illegal EPKCompiler JAR path!", e);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalArgumentException("EPKCompiler JAR does not contain main class: 'CompilePackage'", e);
}
}
try {
mainMethod.invoke(null, new Object[] { args });
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new IllegalArgumentException("EPKCompiler JAR does not contain valid 'main' method", e);
}
}
public static void free() {
if(classLoader != null) {
try {
classLoader.close();
classLoader = null;
} catch (IOException e) {
System.err.println("Memory leak, failed to release EPKCompiler ClassLoader!");
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,223 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class JavaC {
public static final boolean windows;
public static File jdkHome;
public static final List<String> compilerFlags = Arrays.asList(
"-Xlint:-unchecked", "-Xlint:-options", "-Xlint:-deprecation",
"-source", "1.8", "-target", "1.8"
);
private static int debugSourceFileCount = 0;
public static int runJavaC(File mcSourceJar, File outputDirectory, File tmpDirectory, String[] teavmClasspath,
File... eaglerSourceDirs) throws IOException {
if(!outputDirectory.exists() && !outputDirectory.mkdirs()) {
throw new IOException("Could not create output directory: " + outputDirectory.getAbsolutePath());
}
if(!tmpDirectory.exists() && !tmpDirectory.mkdirs()) {
throw new IOException("Could not create temporary directory: " + outputDirectory.getAbsolutePath());
}
File minecraftSrcTmp = new File(tmpDirectory, "MinecraftSrc/src_javadoc_tmp");
if(!minecraftSrcTmp.exists() && !minecraftSrcTmp.mkdirs()) {
throw new IOException("Could not create temporary directory: " + minecraftSrcTmp.getAbsolutePath());
}
debugSourceFileCount = 0;
File argFile = new File(tmpDirectory, "sourceFiles.txt");
try(PrintWriter writer = new PrintWriter(new FileWriter(argFile))) {
System.out.println("Extracting decompiled source...");
byte[] copyBuffer = new byte[16384];
int copyBufferLen;
try(ZipInputStream zis = new ZipInputStream(new FileInputStream(mcSourceJar))) {
ZipEntry etr;
while((etr = zis.getNextEntry()) != null && !etr.isDirectory()) {
String n = etr.getName();
if(n.endsWith(".java")) {
File writeTo = new File(minecraftSrcTmp, n);
File parent = writeTo.getParentFile();
if(!parent.exists() && !parent.mkdirs()) {
throw new IOException("Could not create temporary directory: " + parent.getAbsolutePath());
}
try(OutputStream os = new FileOutputStream(writeTo)) {
while((copyBufferLen = zis.read(copyBuffer)) != -1) {
os.write(copyBuffer, 0, copyBufferLen);
}
}
writer.println("\"" + writeTo.getAbsolutePath().replace('\\', '/') + "\"");
++debugSourceFileCount;
}
}
}
System.out.println("Scanning source folder paths...");
for(int i = 0; i < eaglerSourceDirs.length; ++i) {
discoverSourceFiles(eaglerSourceDirs[i], writer);
}
}
List<String> commandBuilder = new ArrayList();
if(windows) {
commandBuilder.add((new File(jdkHome, "bin/javac.exe")).getAbsolutePath());
}else {
commandBuilder.add((new File(jdkHome, "bin/javac")).getAbsolutePath());
}
commandBuilder.addAll(compilerFlags);
String pathSeparator = System.getProperty("path.separator");
commandBuilder.add("-classpath");
commandBuilder.add(String.join(pathSeparator, teavmClasspath));
commandBuilder.add("-sourcepath");
StringBuilder sourcePathBuilder = new StringBuilder();
sourcePathBuilder.append(mcSourceJar.getAbsolutePath());
for(int i = 0; i < eaglerSourceDirs.length; ++i) {
sourcePathBuilder.append(pathSeparator).append(eaglerSourceDirs[i].getAbsolutePath());
}
commandBuilder.add(sourcePathBuilder.toString());
commandBuilder.add("-d");
commandBuilder.add(outputDirectory.getAbsolutePath());
commandBuilder.add("@" + argFile.getAbsolutePath());
System.out.println();
for(int i = 0, l = commandBuilder.size(); i < l; ++i) {
String e = commandBuilder.get(i);
if(e.indexOf(' ') != -1) {
System.out.print("\"" + e + "\"");
}else {
System.out.print(e);
}
System.out.print(' ');
}
System.out.println();
System.out.println();
System.out.println("Compiling " + debugSourceFileCount + " source files...");
ProcessBuilder procBuilder = new ProcessBuilder(commandBuilder);
procBuilder.directory(tmpDirectory);
Process javacProcess = procBuilder.start();
InputStream stdout = javacProcess.getInputStream();
InputStream stderr = javacProcess.getErrorStream();
byte[] readBuffer = new byte[128];
int j;
boolean tick;
do {
tick = false;
j = stdout.available();
if(j > 0) {
if(j > 128) {
j = 128;
}
stdout.read(readBuffer, 0, j);
System.out.write(readBuffer, 0, j);
tick = true;
}
j = stderr.available();
if(j > 0) {
if(j > 128) {
j = 128;
}
stderr.read(readBuffer, 0, j);
System.err.write(readBuffer, 0, j);
tick = true;
}
if(!tick) {
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
}
}while(javacProcess.isAlive());
while(true) {
try {
return javacProcess.waitFor();
} catch (InterruptedException e) {
}
}
}
private static void discoverSourceFiles(File folder, PrintWriter printWriter) throws IOException {
File[] files = folder.listFiles();
for(int i = 0; i < files.length; ++i) {
File f = files[i];
String name = f.getAbsolutePath();
if(f.isDirectory()) {
discoverSourceFiles(f, printWriter);
}else {
if(name.endsWith(".java")) {
printWriter.println("\"" + name.replace('\\', '/') + "\"");
++debugSourceFileCount;
}
}
}
}
static {
windows = System.getProperty("os.name").toLowerCase().contains("windows");
String javac = windows ? "javac.exe" : "javac";
File jdkHomeProp = new File(System.getProperty("java.home"));
if((new File(jdkHomeProp, "bin/" + javac)).isFile()) {
jdkHome = jdkHomeProp;
}else if((new File(jdkHomeProp, "../bin/" + javac)).isFile()) {
jdkHome = jdkHomeProp.getParentFile();
}else {
jdkHome = null;
}
}
}

View File

@ -0,0 +1,67 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class MakeOfflineDownload {
private static File currentJarFile = null;
private static URLClassLoader classLoader = null;
private static Method mainMethod = null;
public static void compilerMain(File jarFile, String[] args) throws InvocationTargetException {
if(currentJarFile != null && !currentJarFile.equals(jarFile)) {
throw new IllegalArgumentException("Cannot load two different MakeOfflineDownload versions into the same runtime");
}
if(mainMethod == null) {
currentJarFile = jarFile;
try {
if(classLoader == null) {
classLoader = new URLClassLoader(new URL[] { jarFile.toURI().toURL() }, ClassLoader.getSystemClassLoader());
}
Class epkCompilerMain = classLoader.loadClass("net.lax1dude.eaglercraft.v1_8.buildtools.workspace.MakeOfflineDownload");
mainMethod = epkCompilerMain.getDeclaredMethod("main", String[].class);
} catch (MalformedURLException | SecurityException e) {
throw new IllegalArgumentException("Illegal MakeOfflineDownload JAR path!", e);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalArgumentException("MakeOfflineDownload JAR does not contain main class: 'net.lax1dude.eaglercraft.v1_8.buildtools.workspace.MakeOfflineDownload'", e);
}
}
try {
mainMethod.invoke(null, new Object[] { args });
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new IllegalArgumentException("MakeOfflineDownload JAR does not contain valid 'main' method", e);
}
}
public static void free() {
if(classLoader != null) {
try {
classLoader.close();
classLoader = null;
} catch (IOException e) {
System.err.println("Memory leak, failed to release MakeOfflineDownload ClassLoader!");
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,422 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FileUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class TeaVMBinaries {
public static final String teavmCoreJar = "teavm-core-0.6.1.jar";
public static final String teavmCoreMaven = "org/teavm/teavm-core/0.6.1/teavm-core-0.6.1.jar";
public static File teavmCore = null;
public static final String teavmCliJar = "teavm-cli-0.6.1.jar";
public static final String teavmCliMaven = "org/teavm/teavm-cli/0.6.1/teavm-cli-0.6.1.jar";
public static File teavmCli = null;
public static final String teavmToolingJar = "teavm-tooling-0.6.1.jar";
public static final String teavmToolingMaven = "org/teavm/teavm-tooling/0.6.1/teavm-tooling-0.6.1.jar";
public static File teavmTooling = null;
public static final String teavmPlatformJar = "teavm-platform-0.6.1.jar";
public static final String teavmPlatformMaven = "org/teavm/teavm-platform/0.6.1/teavm-platform-0.6.1.jar";
public static File teavmPlatform = null;
public static final String teavmClasslibJar = "teavm-classlib-0.6.1.jar";
public static final String teavmClasslibMaven = "org/teavm/teavm-classlib/0.6.1/teavm-classlib-0.6.1.jar";
public static File teavmClasslib = null;
public static final String teavmInteropJar = "teavm-interop-0.6.1.jar";
public static final String teavmInteropMaven = "org/teavm/teavm-interop/0.6.1/teavm-interop-0.6.1.jar";
public static File teavmInterop = null;
public static final String teavmJSOJar = "teavm-jso-0.6.1.jar";
public static final String teavmJSOMaven = "org/teavm/teavm-jso/0.6.1/teavm-jso-0.6.1.jar";
public static File teavmJSO = null;
public static final String teavmJSOApisJar = "teavm-jso-apis-0.6.1.jar";
public static final String teavmJSOApisMaven = "org/teavm/teavm-jso-apis/0.6.1/teavm-jso-apis-0.6.1.jar";
public static File teavmJSOApis = null;
public static final String teavmJSOImplJar = "teavm-jso-impl-0.6.1.jar";
public static final String teavmJSOImplMaven = "org/teavm/teavm-jso-impl/0.6.1/teavm-jso-impl-0.6.1.jar";
public static File teavmJSOImpl = null;
public static final String teavmMetaprogrammingAPIJar = "teavm-metaprogramming-api-0.6.1.jar";
public static final String teavmMetaprogrammingAPIMaven = "org/teavm/teavm-metaprogramming-api/0.6.1/teavm-metaprogramming-api-0.6.1.jar";
public static File teavmMetaprogrammingAPI = null;
public static final String teavmMetaprogrammingImplJar = "teavm-metaprogramming-impl-0.6.1.jar";
public static final String teavmMetaprogrammingImplMaven = "org/teavm/teavm-metaprogramming-impl/0.6.1/teavm-metaprogramming-impl-0.6.1.jar";
public static File teavmMetaprogrammingImpl = null;
public static final String teavmJodaTimeJar = "joda-time-2.7.jar";
public static final String teavmJodaTimeMaven = "joda-time/joda-time/2.7/joda-time-2.7.jar";
public static File teavmJodaTime = null;
public static final String teavmJZLIBJar = "jzlib-1.1.3.jar";
public static final String teavmJZLIBMaven = "com/jcraft/jzlib/1.1.3/jzlib-1.1.3.jar";
public static File teavmJZLIB = null;
public static File teavmBridge = null;
public static class MissingJARsException extends RuntimeException {
public final List<String> jars;
public MissingJARsException(String msg, List<String> jars) {
super(msg);
this.jars = jars;
}
public MissingJARsException(List<String> jars) {
this("The following JAR files were not found: " + String.join(", ", jars), jars);
}
}
public static void downloadFromMaven(String url, File outputDir) throws MissingJARsException {
teavmCore = teavmPlatform = teavmClasslib = teavmInterop = teavmJSO =
teavmJSOApis = teavmJSOImpl = teavmMetaprogrammingAPI = teavmMetaprogrammingImpl =
teavmJodaTime = teavmJZLIB = teavmTooling = teavmCli = null;
if(url.lastIndexOf('/') != url.length() - 1) {
url += "/";
}
String urlConc = url + teavmCoreMaven;
try {
File f = new File(outputDir, teavmCoreJar);
copyURLToFileCheck404(urlConc, f);
teavmCore = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmCliMaven;
try {
File f = new File(outputDir, teavmCliJar);
copyURLToFileCheck404(urlConc, f);
teavmCli = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmToolingMaven;
try {
File f = new File(outputDir, teavmToolingJar);
copyURLToFileCheck404(urlConc, f);
teavmTooling = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmPlatformMaven;
try {
File f = new File(outputDir, teavmPlatformJar);
copyURLToFileCheck404(urlConc, f);
teavmPlatform = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmClasslibMaven;
try {
File f = new File(outputDir, teavmClasslibJar);
copyURLToFileCheck404(urlConc, f);
teavmClasslib = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmInteropMaven;
try {
File f = new File(outputDir, teavmInteropJar);
copyURLToFileCheck404(urlConc, f);
teavmInterop = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJSOMaven;
try {
File f = new File(outputDir, teavmJSOJar);
copyURLToFileCheck404(urlConc, f);
teavmJSO = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJSOApisMaven;
try {
File f = new File(outputDir, teavmJSOApisJar);
copyURLToFileCheck404(urlConc, f);
teavmJSOApis = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJSOImplMaven;
try {
File f = new File(outputDir, teavmJSOImplJar);
copyURLToFileCheck404(urlConc, f);
teavmJSOImpl = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmMetaprogrammingAPIMaven;
try {
File f = new File(outputDir, teavmMetaprogrammingAPIJar);
copyURLToFileCheck404(urlConc, f);
teavmMetaprogrammingAPI = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmMetaprogrammingImplMaven;
try {
File f = new File(outputDir, teavmMetaprogrammingImplJar);
copyURLToFileCheck404(urlConc, f);
teavmMetaprogrammingImpl = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJodaTimeMaven;
try {
File f = new File(outputDir, teavmJodaTimeJar);
copyURLToFileCheck404(urlConc, f);
teavmJodaTime = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJZLIBMaven;
try {
File f = new File(outputDir, teavmJZLIBJar);
copyURLToFileCheck404(urlConc, f);
teavmJZLIB = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
}
public static void loadFromDirectory(File directory) throws MissingJARsException {
teavmCore = teavmPlatform = teavmClasslib = teavmInterop = teavmJSO =
teavmJSOApis = teavmJSOImpl = teavmMetaprogrammingAPI = teavmMetaprogrammingImpl =
teavmJodaTime = teavmJZLIB = teavmTooling = teavmCli = null;
discoverJars(directory);
List<String> missingJars = new ArrayList();
if(teavmCore == null) {
missingJars.add(teavmCoreJar);
}
if(teavmCli == null) {
missingJars.add(teavmCliJar);
}
if(teavmTooling == null) {
missingJars.add(teavmToolingJar);
}
if(teavmPlatform == null) {
missingJars.add(teavmPlatformJar);
}
if(teavmClasslib == null) {
missingJars.add(teavmClasslibJar);
}
if(teavmInterop == null) {
missingJars.add(teavmInteropJar);
}
if(teavmJSO == null) {
missingJars.add(teavmJSOJar);
}
if(teavmJSOApis == null) {
missingJars.add(teavmJSOApisJar);
}
if(teavmJSOImpl == null) {
missingJars.add(teavmJSOImplJar);
}
if(teavmMetaprogrammingAPI == null) {
missingJars.add(teavmMetaprogrammingAPIJar);
}
if(teavmMetaprogrammingImpl == null) {
missingJars.add(teavmMetaprogrammingImplJar);
}
if(teavmJodaTime == null) {
missingJars.add(teavmJodaTimeJar);
}
if(teavmJZLIB == null) {
missingJars.add(teavmJZLIBJar);
}
if(missingJars.size() > 0) {
throw new MissingJARsException(missingJars);
}
}
private static void discoverJars(File dir) {
File[] files = dir.listFiles();
for(int i = 0; i < files.length; ++i) {
File f = files[i];
if(f.isDirectory()) {
discoverJars(f);
}else {
String n = f.getName();
switch(n) {
case teavmCoreJar:
teavmCore = f;
break;
case teavmCliJar:
teavmCli = f;
break;
case teavmToolingJar:
teavmTooling = f;
break;
case teavmPlatformJar:
teavmPlatform = f;
break;
case teavmClasslibJar:
teavmClasslib = f;
break;
case teavmInteropJar:
teavmInterop = f;
break;
case teavmJSOJar:
teavmJSO = f;
break;
case teavmJSOApisJar:
teavmJSOApis = f;
break;
case teavmJSOImplJar:
teavmJSOImpl = f;
break;
case teavmMetaprogrammingAPIJar:
teavmMetaprogrammingAPI = f;
break;
case teavmMetaprogrammingImplJar:
teavmMetaprogrammingImpl = f;
break;
case teavmJodaTimeJar:
teavmJodaTime = f;
break;
case teavmJZLIBJar:
teavmJZLIB = f;
break;
default:
break;
}
}
}
}
private static void copyURLToFileCheck404(String urlIn, File fileOut) throws IOException {
System.out.println("downloading: " + urlIn);
URL url;
try {
url = new URL(urlIn);
}catch(MalformedURLException ex) {
throw new IOException("Invalid URL: " + urlIn, ex);
}
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
int respCode = connection.getResponseCode();
if(respCode != 200) {
connection.disconnect();
throw new IOException("Recieved response code: " + respCode);
}
try (InputStream stream = connection.getInputStream()) {
FileUtils.copyInputStreamToFile(stream, fileOut);
}finally {
connection.disconnect(); // is this required?
}
}
public static boolean tryLoadTeaVMBridge() {
String override = System.getProperty("eaglercraft.TeaVMBridge");
File teavmBridgeCheck;
if(override != null) {
teavmBridgeCheck = new File(override);
}else {
try {
teavmBridgeCheck = new File(new File(URLDecoder.decode(
TeaVMBinaries.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath(),
"UTF-8")).getParent(), "TeaVMBridge.jar");
} catch (URISyntaxException | UnsupportedEncodingException e) {
System.err.println("Failed to locate TeaVMBridge.jar relative to BuildTools jar!");
e.printStackTrace();
return false;
}
}
if(teavmBridgeCheck.exists()) {
teavmBridge = teavmBridgeCheck;
return true;
}else {
System.err.println("File does not exist: " + teavmBridgeCheck.getAbsolutePath());
return false;
}
}
public static File[] getTeaVMCompilerClasspath() {
return new File[] { teavmCore, teavmCli, teavmTooling, teavmInterop, teavmMetaprogrammingAPI, teavmBridge };
}
public static String[] getTeaVMRuntimeClasspath() {
return new String[] {
teavmJodaTime.getAbsolutePath(), teavmJZLIB.getAbsolutePath(), teavmClasslib.getAbsolutePath(),
teavmInterop.getAbsolutePath(), teavmJSO.getAbsolutePath(), teavmJSOApis.getAbsolutePath(),
teavmJSOImpl.getAbsolutePath(), teavmMetaprogrammingAPI.getAbsolutePath(),
teavmMetaprogrammingImpl.getAbsolutePath(), teavmPlatform.getAbsolutePath()
};
}
}

View File

@ -0,0 +1,612 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui.headless;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.LicensePrompt;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.EPKCompiler;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.JavaC;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.MakeOfflineDownload;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.CompileLatestClientGUI.CompileFailureException;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries.MissingJARsException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.DecompileMinecraft;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.FFMPEG;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InitMCP;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMClassLoadException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMRuntimeException;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CompileLatestClientHeadless {
public static void main(String[] args) throws Throwable {
System.out.println();
System.out.println("Launching client compiler...");
System.out.println("Copyright (c) 2022 lax1dude");
System.out.println();
boolean yes = false;
String configPath = null;
if(args.length == 1) {
configPath = args[0];
}else if(args.length == 2 && (yes = args[0].equalsIgnoreCase("-y"))) {
configPath = args[1];
}else {
System.err.println("Usage: java -jar BuildTools.jar [-y] <config file>");
System.err.println();
System.exit(-1);
return;
}
System.out.println("Loading config file: " + configPath);
System.out.println();
File configFile = new File(configPath);
String configSrc;
try {
configSrc = FileUtils.readFileToString(configFile, StandardCharsets.UTF_8);
}catch(FileNotFoundException ex) {
ex.printStackTrace();
System.err.println();
System.err.println("ERROR: File '" + configFile.getAbsolutePath() + "' does not exist!");
System.err.println();
System.exit(-1);
return;
}
JSONObject configJSON;
try {
configJSON = new JSONObject(configSrc);
}catch(JSONException ex) {
System.err.println("ERROR: Could not parse '" + configFile.getName() + "' as JSON!");
System.err.println();
System.err.println(ex.toString());
System.err.println();
System.exit(-1);
return;
}
File repositoryFolder;
File modCoderPack;
File minecraftJar;
File assetsIndex;
File outputDirectory;
File temporaryDirectory;
String ffmpeg = "ffmpeg";
String mavenURL = null;
File mavenLocal = null;
File productionIndex = null;
File productionFavicon = null;
List<String> addScripts = null;
List<String> removeScripts = null;
List<String> injectInOfflineScripts = null;
boolean generateOffline;
File offlineTemplate = null;
boolean keepTemporaryFiles;
boolean writeSourceMap = false;
boolean minifying = true;
try {
repositoryFolder = new File(configJSON.optString("repositoryFolder", "."));
modCoderPack = new File(configJSON.getString("modCoderPack"));
minecraftJar = new File(configJSON.getString("minecraftJar"));
assetsIndex = new File(configJSON.getString("assetsIndex"));
outputDirectory = new File(configJSON.getString("outputDirectory"));
String tmpDir = configJSON.optString("temporaryDirectory");
temporaryDirectory = tmpDir == null ? new File(outputDirectory, "build") : new File(tmpDir);
ffmpeg = configJSON.optString("ffmpeg", ffmpeg);
if(ffmpeg.length() == 0) {
ffmpeg = "ffmpeg";
}
String prodIndex = configJSON.optString("productionIndex");
if(prodIndex != null) {
productionIndex = new File(prodIndex);
String prodFavicon = configJSON.optString("productionFavicon");
if(prodFavicon != null) {
productionFavicon = new File(prodFavicon);
}
JSONArray scripts = configJSON.optJSONArray("addScripts");
if(scripts != null) {
int l = scripts.length();
if(l > 0) {
addScripts = new ArrayList(l);
for(int i = 0; i < l; ++i) {
addScripts.add(scripts.getString(i));
}
}
}
scripts = configJSON.optJSONArray("removeScripts");
if(scripts != null) {
int l = scripts.length();
if(l > 0) {
removeScripts = new ArrayList(l);
for(int i = 0; i < l; ++i) {
removeScripts.add(scripts.getString(i));
}
}
}
scripts = configJSON.optJSONArray("injectInOffline");
if(scripts != null) {
int l = scripts.length();
if(l > 0) {
injectInOfflineScripts = new ArrayList(l);
for(int i = 0; i < l; ++i) {
injectInOfflineScripts.add(scripts.getString(i));
}
}
}
}
mavenURL = configJSON.optString("mavenURL");
mavenLocal = new File(configJSON.getString("mavenLocal"));
generateOffline = configJSON.optBoolean("generateOfflineDownload", false);
if(generateOffline) {
offlineTemplate = new File(configJSON.getString("offlineDownloadTemplate"));
}
keepTemporaryFiles = configJSON.optBoolean("keepTemporaryFiles", false);
writeSourceMap = configJSON.optBoolean("writeSourceMap", false);
minifying = configJSON.optBoolean("minifying", true);
}catch(JSONException ex) {
System.err.println("CONFIG ERROR: " + ex.toString());
System.err.println();
System.exit(-1);
return;
}
System.out.println("Loaded config successfully:");
System.out.println();
System.out.println(" - Repository Folder: " + repositoryFolder.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Mod Coder Pack: " + modCoderPack.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Minecraft 1.8.8: " + minecraftJar.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Assets Index 1.8: " + assetsIndex.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Temporary Directory: " + temporaryDirectory.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Output Directory: " + outputDirectory.getAbsolutePath().replace('\\', '/'));
System.out.println(" - FFmpeg Executable: " + ffmpeg.replace('\\', '/'));
System.out.println(" - Maven Repo URL: " + mavenURL);
System.out.println(" - Maven Local Dir: " + mavenLocal.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Production Index: " + (productionIndex == null ? "null" : productionIndex.getAbsolutePath().replace('\\', '/')));
System.out.println(" - Production Favicon: " + (productionFavicon == null ? "null" : productionFavicon.getAbsolutePath().replace('\\', '/')));
System.out.println(" - Generate Offline: " + generateOffline);
System.out.println(" - Offline Template: " + (offlineTemplate == null ? "null" : offlineTemplate.getAbsolutePath().replace('\\', '/')));
System.out.println(" - Inject in Offline: " + (injectInOfflineScripts == null ? "[ ]" : "[ " + String.join(", ", injectInOfflineScripts).replace('\\', '/') + " ]"));
System.out.println(" - Minifying: " + minifying);
System.out.println(" - Write Source Map: " + writeSourceMap);
System.out.println(" - Keep Temp Files: " + keepTemporaryFiles);
System.out.println(" - Add Scripts: " + (addScripts == null ? "[ ]" : "[ " + String.join(", ", addScripts).replace('\\', '/') + " ]"));
System.out.println(" - Remove Scripts: " + (removeScripts == null ? "[ ]" : "[ " + String.join(", ", removeScripts).replace('\\', '/') + " ]"));
System.out.println();
if(!yes) {
System.out.println();
LicensePrompt.display();
System.out.println();
}
EaglerBuildTools.repositoryRoot = repositoryFolder;
try {
if(!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
throw new CompileFailureException("Could not create output directory!");
}
File[] existingOutput = outputDirectory.listFiles();
if(existingOutput.length > 0) {
if(!yes) {
System.out.print("Output directory has existing files, would you like to delete them? [y/n] ");
String str = (new BufferedReader(new InputStreamReader(System.in))).readLine();
System.out.println();
if(!str.equalsIgnoreCase("y") && !str.equalsIgnoreCase("yes")) {
System.out.println("Build cancelled.");
System.out.println();
System.exit(-1);
return;
}
}
System.out.println("Deleting existing files from the output directory...");
try {
for(int i = 0; i < existingOutput.length; ++i) {
File f = existingOutput[i];
if(f.isDirectory()) {
FileUtils.deleteDirectory(f);
}else {
if(!f.delete()) {
throw new IOException("Could not delete: " + f.getAbsolutePath());
}
}
}
}catch(IOException t) {
throw new CompileFailureException("Could not delete old output directory: " + t.getMessage());
}
}
File mcpDataTMP = new File(temporaryDirectory, "ModCoderPack");
File minecraftSrcTmp = new File(temporaryDirectory, "MinecraftSrc");
if(ffmpeg.length() == 0) {
FFMPEG.foundFFMPEG = "ffmpeg";
}else {
FFMPEG.foundFFMPEG = ffmpeg;
}
if(!mcpDataTMP.isDirectory() && !mcpDataTMP.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + mcpDataTMP.getAbsolutePath() + "\"!");
}
if(!InitMCP.initTask(modCoderPack, mcpDataTMP)) {
throw new CompileFailureException("Error: could not initialize MCP from \"" + modCoderPack.getAbsolutePath() + "\"!");
}
if(!minecraftSrcTmp.isDirectory() && !minecraftSrcTmp.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + minecraftSrcTmp.getAbsolutePath() + "\"!");
}
if(!DecompileMinecraft.decompileMinecraft(mcpDataTMP, minecraftJar, minecraftSrcTmp, assetsIndex, false)) {
throw new CompileFailureException("Error: could not decompile and patch 1.8.8.jar from \"" + minecraftJar.getAbsolutePath() + "\"!");
}
try {
FileUtils.copyFile(new File(repositoryFolder, "patches/minecraft/output_license.txt"), new File(temporaryDirectory, "MinecraftSrc/LICENSE"));
}catch(IOException ex) {
System.err.println("Error: failed to write LICENSE in temporary directory!");
ex.printStackTrace();
}
System.out.println();
if(mavenURL == null) {
System.out.println("TeaVM JARs will be loaded from: " + mavenLocal.getAbsolutePath());
System.out.println();
try {
TeaVMBinaries.loadFromDirectory(mavenLocal);
}catch(MissingJARsException ex) {
throw new CompileFailureException(ex.getMessage());
}
}else {
System.out.println("TeaVM JARs will be downloaded from repository: " + mavenURL);
System.out.println();
try {
TeaVMBinaries.downloadFromMaven(mavenURL, mavenLocal);
}catch(MissingJARsException ex) {
throw new CompileFailureException(ex.getMessage());
}
System.out.println();
System.out.println("Notice: make sure to delete \"" + mavenLocal.getAbsolutePath() + "\" when the compiler is finished, it will not be deleted automatically");
System.out.println();
}
int compileResultCode;
File compiledResultClasses = new File(temporaryDirectory, "classes");
try {
try {
compileResultCode = JavaC.runJavaC(new File(minecraftSrcTmp, "minecraft_src_javadoc.jar"),
compiledResultClasses, temporaryDirectory, TeaVMBinaries.getTeaVMRuntimeClasspath(),
new File(repositoryFolder, "sources/main/java"), new File(repositoryFolder, "sources/teavm/java"));
}catch(IOException ex) {
throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex);
}
System.out.println();
if(compileResultCode == 0) {
System.out.println("Java compiler completed successfully");
}else {
throw new CompileFailureException("failed to run javac compiler! exit code " + compileResultCode + ", check log");
}
}finally {
File extractedSrcTmp = new File(temporaryDirectory, "MinecraftSrc/src_javadoc_tmp");
if(extractedSrcTmp.exists()) {
System.out.println();
System.out.println("Deleting temporary directory: " + extractedSrcTmp.getAbsolutePath());
try {
FileUtils.deleteDirectory(extractedSrcTmp);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory!");
ex.printStackTrace();
}
}
}
System.out.println();
System.out.println("Preparing arguments for TeaVM...");
if(!TeaVMBinaries.tryLoadTeaVMBridge()) {
System.err.println("Failed to locate TeaVMBridge.jar, you can specify it's path manually by adding the JVM argument \"-Deaglercraft.TeaVMBridge=<path>\"");
throw new CompileFailureException("Failed to locate TeaVMBridge.jar!");
}
Map<String, Object> teavmArgs = new HashMap();
List<String> teavmClassPath = new ArrayList();
teavmClassPath.add(compiledResultClasses.getAbsolutePath());
teavmClassPath.addAll(Arrays.asList(TeaVMBinaries.getTeaVMRuntimeClasspath()));
teavmArgs.put("classPathEntries", teavmClassPath);
teavmArgs.put("entryPointName", "main");
teavmArgs.put("mainClass", "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass");
teavmArgs.put("minifying", minifying);
teavmArgs.put("optimizationLevel", "ADVANCED");
teavmArgs.put("targetDirectory", outputDirectory.getAbsolutePath());
teavmArgs.put("generateSourceMaps", writeSourceMap);
teavmArgs.put("targetFileName", "classes.js");
System.out.println();
boolean teavmStatus;
try {
teavmStatus = TeaVMBridge.compileTeaVM(teavmArgs);
}catch(TeaVMClassLoadException ex) {
throw new CompileFailureException("Failed to link TeaVM jar files! Did you select the wrong jar?", ex);
}catch(TeaVMRuntimeException ex) {
throw new CompileFailureException("Failed to run TeaVM! Check log", ex);
}
if(!teavmStatus) {
System.out.println("TeaVM reported problems, check the log");
System.out.println();
System.exit(-1);
return;
}
File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar");
if(!epkCompiler.exists()) {
throw new CompileFailureException("EPKCompiler JAR file is missing: " + epkCompiler.getAbsolutePath());
}
System.out.println();
System.out.println("Writing index.html...");
System.out.println();
String faviconExt = null;
if(productionFavicon != null) {
faviconExt = productionFavicon.getName();
int i = faviconExt.lastIndexOf('.');
if(i != -1) {
faviconExt = faviconExt.substring(i + 1);
}
}
try(BufferedReader indexReader = new BufferedReader(new FileReaderUTF(productionIndex));
PrintWriter indexWriter = new PrintWriter(new FileWriterUTF(new File(outputDirectory, "index.html")))) {
String line;
while((line = indexReader.readLine()) != null) {
String trim = line.trim();
if(trim.startsWith("<link")) {
if(trim.contains("rel=\"shortcut icon\"")) {
if(faviconExt != null) {
String contentType = "image/png";
switch(faviconExt) {
case "png":
break;
case "jpg":
case "jpeg":
contentType = "image/jpeg";
break;
case "ico":
contentType = "image/x-icon";
break;
case "gif":
contentType = "image/gif";
break;
case "bmp":
contentType = "image/bmp";
break;
case "webp":
contentType = "image/webp";
break;
default:
System.err.println();
System.err.println("WARNING: favicon extension '" + faviconExt + "' is unknown, defaulting to image/png MIME type");
System.err.println();
break;
}
indexWriter.println(line.replace("favicon.png", "favicon." + faviconExt).replace("image/png", contentType));
System.out.println("Setting favicon <link> href to \"favicon." + faviconExt + "\", MIME type \"" + contentType + "\" in index.html");
}else {
System.out.println("Removed favicon <link> from index.html, no favicon configured");
}
continue;
}
}
if(trim.startsWith("<meta")) {
if(trim.contains("property=\"og:image\"")) {
if(faviconExt != null) {
indexWriter.println(line.replace("favicon.png", "favicon." + faviconExt));
System.out.println("Setting og:image <link> href to \"favicon." + faviconExt + "\"");
}else {
System.out.println("Removed og:image <meta> tag in index.html, no favicon configured");
}
continue;
}
}
if(trim.startsWith("<script")) {
int idx = line.indexOf("src=\"");
int idx2 = line.indexOf('"', idx + 5);
String srcSubStr = line.substring(idx + 5, idx2);
if(addScripts != null && srcSubStr.equals("classes.js")) {
for(int i = 0, l = addScripts.size(); i < l; ++i) {
String addSrc = addScripts.get(i);
indexWriter.println(line.replace("classes.js", addSrc));
System.out.println("Added <script> tag with src \"" + addSrc + "\" to index.html");
}
}
if(removeScripts != null && removeScripts.contains(srcSubStr)) {
System.out.println("Removed <script> tag with src \"" + srcSubStr + "\" from index.html");
continue;
}
}
indexWriter.println(line);
}
}
System.out.println();
if(productionFavicon != null) {
FileUtils.copyFile(productionFavicon, new File(outputDirectory, "favicon." + faviconExt));
}
FileUtils.copyFile(new File(repositoryFolder, "sources/setup/workspace_template/javascript/fix-webm-duration.js"), new File(outputDirectory, "fix-webm-duration.js"));
System.out.println();
System.out.println("Running EPKCompiler on assets...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
((new File(minecraftSrcTmp, "minecraft_res_patch.jar")).getAbsolutePath() + System.getProperty("path.separator") +
(new File(repositoryFolder, "sources/resources")).getAbsolutePath()), (new File(outputDirectory, "assets.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Running EPKCompiler on languages.zip...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
(new File(minecraftSrcTmp, "minecraft_languages.zip")).getAbsolutePath(),
(new File(temporaryDirectory, "languages.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Creating languages directory...");
File langDirectory = new File(outputDirectory, "lang");
byte[] copyBuffer = new byte[16384];
int i;
try(ZipInputStream zis = new ZipInputStream(new FileInputStream(new File(minecraftSrcTmp, "minecraft_languages.zip")))) {
ZipEntry etr;
while((etr = zis.getNextEntry()) != null) {
if(!etr.isDirectory()) {
File phile = new File(langDirectory, etr.getName());
File parent = phile.getParentFile();
if(!parent.exists() && !parent.mkdirs()) {
throw new IOException("Could not create directory: " + parent.getAbsolutePath());
}
try(FileOutputStream os = new FileOutputStream(phile)) {
while((i = zis.read(copyBuffer)) != -1) {
os.write(copyBuffer, 0, i);
}
}
}
}
}
System.out.println();
if(generateOffline) {
System.out.println("Running offline download generator...");
System.out.println();
File offlineTemplateArg = offlineTemplate;
if(injectInOfflineScripts != null) {
offlineTemplateArg = new File(temporaryDirectory, "offline_download_template.txt");
try(BufferedReader indexReader = new BufferedReader(new FileReaderUTF(offlineTemplate));
PrintWriter indexWriter = new PrintWriter(new FileWriterUTF(offlineTemplateArg))) {
String line;
while((line = indexReader.readLine()) != null) {
if(line.contains("${classes_js}")) {
for(int j = 0, l = injectInOfflineScripts.size(); j < l; ++j) {
File injectFile = new File(injectInOfflineScripts.get(j));
String injectName = injectFile.getAbsolutePath();
String injectNameName = injectFile.getName();
System.out.println("Adding file to offline download template: " + injectName);
indexWriter.println("// %%%%%%%%% " + injectNameName + " %%%%%%%%%");
indexWriter.println();
try(BufferedReader insertReader = new BufferedReader(new FileReaderUTF(injectFile))) {
String line2;
while((line2 = insertReader.readLine()) != null) {
indexWriter.println(line2);
}
}
indexWriter.println();
char[] percents = new char[20 + injectNameName.length()];
for(int k = 0; k < percents.length; ++k) {
percents[k] = '%';
}
indexWriter.print("// ");
indexWriter.println(percents);
indexWriter.println();
indexWriter.println();
}
System.out.println();
}
indexWriter.println(line);
}
}
}
File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar");
MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] {
offlineTemplateArg.getAbsolutePath(),
(new File(outputDirectory, "classes.js")).getAbsolutePath() + System.getProperty("path.separator")
+ (new File(outputDirectory, "fix-webm-duration.js")).getAbsolutePath(),
(new File(outputDirectory, "assets.epk")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(),
(new File(temporaryDirectory, "languages.epk")).getAbsolutePath()
});
}
System.out.println("Releasing external ClassLoader(s)...");
System.out.println();
TeaVMBridge.free();
EPKCompiler.free();
if(generateOffline) {
MakeOfflineDownload.free();
}
if(!keepTemporaryFiles) {
System.out.println("Cleaning up temporary files...");
try {
FileUtils.deleteDirectory(temporaryDirectory);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory: " + temporaryDirectory.getAbsolutePath());
ex.printStackTrace();
}
}
System.out.println();
System.out.println("Client build successful! Check the output directory for your files");
}catch(CompileFailureException ex) {
System.out.println();
System.err.println("COMPILATION FAILED: " + ex.getMessage());
System.out.println();
System.exit(-1);
}
}
}

View File

@ -0,0 +1,153 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ApplyPatchesToZip {
public static final int patchContextLength = 3;
public static void applyPatches(File zipIn, File unpatchedZipIn, File patchesIn, File zipOut, boolean compress, boolean useECR) throws Throwable {
if(!patchesIn.isDirectory()) {
FileUtils.copyFile(zipIn, zipOut);
return;
}
Map<String,byte[]> jarEntriesUnpatched;
if(unpatchedZipIn != null) {
System.out.println("Loading files from '" + unpatchedZipIn.getName() + "'...");
try(FileInputStream is = new FileInputStream(unpatchedZipIn)) {
jarEntriesUnpatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesUnpatched = new WeakHashMap();
}
Map<String,byte[]> jarEntriesPatched;
if(zipIn != null) {
System.out.println("Loading files from '" + zipIn.getName() + "'...");
try(FileInputStream is = new FileInputStream(zipIn)) {
jarEntriesPatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesPatched = new WeakHashMap();
}
System.out.println("Patching files in '" + zipIn.getName() + "'...");
final Map<String,byte[]> jarEntries = new HashMap();
jarEntries.putAll(jarEntriesUnpatched);
jarEntries.putAll(jarEntriesPatched);
DiffSet diffs = new DiffSet();
int totalLoad = diffs.loadFolder(patchesIn, useECR, useECR ? new DiffSet.SourceProvider() {
@Override
public List<String> getSource(String filename) throws IOException {
byte[] etr = jarEntries.get(filename);
if(etr == null) {
throw new FileNotFoundException("Could not find source for: " + filename);
}
return Lines.linesList(new String(etr, StandardCharsets.UTF_8));
}
} : null);
System.out.println(" loaded " + totalLoad + " patch files from the repo");
System.out.println(" patching files...");
System.out.print(" ");
int cnt = 0;
int crtCnt = 0;
int delCnt = 0;
int repCnt = 0;
int pthCnt = 0;
try(ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(zipOut))) {
jarOut.setLevel(compress ? 5 : 0);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
String nm;
for(Entry<String,byte[]> et : jarEntries.entrySet()) {
nm = et.getKey();
if(!nm.startsWith("META-INF")) {
Object op = diffs.diffs.get(nm);
if(op != null) {
if(op instanceof DiffSet.DeleteFunction) {
++delCnt;
continue;
}else if(op instanceof DiffSet.ReplaceFunction) {
jarOut.putNextEntry(new ZipEntry(nm));
IOUtils.write(((DiffSet.ReplaceFunction)op).file, jarOut);
++repCnt;
}else if(op instanceof Patch<?>) {
jarOut.putNextEntry(new ZipEntry(nm));
List<String> lines = Lines.linesList(new String(et.getValue(), "UTF-8"));
try {
lines = ((Patch<String>)op).applyTo(lines);
}catch(PatchFailedException ptch) {
throw new IOException("Could not patch file \"" + nm + "\"!", ptch);
}
IOUtils.writeLines(lines, null, jarOut, "UTF-8");
++pthCnt;
}else {
// ?
}
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}else {
if(jarEntriesPatched.containsKey(nm)) {
jarOut.putNextEntry(new ZipEntry(nm));
IOUtils.write(et.getValue(), jarOut);
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}
}
}
}
for(Entry<String,byte[]> etr : diffs.recreate.entrySet()) {
jarOut.putNextEntry(new ZipEntry(etr.getKey()));
IOUtils.write(etr.getValue(), jarOut);
++crtCnt;
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}
}
System.out.println();
System.out.println("Patched " + pthCnt + " files");
System.out.println("Restored " + crtCnt + " files");
System.out.println("Replaced " + repCnt + " files");
System.out.println("Deleted " + delCnt + " files");
System.out.println();
}
}

View File

@ -0,0 +1,148 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class DiffSet {
public static class DeleteFunction {
private DeleteFunction() {
}
}
public static class ReplaceFunction {
public final byte[] file;
private ReplaceFunction(byte[] file) {
this.file = file;
}
}
public static final DeleteFunction deleteFunction = new DeleteFunction();
public final Map<String,Object> diffs;
public final Map<String,byte[]> recreate;
public DiffSet() {
diffs = new HashMap();
recreate = new HashMap();
}
private static final Pattern editPattern = Pattern.compile(".*\\.edit(\\.[^\\.\\/\\\\]+)?$");
private static final Pattern replacePattern = Pattern.compile(".*\\.replace(\\.[^\\.\\/\\\\]+)?$");
private static final Pattern deletePattern = Pattern.compile(".*\\.delete(\\.[^\\.\\/\\\\]+)?$");
private static final Pattern recreatePattern = Pattern.compile(".*\\.recreate(\\.[^\\.\\/\\\\]+)?$");
public int loadFolder(File pathIn, boolean useECR, SourceProvider ecrContextProvider) throws IOException {
String baseAbsolutePath = pathIn.getAbsolutePath();
int total = 0;
File del = new File(pathIn, "delete.txt");
if(del.isFile()) {
Collection<String> cl = FileUtils.readLines(del, "UTF-8");
for(String s : cl) {
s = s.trim();
s = s.replace('\\', '/');
if(!s.startsWith("#")) {
if(s.startsWith("/")) {
s = s.substring(1);
}
diffs.put(s, deleteFunction);
}
}
}
Collection<File> fl = FileUtils.listFiles(pathIn, null, true);
Iterator<File> fi = fl.iterator();
while(fi.hasNext()) {
File f = fi.next();
String fName = f.getAbsolutePath().replace(baseAbsolutePath, "").replace('\\', '/');
if(fName.startsWith("/")) {
fName = fName.substring(1);
}
if(editPattern.matcher(fName).matches()) {
try {
String nm = removeExt(fName, "edit");
Patch<String> pth;
if(useECR) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8))) {
pth = EaglerContextRedacted.readContextRestricted(ecrContextProvider.getSource(nm), reader);
}
}else {
List<String> phile = FileUtils.readLines(f, "UTF-8");
pth = UnifiedDiffUtils.parseUnifiedDiff(phile);
}
if(pth == null) {
throw new IOException("Invalid DIFF file!");
}
diffs.put(nm, pth);
++total;
}catch(Throwable ex) {
System.err.println("ERROR: could not read '" + fName + "'!");
}
}else if(replacePattern.matcher(fName).matches()) {
try {
diffs.put(removeExt(fName, "replace"), new ReplaceFunction(FileUtils.readFileToByteArray(f)));
++total;
}catch(Throwable ex) {
System.err.println("ERROR: could not read '" + fName + "'!");
}
}else if(deletePattern.matcher(fName).matches()) {
diffs.put(removeExt(fName, "delete"), deleteFunction);
++total;
}else if(recreatePattern.matcher(fName).matches()) {
try {
String str = removeExt(fName, "recreate");
recreate.put(str, FileUtils.readFileToByteArray(f));
diffs.remove(str);
++total;
}catch(Throwable ex) {
System.err.println("ERROR: could not read '" + fName + "'!");
}
}
}
return total;
}
private static String removeExt(String fn, String ext) {
int end = fn.lastIndexOf("." + ext);
if(end != -1) {
return fn.substring(0, end) + fn.substring(end + ext.length() + 1, fn.length());
}else {
return fn;
}
}
public static interface SourceProvider {
List<String> getSource(String filename) throws IOException;
}
}

View File

@ -0,0 +1,256 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.ChangeDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.DeleteDelta;
import com.github.difflib.patch.DeltaType;
import com.github.difflib.patch.InsertDelta;
import com.github.difflib.patch.Patch;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EaglerContextRedacted {
public static void writeContextRedacted(Patch<String> patch, PrintWriter output) {
Date theDate = new Date();
output.println();
output.println("# Eagler Context Redacted Diff");
output.println("# Copyright (c) " + (new SimpleDateFormat("yyyy")).format(theDate) + " lax1dude. All rights reserved.");
output.println();
output.println("# Version: 1.0");
output.println("# Author: lax1dude");
output.println();
List<AbstractDelta<String>> deltas = patch.getDeltas();
delta_itr: for(int i = 0, l = deltas.size(); i < l; ++i) {
AbstractDelta<String> delta = deltas.get(i);
DeltaType type = delta.getType();
String blockType;
String blockPrefix;
switch(type) {
case CHANGE:
blockType = "> CHANGE";
blockPrefix = "~ ";
break;
case DELETE:
blockType = "> DELETE";
blockPrefix = "- ";
break;
case EQUAL:
continue delta_itr;
case INSERT:
blockType = "> INSERT";
blockPrefix = "+ ";
break;
default:
throw new IllegalArgumentException("Invalid type " + type + " for delta " + i);
}
Chunk<String> source = delta.getSource();
int sourcePos = source.getPosition();
int sourceLen = source.getLines().size();
Chunk<String> target = delta.getTarget();
int targetPos = target.getPosition();
List<String> linesToWrite = target.getLines();
int targetLen = linesToWrite.size();
output.println(blockType + " " + targetPos + (targetLen > 0 ? " : " + (targetPos + targetLen) : "") + " @ "
+ sourcePos + (sourceLen > 0 ? " : " + (sourcePos + sourceLen) : ""));
output.println();
if(targetLen > 0) {
for(int j = 0, ll = linesToWrite.size(); j < ll; ++j) {
output.println(blockPrefix + linesToWrite.get(j));
}
output.println();
}
}
output.println("> EOF");
}
public static Patch<String> readContextRestricted(List<String> context, BufferedReader reader) throws IOException {
Patch<String> newPatch = new Patch();
DeltaType currentDeltaType = null;
int sourceStart = 0;
int sourceLen = 0;
int targetStart = 0;
int targetLen = 0;
List<String> targetLines = null;
String line;
readLinesLoop: while((line = reader.readLine()) != null) {
if(line.length() < 2) {
continue;
}
if(line.charAt(1) != ' ') {
throw new IOException("Unknown line type: " + line.substring(0, 2));
}
char lineType = line.charAt(0);
String value = line.substring(2);
switch(lineType) {
case '#':
int idx = value.indexOf(':');
if(idx > 0) {
String k = value.substring(0, idx).trim().toLowerCase();
if(k.equals("version")) {
String v = value.substring(idx + 1).trim();
if(!v.equals("1.0")) {
throw new IOException("Unsupported format version: " + v);
}
}
}
break;
case '>':
String[] split = value.trim().split("[\\s]+");
if(split.length == 1 && split[0].equals("EOF")) {
break readLinesLoop;
}
if(split.length < 4 ||
!((split[2].equals("@") && (split.length == 4 || (split.length == 6 && split[4].equals(":")))) ||
(split[2].equals(":") && ((split.length == 6 && split[4].equals("@")) || (split.length == 8 && split[4].equals("@") && split[6].equals(":")))))) {
throw new IOException("Invalid block: [ " + String.join(" ", split) + " ]");
}
if(currentDeltaType != null) {
newPatch.addDelta(makeDelta(currentDeltaType, sourceStart, sourceLen, targetStart, targetLen, context, targetLines));
}
switch(split[0]) {
case "CHANGE":
currentDeltaType = DeltaType.CHANGE;
break;
case "DELETE":
currentDeltaType = DeltaType.DELETE;
break;
case "INSERT":
currentDeltaType = DeltaType.INSERT;
break;
default:
throw new IOException("Unknown line block: " + split[0]);
}
targetLines = null;
targetStart = parseInt(split[1]);
if(split[2].equals(":")) {
targetLen = parseInt(split[3]) - targetStart;
sourceStart = parseInt(split[5]);
if(split.length == 8) {
sourceLen = parseInt(split[7]) - sourceStart;
}else {
sourceLen = 0;
}
}else {
targetLen = 0;
sourceStart = parseInt(split[3]);
if(split.length == 6) {
sourceLen = parseInt(split[5]) - sourceStart;
}else {
sourceLen = 0;
}
}
break;
case '~':
if(currentDeltaType != DeltaType.CHANGE) {
throw new IOException("Read an unexpected CHANGE line in a " + currentDeltaType + " block: " + line);
}else {
if(targetLines == null) targetLines = new ArrayList();
targetLines.add(value);
}
break;
case '-':
if(currentDeltaType != DeltaType.DELETE) {
throw new IOException("Read an unexpected DELETE line in a " + currentDeltaType + " block: " + line);
}else {
if(targetLines == null) targetLines = new ArrayList();
targetLines.add(value);
}
break;
case '+':
if(currentDeltaType != DeltaType.INSERT) {
throw new IOException("Read an unexpected INSERT line in a " + currentDeltaType + " block: " + line);
}else {
if(targetLines == null) targetLines = new ArrayList();
targetLines.add(value);
}
break;
default:
throw new IOException("Unknown line type: " + lineType);
}
}
if(currentDeltaType != null) {
newPatch.addDelta(makeDelta(currentDeltaType, sourceStart, sourceLen, targetStart, targetLen, context, targetLines));
}
return newPatch;
}
private static int parseInt(String str) throws IOException {
try {
return Integer.parseInt(str);
}catch(NumberFormatException ex) {
throw new IOException("Value is not a valid integer: \"" + str + "\"");
}
}
private static AbstractDelta<String> makeDelta(DeltaType deltaType, int sourceStart, int sourceLen,
int targetStart, int targetLen, List<String> context, List<String> targetLines) throws IOException {
List<String> sourceLines = new ArrayList(sourceLen);
for(int i = 0; i < sourceLen; ++i) {
sourceLines.add(context.get(sourceStart + i));
}
if(targetLines == null) {
targetLines = new ArrayList(0);
}
if(targetLen != targetLines.size()) {
throw new IOException("" + deltaType + " block at sourceStart " + sourceStart + " is " + targetLen
+ " lines long but only " + targetLines.size() + " lines were read!");
}
switch(deltaType) {
case CHANGE:
return new ChangeDelta(new Chunk(sourceStart, sourceLines), new Chunk(targetStart, targetLines));
case DELETE:
return new DeleteDelta(new Chunk(sourceStart, sourceLines), new Chunk(targetStart, targetLines));
case INSERT:
return new InsertDelta(new Chunk(sourceStart, sourceLines), new Chunk(targetStart, targetLines));
default:
throw new IllegalArgumentException("Invalid delta type: " + deltaType);
}
}
}

View File

@ -0,0 +1,47 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.IOUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class JARMemoryCache {
public static Map<String,byte[]> loadJAR(InputStream is) throws IOException {
Map<String,byte[]> ret = new HashMap();
ZipInputStream isz = new ZipInputStream(is);
ZipEntry et;
while((et = isz.getNextEntry()) != null) {
if(!et.isDirectory()) {
String n = et.getName();
if(n.startsWith("/")) {
n = n.substring(1);
}
if(!n.startsWith("META-INF")) {
byte[] data = IOUtils.toByteArray(isz);
ret.put(n, data);
}
}
}
return ret;
}
}

View File

@ -0,0 +1,32 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class Lines {
public static final Pattern splitPattern = Pattern.compile("(\\r\\n|\\n|\\r)");
public static String[] linesArray(String input) {
return splitPattern.split(input);
}
public static List<String> linesList(String input) {
return Arrays.asList(splitPattern.split(input));
}
}

View File

@ -0,0 +1,529 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import com.github.difflib.DiffUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InsertJavaDoc;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.SetupWorkspace;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class MergePullRequest {
public static boolean mergeTask() {
try {
return mergeTask0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'merge'!");
t.printStackTrace();
return false;
}
}
private static boolean mergeTask0() throws Throwable {
File pullRequestDir = new File("pullrequest");
if(!pullRequestDir.isDirectory() || FileUtils.isEmptyDirectory(pullRequestDir)) {
System.err.println("ERROR: the 'pullrequest' directory does not exist or is empty, aborting merge because there's nothing to merge");
return false;
}
if((new File(pullRequestDir, "merged.txt")).exists()) {
System.err.println("ERROR: the 'pullrequest' directory has already been merged, aborting merge because there's nothing to merge");
System.err.println("To override, delete 'merged.txt' from the folder.");
return false;
}
System.out.println();
System.out.println("Warning: running 'merge' is a command only intended to be used");
System.out.println("by the repository's owner, it will perminantly incorporate all");
System.out.println("changes in the 'pullrequest' directory into this repository's");
System.out.println("patch file directory!");
System.out.println();
System.out.println("Doing so will make it impossible to reliably create any future");
System.out.println("pull requests back to this project's main repository, unless the");
System.out.println("main repository has merged the same pull request into it's patch");
System.out.println("file directory too.");
System.out.println();
System.out.println("Back up the current state of the patch file directory in a local");
System.out.println("commit or branch to allow you to undo any unintentional changes");
System.out.println("made to the directory as a result of running this command.");
System.out.println();
System.out.print("Do you really want to do this? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("OKAY THANK GOD, crisis averted!");
System.out.println();
System.out.println("Thank the author of this tool kindly for providing this check.");
return true;
}
System.out.println();
System.out.println("Warning: close all programs that may have files or folders open");
System.out.println("in the repository or the merge could fail catastrophically");
System.out.println();
System.out.println("This folder: " + (new File(".")).getAbsolutePath());
System.out.println();
System.out.println("Check for any file explorer windows displaying the contents of a");
System.out.println("file or folder in this directory.");
System.out.println();
System.out.println("Close any programs with files open someplace in this folder.");
System.out.println();
System.out.println("If merging fails, revert all changes in this directory with git");
System.out.println("or a backup, re-run 'init', then run 'pullrequest' and 'merge'");
System.out.println();
System.out.print("Did you close everything? [Y/n]: ");
ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("OKAY THANK GOD, crisis averted!");
System.out.println();
System.out.println("Thank the author of this tool kindly for providing this check.");
return true;
}
System.out.println();
File temporaryDirectory = EaglerBuildToolsConfig.getTemporaryDirectory();
System.out.println();
File pullRequestToSrc = new File(pullRequestDir, "source");
File pullRequestToRes = new File(pullRequestDir, "resources");
boolean prSrcExist = pullRequestToSrc.isDirectory() && !FileUtils.isEmptyDirectory(pullRequestToSrc);
boolean prResExist = pullRequestToRes.isDirectory() && !FileUtils.isEmptyDirectory(pullRequestToRes);
if(!prSrcExist && !prResExist) {
System.err.println("ERROR: the 'pullrequest' directory does not exist or is empty, aborting merge because there's nothing to merge");
return false;
}
if(prSrcExist) {
File tmpOriginalUnpatched = new File(temporaryDirectory, "MinecraftSrc/minecraft_src.jar");
if(!tmpOriginalUnpatched.isFile()) {
System.err.println("ERROR: file '" + tmpOriginalUnpatched.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpOriginal = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_patch.jar");
if(!tmpOriginal.isFile()) {
System.err.println("ERROR: file '" + tmpOriginal.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpMerged = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_merge.jar");
File tmpMergedDiffs = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_merge_diffs.zip");
System.out.println("Applying pull request to '" + tmpOriginal.getName() + "'...");
System.out.println();
ApplyPatchesToZip.applyPatches(tmpOriginal, tmpOriginalUnpatched, pullRequestToSrc, tmpMerged, true, false);
try {
createMergeDiffs(tmpMerged, tmpOriginalUnpatched, tmpMergedDiffs);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
System.out.println();
File patchOut = new File("./patches/minecraft");
File patchTmpOut = new File("./patches.bak/minecraft");
if(patchOut.exists()) {
System.out.println("Backing up '" + patchOut.getAbsolutePath() + "'...");
try {
FileUtils.deleteDirectory(patchTmpOut);
FileUtils.moveDirectory(patchOut, patchTmpOut);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
}
FileUtils.copyFile(new File(patchTmpOut, "output_license.txt"), new File(patchOut, "output_license.txt"));
System.out.println("Extracting '" + tmpMergedDiffs + "' to 'patches/minecraft'...");
int cnt = SetupWorkspace.extractJarTo(tmpMergedDiffs, patchOut);
if(!tmpMergedDiffs.delete()) {
System.err.println("ERROR: could not delete '" + tmpMergedDiffs.getName() + "'!");
}
System.out.println("Wrote " + cnt + " files.");
System.out.println("Copying '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'...");
if((tmpOriginal.exists() && !tmpOriginal.delete()) || !tmpMerged.renameTo(tmpOriginal)) {
System.err.println("ERROR: could not copy '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'!");
System.err.println("Run the 'init' task again before proceeding");
tmpOriginal.delete();
}else {
File javadocOut = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_javadoc.jar");
CSVMappings comments = new CSVMappings();
if(!InsertJavaDoc.processSource(tmpOriginal, javadocOut, new File(temporaryDirectory, "ModCoderPack"), comments)) {
System.err.println();
System.err.println("ERROR: Could not create javadoc!");
return false;
}
}
if(tmpMerged.exists()) {
tmpMerged.delete();
}
System.out.println("Deleting backup folder...");
try {
FileUtils.deleteDirectory(patchTmpOut);
}catch(Throwable t) {
System.err.println("ERROR: could not delete 'patches.bak/minecraft'!");
System.err.println(t.toString());
}
System.out.println();
}
if(prResExist) {
File tmpOriginalUnpatched = new File(temporaryDirectory, "MinecraftSrc/minecraft_res.jar");
if(!tmpOriginalUnpatched.isFile()) {
System.err.println("ERROR: file '" + tmpOriginalUnpatched.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpOriginal = new File(temporaryDirectory, "MinecraftSrc/minecraft_res_patch.jar");
if(!tmpOriginal.isFile()) {
System.err.println("ERROR: file '" + tmpOriginal.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpMerged = new File(temporaryDirectory, "MinecraftSrc/minecraft_res_merge.jar");
File tmpMergedDiffs = new File(temporaryDirectory, "MinecraftSrc/minecraft_res_merge_diffs.zip");
System.out.println("Applying pull request to '" + tmpOriginal.getName() + "'...");
System.out.println();
ApplyPatchesToZip.applyPatches(tmpOriginal, tmpOriginalUnpatched, pullRequestToRes, tmpMerged, true, false);
try {
createMergeDiffs(tmpMerged, tmpOriginalUnpatched, tmpMergedDiffs);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
System.out.println();
File patchOut = new File("./patches/resources");
File patchTmpOut = new File("./patches.bak/resources");
if(patchOut.exists()) {
System.out.println("Backing up '" + patchOut.getAbsolutePath() + "'...");
try {
FileUtils.deleteDirectory(patchTmpOut);
FileUtils.moveDirectory(patchOut, patchTmpOut);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
}
System.out.println("Extracting '" + tmpMergedDiffs + "' to 'patches/resources'...");
int cnt = SetupWorkspace.extractJarTo(tmpMergedDiffs, patchOut);
if(!tmpMergedDiffs.delete()) {
System.err.println("ERROR: could not delete '" + tmpMergedDiffs.getName() + "'!");
}
System.out.println("Wrote " + cnt + " files.");
System.out.println("Copying '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'...");
if((tmpOriginal.exists() && !tmpOriginal.delete()) || !tmpMerged.renameTo(tmpOriginal)) {
System.err.println("ERROR: could not copy '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'!");
System.err.println("Run the 'init' task again before proceeding");
tmpOriginal.delete();
}
if(tmpMerged.exists()) {
tmpMerged.delete();
}
System.out.println("Deleting backup folder...");
try {
FileUtils.deleteDirectory(patchTmpOut);
}catch(Throwable t) {
System.err.println("ERROR: could not delete 'patches.bak/resources'!");
System.err.println(t.getMessage());
}
System.out.println();
}
(new File("./patches.bak")).delete();
System.out.println("Successfully merged pullrequest directory!");
try {
SimpleDateFormat fmt1 = new SimpleDateFormat("MM-dd-yy");
SimpleDateFormat fmt2 = new SimpleDateFormat("kk:mm:ss");
Date dt = new Date();
FileUtils.writeStringToFile(new File(pullRequestDir, "merged.txt"), "This pullrequest was merged on " +
fmt1.format(new Date()) + " at " + fmt2.format(dt) + ".", "UTF-8");
}catch(IOException ex) {
System.err.println("ERROR: could not write 'merged.txt' in pullrequest directory!");
System.err.println("Creating a file called 'merged.txt' is important to tell buildtools that the");
System.err.println("existing pullrequest has already been merged! Do not try to merge it again!");
}
System.out.println("Backing up to 'pullrequest_merged_backup'...");
String pth = pullRequestDir.getAbsolutePath();
if(pth.endsWith("/") || pth.endsWith("\\")) {
pth = pth.substring(0, pth.length() - 1);
}
File m0 = new File(pth + "_merged_backup");
if(m0.exists() && !FileUtils.deleteQuietly(m0)) {
System.err.println("Could not delete old backup!");
m0 = new File(pth + "_merged_backup1");
if(m0.exists() && !FileUtils.deleteQuietly(m0)) {
System.err.println("Could not delete 2nd old backup!");
return true;
}
}
try {
FileUtils.moveDirectory(pullRequestDir, m0);
}catch(IOException ex) {
System.err.println("Could not create backup!");
}
return true;
}
private static void createMergeDiffs(File tmpMerged, File tmpOriginalUnpatched, File tmpMergedDiffs) throws Throwable {
System.out.println("Creating patches from '" + tmpMerged.getName() + "'...");
System.out.println("Loading files from '" + tmpOriginalUnpatched.getName() + "'...");
Map<String, byte[]> memoryCacheUnpatched;
try(InputStream is = new FileInputStream(tmpOriginalUnpatched)) {
memoryCacheUnpatched = JARMemoryCache.loadJAR(is);
}
if(memoryCacheUnpatched == null) {
throw new IOException("Failed to load JAR into memory: '" + tmpOriginalUnpatched.getName());
}
System.out.println("Loading files from '" + tmpMerged.getName() + "'...");
Map<String, byte[]> memoryCacheMerged;
try(InputStream is = new FileInputStream(tmpMerged)) {
memoryCacheMerged = JARMemoryCache.loadJAR(is);
}
if(memoryCacheMerged == null) {
throw new IOException("Failed to load JAR into memory: '" + tmpMerged.getName());
}
Set<String> deleteList = new HashSet();
deleteList.addAll(memoryCacheUnpatched.keySet());
System.out.println("Generating patch files..");
System.out.println("(Writing to: " + tmpMergedDiffs.getName() + ")");
System.out.println("(this may take a while)");
System.out.print(" ");
int cnt = 0;
try(ZipOutputStream mgd = new ZipOutputStream(new FileOutputStream(tmpMergedDiffs))) {
mgd.setLevel(5);
for(Entry<String,byte[]> met : memoryCacheMerged.entrySet()) {
String n = met.getKey();
byte[] orig = memoryCacheUnpatched.get(n);
if(orig == null) {
System.err.println("Error: tried to patch file '" + n + "' that doesn't exist in the minecraft source");
continue;
}
deleteList.remove(n);
if(writeDiff(orig, met.getValue(), n, mgd)) {
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}
}
System.out.println();
System.out.println("Wrote " + cnt + " patch files.");
mgd.putNextEntry(new ZipEntry("delete.txt"));
PrintWriter delWriter = new PrintWriter(mgd);
delWriter.println("# " + deleteList.size() + " files to delete:");
for(String s : deleteList) {
delWriter.println(s);
}
delWriter.flush();
System.out.println("Wrote " + deleteList.size() + " deletes.");
}
}
private static boolean writeDiff(byte[] old, byte[] _new, String outName, ZipOutputStream output) throws IOException {
if(Arrays.equals(old, _new)) {
return false;
}
String oldStr = toStringIfValid(old);
String newStr = oldStr == null ? null : toStringIfValid(_new);
if(oldStr == null || newStr == null) {
output.putNextEntry(new ZipEntry(makeName(outName, "replace")));
IOUtils.write(_new, output);
return true;
}else {
List<String> oldLines = Lines.linesList(oldStr);
List<String> newLines = Lines.linesList(newStr);
Patch<String> deltas = DiffUtils.diff(oldLines, newLines);
// List<String> diffFile = UnifiedDiffUtils.generateUnifiedDiff(outName, outName, oldLines, deltas, ApplyPatchesToZip.patchContextLength);
//
// if(diffFile.size() == 0) {
// return false;
// }
//
// output.putNextEntry(new ZipEntry(makeName(outName, "edit")));
// PrintWriter foutStream = new PrintWriter(output);
// for(int i = 0, l = diffFile.size(); i < l; ++i) {
// foutStream.println(diffFile.get(i));
// }
// foutStream.flush();
output.putNextEntry(new ZipEntry(makeName(outName, "edit")));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"));
EaglerContextRedacted.writeContextRedacted(deltas, writer);
writer.flush();
return true;
}
}
private static String makeName(String input, String type) {
int lastSlash = input.lastIndexOf('/');
int lastDot = input.lastIndexOf('.');
if(lastDot > lastSlash + 1) {
return input.substring(0, lastDot) + "." + type + input.substring(lastDot);
}else {
return input + "." + type;
}
}
private static final CharsetDecoder utf8Decoder = StandardCharsets.UTF_8.newDecoder();
private static String toStringIfValid(byte[] in) {
ByteBuffer inn = ByteBuffer.wrap(in);
CharBuffer cb;
try {
cb = utf8Decoder.decode(inn);
}catch(Throwable t) {
return null;
}
return cb.toString();
}
public static boolean mergeDirect() {
try {
return mergeDirect0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'merge_direct'!");
t.printStackTrace();
return false;
}
}
private static boolean mergeDirect0() throws Throwable {
if(!PullRequestTask.pullRequest()) {
System.err.println();
System.err.println("Error: could not create merge_direct pull request!");
return false;
}
try {
if(!mergeTask0()) {
System.err.println();
System.err.println("Exception encountered while running task 'merge_direct'!");
return false;
}
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'merge_direct'!");
t.printStackTrace();
return false;
}
return true;
}
}

View File

@ -0,0 +1,426 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.zip.CRC32;
import org.apache.commons.io.FileUtils;
import com.github.difflib.DiffUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.formatter.EclipseFormatter;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InsertJavaDoc;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class PullRequestTask {
public static boolean pullRequest() {
try {
return pullRequest0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'pullrequest'!");
t.printStackTrace();
return false;
}
}
private static boolean pullRequest0() throws Throwable {
File originalUnpatchedSourceMainJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src.jar");
File originalSourceMainJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src_patch.jar");
File minecraftJavadocTmp = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src_javadoc.jar");
File originalSourceMain = new File(EaglerBuildTools.repositoryRoot, "sources/main/java");
File originalSourceTeaVM = new File(EaglerBuildTools.repositoryRoot, "sources/teavm/java");
File originalSourceLWJGL = new File(EaglerBuildTools.repositoryRoot, "sources/lwjgl/java");
File originalUnpatchedSourceResourcesJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_res.jar");
File originalSourceResourcesJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_res_patch.jar");
File originalSourceResources = new File(EaglerBuildTools.repositoryRoot, "sources/resources");
File diffFromMain = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/main/java");
File diffFromTeaVM = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm/java");
File diffFromLWJGL = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/lwjgl/java");
File diffFromResources = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "desktopRuntime/resources");
File pullRequestTo = new File(EaglerBuildTools.repositoryRoot, "pullrequest");
boolean prExist = pullRequestTo.exists();
if(prExist && !(pullRequestTo.isDirectory() && pullRequestTo.list().length == 0)) {
System.out.println();
System.out.print("Warning: The 'pullrequest' folder already exists in your repository. Overwrite? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("The pull request was cancelled.");
return true;
}else {
try {
FileUtils.deleteDirectory(pullRequestTo);
prExist = false;
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + pullRequestTo.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
if(!prExist && !pullRequestTo.mkdirs()) {
System.err.println("ERROR: Could not create folder \"" + pullRequestTo.getAbsolutePath() + "\"!");
}
File pullRequestToMain = new File(pullRequestTo, "source");
File pullRequestToResources = new File(pullRequestTo, "resources");
boolean flag = false;
int i = copyAllModified(diffFromTeaVM, originalSourceTeaVM);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /src/teavm/java/");
i = copyAllModified(diffFromLWJGL, originalSourceLWJGL);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /src/lwjgl/java/");
i = createDiffFiles(originalSourceMain, minecraftJavadocTmp, originalUnpatchedSourceMainJar,
originalSourceMainJar, diffFromMain, pullRequestToMain, true);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /src/main/java/");
i = createDiffFiles(originalSourceResources, originalSourceResourcesJar, originalUnpatchedSourceResourcesJar,
null, diffFromResources, pullRequestToResources, false);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /desktopRuntime/resources/");
if(!flag) {
System.out.println("ERROR: No modified files were found!");
if(pullRequestTo.exists()) {
pullRequestTo.delete();
}
}
return true;
}
private static int createDiffFiles(File folderOriginal, File jarOriginal, File jarOriginalUnpatched, File originalJarNoJavadoc,
File folderEdited, File folderOut, boolean isJava) throws Throwable {
if(!folderEdited.isDirectory()) {
return 0;
}
boolean createdFolderOut = folderOut.isDirectory();
int cnt = 0;
Collection<File> workspaceFiles = FileUtils.listFiles(folderEdited, null, true);
Map<String,byte[]> jarEntriesUnpatched;
if(jarOriginalUnpatched != null) {
System.out.println("Loading files from '" + jarOriginalUnpatched.getName() + "'...");
try(FileInputStream is = new FileInputStream(jarOriginalUnpatched)) {
jarEntriesUnpatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesUnpatched = new WeakHashMap();
}
Map<String,byte[]> jarEntriesPatched;
if(jarOriginal != null) {
System.out.println("Loading files from '" + jarOriginal.getName() + "'...");
try(FileInputStream is = new FileInputStream(jarOriginal)) {
jarEntriesPatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesPatched = new WeakHashMap();
}
Map<String,byte[]> jarEntries = new HashMap();
jarEntries.putAll(jarEntriesUnpatched);
jarEntries.putAll(jarEntriesPatched);
Map<String,byte[]> jarEntriesNoJavadoc;
if(originalJarNoJavadoc != null) {
System.out.println("Loading files from '" + originalJarNoJavadoc.getName() + "'...");
try(FileInputStream is = new FileInputStream(originalJarNoJavadoc)) {
jarEntriesNoJavadoc = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesNoJavadoc = new WeakHashMap();
}
System.out.println("Comparing...");
System.out.println("(this may take a while)");
String editedPrefix = folderEdited.getAbsolutePath();
Set<String> filesReplaced = new HashSet();
for(File wf : workspaceFiles) {
String newPath = wf.getAbsolutePath().replace(editedPrefix, "");
if(newPath.indexOf('\\') != -1) {
newPath = newPath.replace('\\', '/');
}
if(newPath.startsWith("/")) {
newPath = newPath.substring(1);
}
File orig = new File(folderOriginal, newPath);
byte[] jarData = null;
boolean replacedFileExists = orig.exists();
if(replacedFileExists) {
filesReplaced.add(newPath);
if(copyFileIfChanged(wf, orig)) {
++cnt;
}
}else if((jarData = jarEntries.get(newPath)) != null) {
filesReplaced.add(newPath);
byte [] o = jarData;
byte [] n = FileUtils.readFileToByteArray(wf);
boolean changed = false;
if(o.length != n.length) {
if(!createdFolderOut) {
if(!folderOut.mkdirs()) {
throw new IOException("Could not create folder: \"" + folderOut.getAbsolutePath() + "\"!");
}
createdFolderOut = true;
}
String noJavaDocString = null;
byte[] noJavaDoc = jarEntriesNoJavadoc.get(newPath);
if(noJavaDoc != null) {
noJavaDocString = new String(noJavaDoc, StandardCharsets.UTF_8);
}
if(writeDiff(o, n, folderOut, newPath, isJava, noJavaDocString)) {
changed = true;
++cnt;
}
}else {
for(int i = 0; i < o.length; ++i) {
if(o[i] != n[i]) {
if(!createdFolderOut) {
if(!folderOut.mkdirs()) {
throw new IOException("Could not create folder: \"" + folderOut.getAbsolutePath() + "\"!");
}
createdFolderOut = true;
}
String noJavaDocString = null;
byte[] noJavaDoc = jarEntriesNoJavadoc.get(newPath);
if(noJavaDoc != null) {
noJavaDocString = new String(noJavaDoc, StandardCharsets.UTF_8);
}
if(writeDiff(o, n, folderOut, newPath, isJava, noJavaDocString)) {
changed = true;
++cnt;
}
break;
}
}
}
if(!changed && !jarEntriesPatched.containsKey(newPath)) {
FileUtils.writeByteArrayToFile(new File(folderOut, makeName(newPath, "recreate")), jarData);
++cnt;
}
}else {
filesReplaced.add(newPath);
FileUtils.copyFile(wf, orig);
++cnt;
}
}
if(jarEntriesPatched.size() > 0) {
for(Entry<String,byte[]> etr : jarEntriesPatched.entrySet()) {
if(filesReplaced.contains(etr.getKey())) {
continue;
}
if(!(new File(folderEdited, etr.getKey())).exists()) {
if(!createdFolderOut) {
if(!folderOut.mkdirs()) {
throw new IOException("Could not create folder: \"" + folderOut.getAbsolutePath() + "\"!");
}
createdFolderOut = true;
}
FileUtils.writeStringToFile(new File(folderOut, makeName(etr.getKey(), "delete")),
"#hash: " + getCRC32(etr.getValue()), "UTF-8");
++cnt;
}
}
}
return cnt;
}
private static boolean writeDiff(byte[] old, byte[] _new, File outDir, String outName, boolean isJava, String javaNotJavadoc) throws IOException {
String oldStr = toStringIfValid(old);
String newStr = oldStr == null ? null : toStringIfValid(_new);
if(oldStr == null || newStr == null) {
FileUtils.writeByteArrayToFile(new File(outDir, makeName(outName, "replace")), _new);
}else {
if(javaNotJavadoc != null) {
oldStr = javaNotJavadoc;
}
//oldStr = stripJavadocAndFormat(oldStr);
newStr = stripJavadocAndFormat(newStr);
List<String> oldLines = Lines.linesList(oldStr);
List<String> newLines = Lines.linesList(newStr);
Patch<String> deltas = DiffUtils.diff(oldLines, newLines);
List<String> diffFile = UnifiedDiffUtils.generateUnifiedDiff(outName, outName, oldLines, deltas, ApplyPatchesToZip.patchContextLength);
if(diffFile.size() == 0) {
return false;
}
File fout = new File(outDir, makeName(outName, "edit"));
File p = fout.getParentFile();
if(!p.isDirectory()) {
if(!p.mkdirs()) {
throw new IOException("Failed to create directory \"" + p.getAbsolutePath() + "\"!");
}
}
try(PrintWriter foutStream = new PrintWriter(new FileWriterUTF(fout))) {
for(int i = 0, l = diffFile.size(); i < l; ++i) {
foutStream.println(diffFile.get(i));
}
}
}
return true;
}
private static String stripJavadocAndFormat(String input) {
input = InsertJavaDoc.stripDocForDiff(input);
input = EclipseFormatter.processSource(input, System.lineSeparator());
return input;
}
private static int copyAllModified(File inDir, File outDir) throws IOException {
if(!inDir.isDirectory()) {
return 0;
}
int cnt = 0;
Collection<File> workspaceFiles = FileUtils.listFiles(inDir, null, true);
String editedPrefix = inDir.getAbsolutePath();
for(File wf : workspaceFiles) {
String newPath = wf.getAbsolutePath().replace(editedPrefix, "");
if(newPath.indexOf('\\') != -1) {
newPath = newPath.replace('\\', '/');
}
if(newPath.startsWith("/")) {
newPath = newPath.substring(1);
}
File orig = new File(outDir, newPath);
if(copyFileIfChanged(wf, orig)) {
++cnt;
}
}
return cnt;
}
private static String makeName(String input, String type) {
int lastSlash = input.lastIndexOf('/');
int lastDot = input.lastIndexOf('.');
if(lastDot > lastSlash + 1) {
return input.substring(0, lastDot) + "." + type + input.substring(lastDot);
}else {
return input + "." + type;
}
}
private static final CharsetDecoder utf8Decoder = StandardCharsets.UTF_8.newDecoder();
private static String toStringIfValid(byte[] in) {
ByteBuffer inn = ByteBuffer.wrap(in);
CharBuffer cb;
try {
cb = utf8Decoder.decode(inn);
}catch(Throwable t) {
return null;
}
return cb.toString();
}
private static final String hex = "0123456789ABCDEF";
private static String hex32(long in) {
char[] ret = new char[8];
for(int i = 7; i >= 0; --i) {
ret[i] = hex.charAt((int)((in >> (i << 2)) & 0xF));
}
return new String(ret);
}
private static String getCRC32(File in) throws IOException {
CRC32 crc = new CRC32();
crc.update(FileUtils.readFileToByteArray(in));
return hex32(crc.getValue());
}
private static String getCRC32(byte[] in) {
CRC32 crc = new CRC32();
crc.update(in);
return hex32(crc.getValue());
}
private static boolean checkCRC32(File in1, File in2) throws IOException {
CRC32 crc = new CRC32();
crc.update(FileUtils.readFileToByteArray(in1));
long v1 = crc.getValue();
crc.reset();
crc.update(FileUtils.readFileToByteArray(in2));
return v1 != crc.getValue();
}
private static boolean copyFileIfChanged(File in1, File in2) throws IOException {
if(!in2.exists()) {
FileUtils.copyFile(in1, in2);
return true;
}
if(in1.lastModified() == in2.lastModified()) {
return false;
}
CRC32 crc = new CRC32();
byte[] f1 = FileUtils.readFileToByteArray(in1);
crc.update(f1);
long v1 = crc.getValue();
crc.reset();
byte[] f2 = FileUtils.readFileToByteArray(in2);
crc.update(f2);
if(v1 != crc.getValue()) {
//System.out.println("changed: " + in1.getAbsolutePath());
FileUtils.writeByteArrayToFile(in2, f1);
return true;
}else {
return false;
}
}
}

View File

@ -0,0 +1,42 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.formatter;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter;
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.TextEdit;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EclipseFormatter {
private static final DefaultCodeFormatter formatter = new DefaultCodeFormatter(DefaultCodeFormatterOptions.getEclipseDefaultSettings());
public static String processSource(String input, String lineSeparator) {
try {
IDocument doc = new Document();
doc.set(input);
TextEdit edit = formatter.format(CodeFormatter.K_COMPILATION_UNIT |
CodeFormatter.F_INCLUDE_COMMENTS, input, 0, input.length(), 0, lineSeparator);
edit.apply(doc);
return doc.get();
}catch(Throwable t) {
System.err.println("Code formatting failed!");
t.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,130 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CSVMappings {
public final Map<String, Symbol> csvFieldsMappings = new HashMap();
public final Map<String, Symbol> csvMethodsMappings = new HashMap();
public final Map<String, Param> csvParamsMappings = new HashMap();
public final Map<String, Param[]> csvParamsForFunction = new HashMap();
public static class Symbol {
public final String name;
public final int mod;
public final String comment;
public Symbol(String name, int mod, String comment) {
this.name = name;
this.mod = mod;
this.comment = comment;
}
}
public static class Param {
public final String name;
public final int mod;
public Param(String name, int mod) {
this.name = name;
this.mod = mod;
}
}
public void loadMethodsFile(Reader reader) throws IOException {
loadSymbols(reader, csvMethodsMappings, "methods.csv");
}
public void loadFieldsFile(Reader reader) throws IOException {
loadSymbols(reader, csvFieldsMappings, "fields.csv");
}
private void loadSymbols(Reader reader, Map<String, Symbol> map, String debugFileName) throws IOException {
try {
CSVParser ps = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader);
Iterator<CSVRecord> rows = ps.iterator();
while(rows.hasNext()) {
CSVRecord rec = rows.next();
String srgName = rec.get("searge");
String deobfName = rec.get("name");
int mod = Integer.parseInt(rec.get("side"));
String comment = rec.get("desc");
map.put(srgName, new Symbol(deobfName, mod, comment));
}
System.out.println(" Loaded " + map.size() + " symbols from " + debugFileName);
}catch(Throwable t) {
t.printStackTrace();
throw new IOException("Invalid " + debugFileName + " file!");
}
}
public void loadParamsFile(Reader reader) throws IOException {
try {
CSVParser ps = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader);
Iterator<CSVRecord> rows = ps.iterator();
while(rows.hasNext()) {
CSVRecord rec = rows.next();
String srgName = rec.get("param");
String deobfName = rec.get("name");
int mod = Integer.parseInt(rec.get("side"));
csvParamsMappings.put(srgName, new Param(deobfName, mod));
String fName = srgName.substring(srgName.indexOf('_') + 1);
if(!fName.startsWith("i")) {
int i2 = fName.indexOf('_');
if(i2 != -1) {
int ordinal = -1;
String ordStr = fName.substring(i2 + 1);
if(ordStr.length() >= 2) {
try {
ordinal = Integer.parseInt(ordStr.substring(0, ordStr.length() - 1));
}catch(NumberFormatException ex) {
}
}
if(ordinal >= 0) {
fName = "func_" + fName.substring(0, i2);
Param[] prm = csvParamsForFunction.get(fName);
if(prm == null || prm.length <= ordinal) {
Param[] prm2 = new Param[ordinal + 1];
if(prm != null) {
System.arraycopy(prm, 0, prm2, 0, prm.length);
}
prm = prm2;
}
prm[ordinal] = new Param(deobfName, mod);
csvParamsForFunction.put(fName, prm);
}
}
}
}
System.out.println(" Loaded " + csvParamsMappings.size() + " symbols from params.csv");
}catch(Throwable t) {
throw new IOException("Invalid params.csv file!");
}
}
}

View File

@ -0,0 +1,127 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CreateUnpatched {
public static boolean createUnpatched() {
try {
return createUnpatched0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'unpatched'!");
t.printStackTrace();
return false;
}
}
private static boolean createUnpatched0() throws Throwable {
File tmpDirectory = EaglerBuildToolsConfig.getTemporaryDirectory();
File mcpDir = new File(tmpDirectory, "ModCoderPack");
File minecraftSrc = new File(tmpDirectory, "MinecraftSrc/minecraft_src.jar");
File minecraftRes = new File(tmpDirectory, "MinecraftSrc/minecraft_res.jar");
File outputFile = new File("./MinecraftSrc.zip");
if(outputFile.exists()) {
System.err.println("ERROR: The file 'MinecraftSrc.zip' already exists in this directory!");
System.err.println("Delete it and re-run 'unpatched' to try again");
return false;
}
if(!mcpDir.isDirectory()) {
System.err.println("The '" + mcpDir.getName() + "' directory was not found in the temporary directory!");
System.err.println("Please run the 'init' command to create it");
return false;
}
if(!minecraftSrc.isFile()) {
System.err.println("The '" + minecraftSrc.getName() + "' file was not found in the temporary directory!");
System.err.println("Please run the 'init' command to create it");
return false;
}
if(!minecraftRes.isFile()) {
System.err.println("The '" + minecraftRes.getName() + "' file was not found in the temporary directory!");
System.err.println("Please run the 'init' command to create it");
return false;
}
File tmpJavadocOut = new File(tmpDirectory, "MinecraftSrc/minecraft_unpatched_javadoc.jar");
System.out.println();
System.out.println("Preparing source in '" + minecraftSrc.getName() + "'...");
System.out.println();
CSVMappings mp = new CSVMappings();
InsertJavaDoc.processSource(minecraftSrc, tmpJavadocOut, mcpDir, mp, false);
try(ZipOutputStream zot = new ZipOutputStream(new FileOutputStream(outputFile))) {
zot.setLevel(0);
int tl;
System.out.println("Extracting '" + tmpJavadocOut.getName() + "' into '" + outputFile.getName() + "'...");
try(FileInputStream fin = new FileInputStream(tmpJavadocOut)) {
tl = extractZipTo(new ZipInputStream(fin), zot, "src");
}
System.out.println("Extracted " + tl + " files.");
System.out.println();
System.out.println("Extracting '" + minecraftRes.getName() + "' into '" + outputFile.getName() + "'...");
try(FileInputStream fin = new FileInputStream(minecraftRes)) {
tl = extractZipTo(new ZipInputStream(fin), zot, "res");
}
System.out.println("Extracted " + tl + " files.");
}
if(!tmpJavadocOut.delete()) {
System.err.println();
System.err.println("ERROR: failed to delete '" + tmpJavadocOut.getName() + "' from temporary directory!");
}
return true;
}
private static int extractZipTo(ZipInputStream zin, ZipOutputStream zout, String pfx) throws IOException {
int cnt = 0;
ZipEntry in;
while((in = zin.getNextEntry()) != null) {
if(in.isDirectory()) {
continue;
}
String n = in.getName();
if(n.startsWith("/")) {
n = n.substring(1);
}
if(n.startsWith("META-INF")) {
continue;
}
ZipEntry out = new ZipEntry(pfx + "/" + n);
zout.putNextEntry(out);
IOUtils.copy(zin, zout, 8192);
++cnt;
}
return cnt;
}
}

View File

@ -0,0 +1,241 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.ApplyPatchesToZip;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.formatter.EclipseFormatter;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.JARSubprocess;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class DecompileMinecraft {
public static boolean decompileMinecraft(File mcpDataTMP, File minecraftJar, File minecraftSrc, File assetsJson, boolean writeJavaDoc) throws Throwable {
File filterOut = new File(minecraftSrc, "minecraft_classes.jar");
System.out.println();
System.out.println("Extracting '" + minecraftJar.getAbsolutePath() + "\" to \"" + filterOut.getAbsolutePath() + "\"...");
int xt = 0;
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(minecraftJar));
ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(filterOut))) {
jarOut.setLevel(0);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry et;
String nm;
while((et = jarIn.getNextEntry()) != null) {
if(!et.isDirectory() && (nm = et.getName()).endsWith(".class")) {
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.copy(jarIn, jarOut);
++xt;
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to extract \"" + minecraftJar.getAbsolutePath() + "\" to \"" + filterOut.getAbsolutePath() + "\"!");
ex.printStackTrace();
if(filterOut.exists()) {
filterOut.delete();
}
return false;
}
System.out.println("Extracted " + xt + " class files.");
File deobfOut = new File(minecraftSrc, "minecraft_specialsource.jar");
System.out.println();
System.out.println("Running SpecialSource...");
int ex = JARSubprocess.runJava(mcpDataTMP, new String[] {
"-cp", filterOut.getAbsolutePath() + JARSubprocess.classPathSeperator + "runtime.jar",
"net.md_5.specialsource.SpecialSource", "-i", filterOut.getAbsolutePath(), "-o",
deobfOut.getAbsolutePath(), "-m", "minecraft.srg", "--kill-source"
}, " [SpecialSource]");
filterOut.delete();
if(ex == 0) {
System.out.println("SpecialSource completed successfully.");
}else {
System.err.println("ERROR: MCP SpecialSource execution failed!");
return false;
}
System.out.println();
File deobfOut2 = new File(minecraftSrc, "minecraft_mcinjector.jar");
System.out.println("Running MCInjector...");
ex = JARSubprocess.runJava(mcpDataTMP, new String[] {
"-cp", filterOut.getAbsolutePath() + JARSubprocess.classPathSeperator + "runtime.jar",
"de.oceanlabs.mcp.mcinjector.MCInjector", "--jarIn", deobfOut.getAbsolutePath(), "--jarOut",
deobfOut2.getAbsolutePath(), "--mapIn", "minecraft.exc", "--jsonIn", "exceptor.json",
"--lvt", "STRIP"
}, " [MCInjector]");
deobfOut.delete();
if(ex == 0) {
System.out.println("MCInjector completed successfully.");
}else {
System.err.println("ERROR: MCP MCInjector execution failed!");
return false;
}
System.out.println();
File ffOut = new File(minecraftSrc, "fernflower.tmp");
if(ffOut.isFile()) {
ffOut.delete();
}else if(ffOut.isDirectory()) {
FileUtils.deleteDirectory(ffOut);
}
if(!ffOut.mkdir()) {
System.err.println("ERROR: Could not create Fernflower output directory!");
return false;
}
System.out.println("Decompiling with Fernflower...");
System.out.println("This will take a while, go get a drink or something lol.");
System.out.println();
System.out.println("Staying hydrated is important when u work on a fucked up project that");
System.out.println("will make you angry enough put your fists through your bedroom wall");
System.out.println();
ex = JARSubprocess.runJava(mcpDataTMP, new String[] {
"-jar", "fernflower.jar", "-din=1", "-rbr=1", "-dgs=1", "-asc=1", "-rsy=1", "-iec=1",
"-ren=0", "-jvn=1", "-udv=1", "-ump=1", "-log=WARN", deobfOut2.getAbsolutePath(),
ffOut.getAbsolutePath()
}, " [Fernflower]");
deobfOut2.delete();
if(ex == 0) {
System.out.println("Decompiler completed successfully.");
}else {
System.err.println("ERROR: Fernflower decompiler failed!");
return false;
}
System.out.println();
File[] ff = ffOut.listFiles();
File decomp = null;
for(int i = 0; i < ff.length; ++i) {
if(ff[i].getName().endsWith(".jar")) {
if(ff[i].getName().equalsIgnoreCase("minecraft_mcinjector.jar")) {
decomp = ff[i];
}else {
if(decomp == null) {
decomp = ff[i];
}
}
}
}
if(decomp == null) {
System.err.println("Could not find Fernflower output jar! (in " + ffOut.getAbsolutePath() + ")");
return false;
}
File formatOut = new File(minecraftSrc, "minecraft_src.jar");
System.out.println("Formatting source for patches...");
System.out.println(" (Using default Eclipse format)");
System.out.print(" ");
xt = 0;
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(decomp));
ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(formatOut))) {
jarOut.setLevel(5);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry et;
String nm;
while((et = jarIn.getNextEntry()) != null) {
if((nm = et.getName()).endsWith(".java")) {
String txt = IOUtils.toString(jarIn, "UTF-8");
txt = EclipseFormatter.processSource(txt, "\n");
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.write(txt, jarOut, "UTF-8");
++xt;
if(xt % 75 == 74) {
System.out.print(".");
}
}else {
if(!nm.startsWith("META-INF")) {
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.copy(jarIn, jarOut, 4096);
}
}
}
}
System.out.println();
System.out.println("Formatted " + xt + " classes.");
System.out.println();
try {
FileUtils.deleteDirectory(ffOut);
}catch(IOException exx) {
}
File patchOut = new File(minecraftSrc, "minecraft_src_patch.jar");
try {
ApplyPatchesToZip.applyPatches(formatOut, null, new File(EaglerBuildTools.repositoryRoot, "patches/minecraft"), patchOut, true, true);
}catch(Throwable t) {
System.err.println("ERROR: Could not apply 'patches' directory to: " + patchOut.getName());
return false;
}
File javadocOut = new File(minecraftSrc, "minecraft_src_javadoc.jar");
CSVMappings comments = writeJavaDoc ? new CSVMappings() : null;
if(!InsertJavaDoc.processSource(patchOut, javadocOut, mcpDataTMP, comments)) {
System.err.println("ERROR: Could not create javadoc!");
return false;
}
File resourcesOut = new File(minecraftSrc, "minecraft_res.jar");
if(!LoadResources.loadResources(minecraftJar, assetsJson, resourcesOut, mcpDataTMP, new File(minecraftSrc, "minecraft_languages.zip"))) {
System.err.println("ERROR: Could not copy resources!");
return false;
}
File patchResourcesOut = new File(minecraftSrc, "minecraft_res_patch.jar");
try {
ApplyPatchesToZip.applyPatches(resourcesOut, null, new File(EaglerBuildTools.repositoryRoot, "patches/resources"), patchResourcesOut, true, true);
}catch(Throwable t) {
System.err.println("ERROR: Could not apply 'patches' directory to: " + patchResourcesOut.getName());
t.printStackTrace();
return false;
}
return true;
}
}

View File

@ -0,0 +1,175 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import org.apache.commons.io.FileUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FFMPEG {
public static final boolean windows = System.getProperty("os.name").toLowerCase().contains("windows");
public static String foundFFMPEG = null;
public static void confirmFFMPEG() {
if(checkFFMPEGOnPath()) {
foundFFMPEG = "ffmpeg";
return;
}
if(windows) {
File f = new File("mcp918/ffmpeg.exe");
if(!f.isFile()) {
System.out.println();
System.out.println("ERROR: 'ffmpeg.exe' wasn't found in the 'mcp918' folder!");
System.out.println();
System.out.println("Please visit one of the following URLs to download it:");
System.out.println(" - https://www.gyan.dev/ffmpeg/builds/");
System.out.println(" - https://github.com/BtbN/FFmpeg-Builds/releases");
System.out.println();
System.out.println("Locate 'bin/ffmpeg.exe' in the .zip file you download and");
System.out.println("place it in the 'mcp918' folder and press enter to continue");
System.out.println();
try {
while(System.in.read() != '\n') {
try {
Thread.sleep(20l);
} catch (InterruptedException e) {
}
}
}catch(IOException ex) {
}
confirmFFMPEG();
}else {
foundFFMPEG = f.getAbsolutePath();
}
}else {
do {
File f = new File("mcp918/ffmpeg");
if(f.isFile() && f.canExecute()) {
foundFFMPEG = f.getAbsolutePath();
return;
}
System.out.println();
System.out.println("ERROR: ffmpeg is not installed on this system!");
System.out.println();
System.out.println("Please install it to continue, you can use the package");
System.out.println("manager on most distros to do this automatically:");
System.out.println(" - Debian: apt install ffmpeg");
System.out.println(" - Ubuntu: apt install ffmpeg");
System.out.println(" - Fedora: dnf install ffmpeg");
System.out.println(" - Arch: pacman -S ffmpeg");
System.out.println();
System.out.println("Alternatively, place the 'ffmpeg' executable in the");
System.out.println("'mcp918' folder of this repository");
System.out.println();
System.out.println("Make sure it has chmod +x");
System.out.println();
System.out.println("Press enter to continue once it has installed");
System.out.println();
try {
while(System.in.read() != '\n') {
try {
Thread.sleep(20l);
} catch (InterruptedException e) {
}
}
}catch(IOException ex) {
}
}while(!checkFFMPEGOnPath());
foundFFMPEG = "ffmpeg";
}
}
public static int run(File rundir, String... args) {
String[] e = new String[args.length + 1];
System.arraycopy(args, 0, e, 1, args.length);
if(foundFFMPEG == null) {
confirmFFMPEG();
}
e[0] = foundFFMPEG;
ProcessBuilder pb = new ProcessBuilder(e);
pb.directory(rundir);
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
try {
Process p = pb.start();
while(true) {
try {
return p.waitFor();
} catch (InterruptedException ee) {
}
}
}catch(IOException ex) {
System.err.println("Could not start ffmpeg process!");
ex.printStackTrace();
return -1;
}
}
public static byte[] encodeOgg(File temporaryDir, byte[] bytesInput, int samples, int bitrate, boolean stereo) throws IOException {
File src = new File(temporaryDir, "temp.src.ogg");
FileUtils.writeByteArrayToFile(src, bytesInput);
File dst = new File(temporaryDir, "temp.dst.ogg");
int i;
if (stereo) {
i = run(temporaryDir, "-y", "-v", "error", "-i", "temp.src.ogg", "-c:a", "libvorbis", "-ac", "2",
"-apply_phase_inv", "1", "-b:a", "" + bitrate + "k", "-ar", "" + samples, "temp.dst.ogg");
} else {
i = run(temporaryDir, "-y", "-v", "error", "-i", "temp.src.ogg", "-c:a", "libvorbis", "-ac", "1",
"-apply_phase_inv", "0", "-b:a", "" + bitrate + "k", "-ar", "" + samples, "temp.dst.ogg");
}
src.delete();
if(i != 0) {
throw new IOException("FFMPEG returned error code: " + i);
}
byte[] read = FileUtils.readFileToByteArray(dst);
dst.delete();
return read;
}
public static boolean checkFFMPEGOnPath() {
ProcessBuilder pb = new ProcessBuilder("ffmpeg", "-version");
Process proc;
try {
proc = pb.start();
}catch(IOException ex) {
return false;
}
int exitCode;
while(true) {
try {
exitCode = proc.waitFor();
break;
} catch (InterruptedException e) {
}
}
return exitCode == 0;
}
}

View File

@ -0,0 +1,231 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.lax1dude.eaglercraft.v1_8.buildtools.decompiler.ParameterSplitter;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Param;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Symbol;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class GenerateEXCs {
public static boolean generateEXCs(File mcpDataTMP, File excOut, CSVMappings params) {
System.out.println();
System.out.println("Generating \"" + excOut.getName() + "\" from \"" + mcpDataTMP.getName() + "\"...");
File paramsCSV = new File(mcpDataTMP, "params.csv");
try(FileReaderUTF fr = new FileReaderUTF(paramsCSV)) {
params.loadParamsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + paramsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
Map<Integer,String> paramsTmp = new HashMap();
Set<String> definedFunctions = new HashSet();
int pcount = 0;
int mcount = 0;
int pgcount = 0;
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.exc")));
PrintWriter os = new PrintWriter(new FileWriterUTF(excOut));) {
String s;
while((s = is.readLine()) != null) {
int idx = s.lastIndexOf('|');
if(idx != -1) {
String pfx = s.substring(0, idx);
String func = null;
int p1 = pfx.indexOf('(');
if(p1 != -1) {
func = pfx.substring(0, p1);
func = pfx.substring(func.lastIndexOf('.') + 1);
}
if(func != null) {
definedFunctions.add(func);
}
if(idx != s.length() - 1) {
paramsTmp.clear();
String[] prms = s.substring(idx + 1).split(",");
String[] nprms = new String[prms.length];
int lpc = 0;
for(int i = 0; i < prms.length; ++i) {
Param p = params.csvParamsMappings.get(prms[i]);
if(p != null) {
nprms[i] = p.name;
++pcount;
++lpc;
}
}
if(lpc != prms.length) {
if(p1 != -1) {
String sig = pfx.substring(p1);
sig = sig.substring(0, sig.indexOf('='));
pgcount += ParameterSplitter.getParameterArray(sig, nprms);
}
for(int i = 0; i < nprms.length; ++i) {
if(nprms[i] == null) {
nprms[i] = "param0" + i;
}
}
}
s = pfx + "|" + String.join(",", nprms);
}else if(func != null) {
int idxx = func.indexOf('_');
int idxx2 = func.lastIndexOf('_');
if(idxx2 > idxx) {
func = func.substring(0, idxx2 - 1);
}
Param[] pars = params.csvParamsForFunction.get(func);
String sig = null;
if(p1 != -1) {
sig = pfx.substring(p1);
sig = sig.substring(0, sig.indexOf('='));
}
if(pars == null) {
if(sig != null) {
String[] sg = ParameterSplitter.getParameterSigArray(sig, "par");
if(sg != null) {
s = pfx + "|" + String.join(",", sg);
}
pgcount += sg.length;
}
}else {
int notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
++notNullLen;
}
}
String[] sg = new String[notNullLen];
notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
sg[notNullLen++] = pars[i].name;
++pcount;
}
}
s = pfx + "|" + String.join(",", sg);
}
}
}
int idx3 = s.indexOf('(');
if(idx3 != -1) {
int idx4 = s.lastIndexOf('.', idx3);
if(idx4 != -1) {
String func = s.substring(idx4 + 1, idx3);
Symbol rp = params.csvMethodsMappings.get(func);
if(rp != null) {
String pfx = s.substring(0, idx4);
String pofx = s.substring(idx3);
s = pfx + "." + rp.name + pofx;
++mcount;
}
}
}
os.println(s);
}
os.println();
os.println("# auto generated entries start here:");
try(BufferedReader iss = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.srg")))) {
while((s = iss.readLine()) != null) {
if(s.startsWith("MD:")) {
int idx = s.lastIndexOf(' ');
if(idx > 0) {
int idx2 = s.lastIndexOf(' ', idx - 1);
String fname = s.substring(idx2 + 1, idx);
String fnameShort = fname;
String fsig = s.substring(idx + 1);
fnameShort = fname.substring(fname.lastIndexOf('/') + 1);
int idx3 = fnameShort.lastIndexOf('_');
if(idx3 != -1 && fnameShort.lastIndexOf('_', idx3 - 1) > 0) {
fnameShort = fnameShort.substring(0, idx3);
}
if(definedFunctions.add(fnameShort)) {
String[] sg = ParameterSplitter.getParameterSigArray(fsig, "par");
Param[] pars = params.csvParamsForFunction.get(fnameShort);
if(pars != null) {
int notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
++notNullLen;
}
}
if(notNullLen > 0) {
notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
int ii = notNullLen++;
if(ii < sg.length) {
sg[ii] = pars[i].name;
++pcount;
}
}
}
int idx4 = fname.lastIndexOf('/');
String ppfx = fname.substring(0, idx4);
String ppfunc = fname.substring(idx4 + 1);
Symbol rp = params.csvMethodsMappings.get(ppfunc);
if(rp != null) {
ppfunc = rp.name;
++mcount;
}
fname = ppfx + "." + ppfunc;
os.println(fname + fsig + "=|" + String.join(",", sg));
}
}else {
if(sg != null) {
if(sg.length > 0) {
pgcount += sg.length;
int idx4 = fname.lastIndexOf('/');
String ppfx = fname.substring(0, idx4);
String ppfunc = fname.substring(idx4 + 1);
Symbol rp = params.csvMethodsMappings.get(ppfunc);
if(rp != null) {
ppfunc = rp.name;
++mcount;
}
fname = ppfx + "." + ppfunc;
os.println(fname + fsig + "=|" + String.join(",", sg));
}
}
}
}
}
}
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to write \"" + excOut.getName() + "\" from \"joined.exc\"!");
ex.printStackTrace();
return false;
}
System.out.println(" - Deobf " + pcount + " params to \"" + excOut.getName() + "\"");
System.out.println(" - Generate " + pgcount + " params to \"" + excOut.getName() + "\"");
return true;
}
}

View File

@ -0,0 +1,100 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Symbol;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class GenerateSRGs {
public static boolean generate(File mcpDataTMP, File srgOut, CSVMappings csv) throws Throwable {
System.out.println();
System.out.println("Generating \"" + srgOut.getName() + "\" from \"" + mcpDataTMP.getName() + "\"...");
File methodsCSV = new File(mcpDataTMP, "methods.csv");
try(FileReaderUTF fr = new FileReaderUTF(methodsCSV)) {
csv.loadMethodsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + methodsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
File fieldsCSV = new File(mcpDataTMP, "fields.csv");
try(FileReaderUTF fr = new FileReaderUTF(fieldsCSV)) {
csv.loadFieldsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + fieldsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
int ccount = 0;
int mcount = 0;
int fcount = 0;
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.srg")));
PrintWriter os = new PrintWriter(new FileWriterUTF(srgOut));) {
String s;
while((s = is.readLine()) != null) {
if(s.startsWith("MD:")) {
int lastSpace = s.lastIndexOf(' ');
String sig = s.substring(lastSpace + 1);
s = s.substring(0, lastSpace);
int lastSlash = s.lastIndexOf('/');
String fd = s.substring(lastSlash + 1);
s = s.substring(0, lastSlash);
Symbol sm = csv.csvMethodsMappings.get(fd);
if(sm != null) {
++mcount;
fd = sm.name;
}
os.println(s + "/" + fd + " " + sig);
}else if(s.startsWith("FD:")) {
int lastSlash = s.lastIndexOf('/');
String fd = s.substring(lastSlash + 1);
s = s.substring(0, lastSlash);
Symbol sm = csv.csvFieldsMappings.get(fd);
if(sm != null) {
++fcount;
fd = sm.name;
}
os.println(s + "/" + fd);
}else if(s.startsWith("CL:")) {
++ccount;
os.println(s);
}else {
os.println(s);
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to write \"" + srgOut.getName() + "\" from \"joined.srg\"!");
ex.printStackTrace();
return false;
}
System.out.println(" - Deobf " + ccount + " classes to \"" + srgOut.getName() + "\"");
System.out.println(" - Deobf " + mcount + " methods to \"" + srgOut.getName() + "\"");
System.out.println(" - Deobf " + fcount + " fields to \"" + srgOut.getName() + "\"");
return true;
}
}

View File

@ -0,0 +1,135 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class InitMCP {
public static boolean initTask(File f, File mcpDataTMP) throws Throwable {
File mcpUnifiedJar = new File(mcpDataTMP, "runtime.jar");
String[] jarsToUnify = new String[] { "mcinjector.jar", "specialsource.jar" }; //, "retroguard.jar" };
boolean[] jarsFound = new boolean[jarsToUnify.length];
String[] configToCopy = new String[] { "exceptor.json", "fields.csv", "joined.exc",
"joined.srg", "methods.csv", "params.csv", "fernflower.jar" };
boolean[] configFound = new boolean[configToCopy.length];
Set<String> copiedFiles = new HashSet();
System.out.println();
System.out.println("Extracting \"" + f.getAbsolutePath() + "\" to \"" + mcpDataTMP.getAbsolutePath() + "\"...");
try(ZipInputStream is = new ZipInputStream(new FileInputStream(f));
ZipOutputStream os = new ZipOutputStream(new FileOutputStream(mcpUnifiedJar))) {
os.setLevel(0);
os.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
os.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry e;
entry_read: while((e = is.getNextEntry()) != null) {
String zn = e.getName();
if(zn.startsWith("/")) {
zn = zn.substring(1);
}
for(int ii = 0; ii < jarsToUnify.length; ++ii) {
if(zn.endsWith(jarsToUnify[ii])) {
System.out.println(" " + jarsToUnify[ii] + " -> " + mcpUnifiedJar.getName());
ZipInputStream iis = new ZipInputStream(is);
ZipEntry e2;
while((e2 = iis.getNextEntry()) != null) {
if(e2.isDirectory()) {
continue;
}
String n = e2.getName();
int i = n.indexOf("META-INF");
if(i == 0 || i == 1) {
continue;
}
if(copiedFiles.add(n)) {
ZipEntry e3 = new ZipEntry(e2.getName());
os.putNextEntry(e3);
IOUtils.copy(iis, os, 4096);
}
}
jarsFound[ii] = true;
continue entry_read;
}
}
for(int ii = 0; ii < configToCopy.length; ++ii) {
if(zn.endsWith(configToCopy[ii])) {
System.out.println(" " + configToCopy[ii] + " -> " + configToCopy[ii]);
try(OutputStream oss = new FileOutputStream(new File(mcpDataTMP, configToCopy[ii]))) {
IOUtils.copy(is, oss, 32768);
}
configFound[ii] = true;
continue entry_read;
}
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to extract \"" + f.getAbsolutePath() + "\" to \"" + mcpDataTMP.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
boolean err = false;
for(int ii = 0; ii < jarsToUnify.length; ++ii) {
if(!jarsFound[ii]) {
err = true;
System.err.println("JAR not found: \"" + jarsToUnify[ii] + "\"!");
}
}
for(int ii = 0; ii < configToCopy.length; ++ii) {
if(!configFound[ii]) {
err = true;
System.err.println("Config not found: \"" + configToCopy[ii] + "\"!");
}
}
if(err) {
System.err.println("ERROR: Could not extract all required MCP files from \"" + f.getName() + "\"!");
return false;
}
CSVMappings mappings = new CSVMappings();
File srgsOut = new File(mcpDataTMP, "minecraft.srg");
if(!GenerateSRGs.generate(mcpDataTMP, srgsOut, mappings)) {
System.err.println("ERROR: could not generate joined \"minecraft.srg\" file from conf in \"" + mcpDataTMP.getAbsolutePath() + "\"!");
return false;
}
File excsOut = new File(mcpDataTMP, "minecraft.exc");
if(!GenerateEXCs.generateEXCs(mcpDataTMP, excsOut, mappings)) {
System.err.println("ERROR: could not generate joined \"minecraft.exc\" file from conf in \"" + mcpDataTMP.getAbsolutePath() + "\"!");
return false;
}
return true;
}
}

View File

@ -0,0 +1,158 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.io.FileUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class InitTask {
private static File locatedMCPZip = null;
private static File locatedMinecraftJar = null;
private static File locatedAssetsJson = null;
public static boolean initTask() {
try {
return initTask0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'init'!");
t.printStackTrace();
return false;
}
}
private static boolean initTask0() throws Throwable {
System.out.println("Scanning 'mcp918' folder...");
File mcp918dir = new File(EaglerBuildTools.repositoryRoot, "mcp918");
if(!mcp918dir.isDirectory()) {
System.err.println("ERROR: \"" + mcp918dir.getAbsolutePath() + "\" is not a directory!");
return false;
}
for(File f : mcp918dir.listFiles()) {
if(f.getName().equalsIgnoreCase("mcp918.zip")) {
locatedMCPZip = f;
}
if(locatedMCPZip == null && f.getName().endsWith(".zip")) {
locatedMCPZip = f;
}
if(f.getName().equalsIgnoreCase("1.8.8.jar")) {
locatedMinecraftJar = f;
}
if(locatedMinecraftJar == null && f.getName().endsWith(".jar")) {
locatedMinecraftJar = f;
}
if(f.getName().equalsIgnoreCase("1.8.json")) {
locatedAssetsJson = f;
}
if(locatedAssetsJson == null && f.getName().endsWith(".json")) {
locatedAssetsJson = f;
}
}
if(locatedMCPZip == null) {
System.err.println("ERROR: could not find ./mcp918/mcp918.zip! Please locate it and copy it into the 'mcp918' folder.");
return false;
}
if(locatedMinecraftJar == null) {
locatedMinecraftJar = MinecraftLocator.locateMinecraftVersionJar("1.8.8");
if(locatedMinecraftJar == null) {
System.err.println("ERROR: could not find ./mcp918/1.8.8.jar! Please locate it and copy it into the 'mcp918' folder.");
return false;
}
}
if(locatedAssetsJson == null) {
locatedAssetsJson = MinecraftLocator.locateMinecraftVersionAssets("1.8");
if(locatedAssetsJson == null) {
System.err.println("ERROR: could not find ./mcp918/1.8.json! Please locate it and copy it into the 'mcp918' folder.");
return false;
}
}
FFMPEG.confirmFFMPEG();
File buildToolsTmp = EaglerBuildToolsConfig.getTemporaryDirectory();
boolean btExist = buildToolsTmp.exists();
if(btExist && !(buildToolsTmp.isDirectory() && buildToolsTmp.list().length == 0)) {
System.out.println();
System.out.println("Notice: BuildTools is already initialized.");
System.out.println();
System.out.println("you must revert all changes in the 'patches' directory of");
System.out.println("this repo back to the main repository's current commits,");
System.out.println("otherwise the 'pullrequest' command wll not work properly");
System.out.println();
System.out.print("Do you want to re-initialize? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("Ok nice, the re-init will be cancelled. (thank god)");
return true;
}else {
try {
FileUtils.deleteDirectory(buildToolsTmp);
btExist = false;
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + buildToolsTmp.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
File mcpDataTMP = new File(buildToolsTmp, "ModCoderPack");
if(!mcpDataTMP.isDirectory() && !mcpDataTMP.mkdirs()) {
System.err.println("ERROR: failed to create \"" + mcpDataTMP.getAbsolutePath() + "\"!");
return false;
}
boolean skipMCP = false;
if(!skipMCP && !InitMCP.initTask(locatedMCPZip, mcpDataTMP)) {
System.err.println("ERROR: could not initialize MCP from \"" + locatedMCPZip.getAbsolutePath() + "\"!");
return false;
}
File minecraftSrcTmp = new File(buildToolsTmp, "MinecraftSrc");
if(!minecraftSrcTmp.isDirectory() && !minecraftSrcTmp.mkdirs()) {
System.err.println("ERROR: failed to create \"" + minecraftSrcTmp.getAbsolutePath() + "\"!");
return false;
}
if(!DecompileMinecraft.decompileMinecraft(mcpDataTMP, locatedMinecraftJar, minecraftSrcTmp, locatedAssetsJson, true)) {
System.err.println("ERROR: could not decompile and patch 1.8.8.jar from \"" + locatedMinecraftJar.getAbsolutePath() + "\"!");
return false;
}
return true;
}
}

View File

@ -0,0 +1,389 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.Lines;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Symbol;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class InsertJavaDoc {
public static final String enumImport = "import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;";
private static final String[] typeModifiersFields = new String[] {
"public", "private", "protected", "static",
"final", "volatile", "transient"
};
private static boolean isTypeModifierField(String tk) {
for(int i = 0; i < typeModifiersFields.length; ++i) {
if(typeModifiersFields[i].equals(tk)) {
return true;
}
}
return false;
}
private static final String[] typeModifiersMethods = new String[] {
"public", "private", "protected", "static",
"final", "synchronized", "abstract", "default"
};
private static final Pattern illegalCharactersNotATypeName = Pattern.compile("[^a-zA-Z0-9_\\-\\$\\[\\]<>\\.]");
private static boolean isTypeModifierMethod(String tk) {
for(int i = 0; i < typeModifiersMethods.length; ++i) {
if(typeModifiersMethods[i].equals(tk)) {
return true;
}
}
return false;
}
public static boolean processSource(File fileIn, File fileOut, File mcpDataTMP, CSVMappings csv) throws Throwable {
return processSource(fileIn, fileOut, mcpDataTMP, csv, true);
}
public static boolean processSource(File fileIn, File fileOut, File mcpDataTMP, CSVMappings csv, boolean compress) throws Throwable {
System.out.println("Adding javadoc...");
if(csv == null) {
System.out.println("(writing enums only, skipping field/method annotations)");
}
//RealOpenGLEnums.initEnums();
//System.out.println("Loaded " + RealOpenGLEnums.enumNames.size() + " OpenGL enums");
List<String> copyrightComment = null;
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(EaglerBuildTools.repositoryRoot, "patches/minecraft/output_license.txt")))) {
copyrightComment = new ArrayList();
copyrightComment.add("/**+");
String ln;
while((ln = is.readLine()) != null) {
copyrightComment.add(" * " + ln);
}
copyrightComment.add(" * ");
copyrightComment.add(" */");
}
Map<String, List<Symbol>> methodsInClasses = new HashMap();
Map<String, List<Symbol>> fieldsInClasses = new HashMap();
if(csv != null) {
File methodsCSV = new File(mcpDataTMP, "methods.csv");
try(FileReaderUTF fr = new FileReaderUTF(methodsCSV)) {
csv.loadMethodsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + methodsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
File fieldsCSV = new File(mcpDataTMP, "fields.csv");
try(FileReaderUTF fr = new FileReaderUTF(fieldsCSV)) {
csv.loadFieldsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + fieldsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.srg")))) {
String s;
while((s = is.readLine()) != null) {
if(s.startsWith("MD:")) {
s = s.trim();
int idxx = s.lastIndexOf(' ');
int idxx2 = s.lastIndexOf(' ', idxx - 1);
s = s.substring(idxx2 + 1, idxx);
idxx = s.lastIndexOf('/');
String s1 = s.substring(0, idxx);
String s2 = s.substring(idxx + 1);
Symbol sm = csv.csvMethodsMappings.get(s2);
if(sm != null && sm.comment != null && sm.comment.length() > 0) {
List<Symbol> sbls = methodsInClasses.get(s1);
if(sbls == null) {
methodsInClasses.put(s1, sbls = new ArrayList());
}
sbls.add(sm);
}
}else if(s.startsWith("FD:")) {
s = s.trim();
int idxx = s.lastIndexOf(' ');
s = s.substring(idxx + 1);
idxx = s.lastIndexOf('/');
String s1 = s.substring(0, idxx);
String s2 = s.substring(idxx + 1);
Symbol sm = csv.csvFieldsMappings.get(s2);
if(sm != null && sm.comment != null && sm.comment.length() > 0) {
List<Symbol> sbls = fieldsInClasses.get(s1);
if(sbls == null) {
fieldsInClasses.put(s1, sbls = new ArrayList());
}
sbls.add(sm);
}
}
}
}
}
OpenGLEnumManager.loadEnumMap();
System.out.print(" ");
int xt = 0;
int modm = 0;
int modf = 0;
final int[] enums = new int[1];
Consumer<Integer> enumCounter = new Consumer<Integer>() {
@Override
public void accept(Integer t) {
enums[0] += t.intValue();
}
};
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(fileIn));
ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(fileOut))) {
jarOut.setLevel(compress ? 5 : 0);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry et;
String nm;
while((et = jarIn.getNextEntry()) != null) {
if(et.isDirectory()) {
continue;
}
nm = et.getName();
if(nm.endsWith(".java")) {
String fs = IOUtils.toString(jarIn, "UTF-8");
List<String> linesLst = new ArrayList();
linesLst.addAll(Lines.linesList(fs));
if(copyrightComment != null) {
for(int i = 0; i < linesLst.size(); ++i) {
String ln = linesLst.get(i);
if(!ln.startsWith("import")) {
if(ln.startsWith("public")) {
ln = ln.substring(6).trim();
}
if(ln.startsWith("class") || ln.startsWith("enum") || ln.startsWith("interface") || ln.startsWith("@interface")) {
linesLst.addAll(i, copyrightComment);
i += copyrightComment.size();
break;
}
}
}
}
String cnm = nm.substring(0, nm.length() - 5);
List<Symbol> meths = csv == null ? null : methodsInClasses.get(cnm);
List<Symbol> fields = csv == null ? null : fieldsInClasses.get(cnm);
if(meths != null || fields != null) {
for(int i = 0; i < linesLst.size(); ++i) {
String ln2 = linesLst.get(i);
boolean notMethod = ln2.endsWith(";");
String ln = ln2;
String indent = "";
while(ln.length() > 0 && Character.isWhitespace(ln.charAt(0))) {
indent += ln.charAt(0);
ln = ln.substring(1);
}
String[] tokens = ln.split("\\s+");
boolean hasTypeDecl = false;
boolean hasMethodDecl = false;
boolean hasType = false;
for(int j = 0; j < tokens.length; ++j) {
if(tokens[j].length() > 0) {
boolean b1 = false;
boolean b2 = false;
if(isTypeModifierField(tokens[j])) {
b1 = true;
hasTypeDecl = true;
}
if(!notMethod && isTypeModifierMethod(tokens[j])) {
b2 = true;
hasMethodDecl = true;
}
if(b1 || b2) {
continue;
}else if(!hasType) {
if(illegalCharactersNotATypeName.matcher(tokens[j]).find()) {
break;
}else {
hasType = true;
continue;
}
}
int idx = 0;
if(hasTypeDecl && j < tokens.length - 1 && tokens[j + 1].equals("=")) {
if(fields != null) {
for(int k = 0, l = fields.size(); k < l; ++k) {
Symbol ss = fields.get(k);
if(ss.name.equals(tokens[j])) {
List<String> lines = wordWrapComment(ss.comment, indent);
linesLst.addAll(i, lines);
i += lines.size();
++modf;
break;
}
}
}
}else if(((idx = tokens[j].indexOf('(')) != -1 && j > 0) || hasMethodDecl) {
if(meths != null) {
if(idx > 0) {
String sss = tokens[j].substring(0, idx);
for(int k = 0, l = meths.size(); k < l; ++k) {
Symbol ss = meths.get(k);
if(ss.name.equals(sss)) {
List<String> lines = wordWrapComment(ss.comment, indent);
linesLst.addAll(i, lines);
i += lines.size();
++modm;
break;
}
}
}
}
}
break;
}
}
}
}
int cnt0 = enums[0];
for(int i = 0, l = linesLst.size(); i < l; ++i) {
linesLst.set(i, OpenGLEnumManager.insertIntoLine(linesLst.get(i), enumCounter));
}
if(cnt0 != enums[0]) {
for(int i = 0, l = linesLst.size(); i < l; ++i) {
String line = linesLst.get(i);
if(line.startsWith("package")) {
linesLst.addAll(i + 1, Arrays.asList("", enumImport));
break;
}
}
}
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.write(String.join(System.lineSeparator(), linesLst), jarOut, "UTF-8");
++xt;
if(xt % 75 == 74) {
System.out.print(".");
}
}else {
if(!nm.startsWith("META-INF")) {
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.copy(jarIn, jarOut, 4096);
}
}
}
}catch(IOException ex) {
System.err.println("Failed to process jar '" + fileIn.getName() + "' and write it to '" + fileOut.getName() + "!");
ex.printStackTrace();
return false;
}
System.out.println();
System.out.println("Added " + enums[0] + " OpenGL enums");
if(csv != null) {
System.out.println("Added " + modm + " comments to methods");
System.out.println("Added " + modf + " comments to fields");
}
System.out.println();
return true;
}
private static List<String> wordWrapComment(String strIn, String indent) {
String[] wds = strIn.split("\\s+");
List<String> ret = new ArrayList();
ret.add(indent + "/**+");
String ln = "";
for(int i = 0; i < wds.length; ++i) {
if(ln.length() > 0 && wds[i].length() + ln.length() > 60) {
ret.add(indent + " * " + ln);
ln = "";
}
ln += ln.length() > 0 ? " " + wds[i] : wds[i];
}
if(ln.length() > 0) {
ret.add(indent + " * " + ln);
}
ret.add(indent + " */");
return ret;
}
public static String stripDocForDiff(String fileIn) {
List<String> linesIn = Lines.linesList(fileIn);
OpenGLEnumManager.loadEnumMap();
List<String> linesOut = new ArrayList();
boolean addOpenGLImport = false;
for(int i = 0, l = linesIn.size(); i < l; ++i) {
String line = linesIn.get(i);
if(line.trim().startsWith("/**+")) {
for(; i < l; ++i) {
if(linesIn.get(i).endsWith("*/")) {
break;
}
}
}else {
String line2 = OpenGLEnumManager.stripFromLine(line);
if(line2 != null) {
linesOut.add(line2);
addOpenGLImport = true;
}else {
linesOut.add(line);
}
}
}
if(addOpenGLImport) {
int idx = linesOut.indexOf(enumImport);
if(idx != -1) {
if(idx - 1 >= 0 && linesOut.get(idx - 1).trim().length() == 0 && linesOut.size() > 1) {
idx -= 1;
linesOut.remove(idx);
linesOut.remove(idx);
}else {
linesOut.remove(idx);
}
}
}
return String.join(System.lineSeparator(), linesOut);
}
}

View File

@ -0,0 +1,180 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.json.JSONObject;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class LoadResources {
public static boolean loadResources(File minecraftJarIn, File assetsIndexIn, File assetsJarOut, File tmpDir, File languagesZipOut) {
System.out.println("Copying resources from '" + minecraftJarIn.getName() + "' into '" + assetsJarOut.getName() + "'");
try(ZipOutputStream os = new ZipOutputStream(new FileOutputStream(assetsJarOut))) {
os.setLevel(5);
os.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
os.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
try(ZipInputStream is = new ZipInputStream(new FileInputStream(minecraftJarIn))) {
ZipEntry e;
while((e = is.getNextEntry()) != null) {
if(e.isDirectory()) {
continue;
}
String zn = e.getName();
if(zn.startsWith("/")) {
zn = zn.substring(1);
}
if(zn.startsWith("META-INF") || zn.endsWith(".class")) {
continue;
}
os.putNextEntry(e);
IOUtils.copy(is, os, 4096);
}
}
System.out.println();
System.out.println("Reading 'assetsIndexTransformer.json'...");
ResourceRulesList rules;
try {
rules = ResourceRulesList.loadResourceRules(new File(EaglerBuildTools.repositoryRoot, "mcp918/assetsIndexTransformer.json"));
}catch(IOException ex) {
System.err.println();
System.err.println("ERROR: failed to read 'mcp918/assetsIndexTransformer.json'!");
ex.printStackTrace();
return false;
}
System.out.println();
System.out.println("Reading asset index '" + assetsIndexIn.getAbsolutePath() + "'...");
try(ZipOutputStream os2 = new ZipOutputStream(new FileOutputStream(languagesZipOut))) {
os2.setLevel(5);
try {
JSONObject json = (new JSONObject(FileUtils.readFileToString(assetsIndexIn, StandardCharsets.UTF_8))).getJSONObject("objects");
Iterator<String> itr = json.keys();
System.out.println("Downloading assets from 'https://resources.download.minecraft.net/'...");
while(itr.hasNext()) {
String name = itr.next();
JSONObject obj = json.getJSONObject(name);
ResourceRulesList.ResourceRule r = rules.get(name);
if(r.action == ResourceRulesList.Action.EXCLUDE) {
System.out.println("Skipping file '" + name + "'");
continue;
}
String hash = obj.getString("hash");
int len = obj.getInt("size");
System.out.println("Downloading '" + name + "' (" + formatByteLength(len) + ") ...");
URL url;
try {
url = new URL("https://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash);
}catch(MalformedURLException ex) {
System.err.println("Resource file '" + name + "' had an invalid URL!");
ex.printStackTrace();
continue;
}
byte[] downloadedFile = new byte[len];
try(InputStream is = url.openStream()) {
int dl = 0;
int i = 0;
while(dl != len && (i = is.read(downloadedFile, dl, len - dl)) > 0) {
dl += i;
}
int a = is.available();
if(dl != len || a > 0) {
throw new IOException("File '" + url.toString() + "' was the wrong length! " + (a > 0 ? "" + a + " bytes remaining" : "" + (len - dl) + " bytes missing"));
}
}catch(IOException ex) {
System.err.println("Resource file '" + url.toString() + "' could not be downloaded!");
ex.printStackTrace();
continue;
}
if(r.action == ResourceRulesList.Action.ENCODE) {
try {
System.out.println(" - encoding ogg: " + (r.ffmpegSamples / 1000) + "kHz, " + r.ffmpegBitrate + "kbps, " + (r.ffmpegStereo ? "stereo" : "mono"));
downloadedFile = FFMPEG.encodeOgg(tmpDir, downloadedFile, r.ffmpegSamples, r.ffmpegBitrate, r.ffmpegStereo);
}catch(IOException ex) {
System.err.println("Resource file '" + name + "' could not be encoded!");
ex.printStackTrace();
continue;
}
}else if(r.action == ResourceRulesList.Action.LANGUAGES_ZIP) {
int j = name.lastIndexOf('/');
if(j != -1) {
name = name.substring(j + 1);
}
System.out.println(" - writing language '" + name + "' to '" + languagesZipOut.getName() + "'");
os2.putNextEntry(new ZipEntry(name));
os2.write(downloadedFile);
continue;
}
os.putNextEntry(new ZipEntry("assets/" + name));
os.write(downloadedFile);
}
}catch(IOException | JSONException ex) {
System.err.println("ERROR: failed to download additional assets from '" + assetsIndexIn.getName() + "'!");
ex.printStackTrace();
return false;
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to copy from '" + minecraftJarIn.getName() + "' -> '" +assetsJarOut.getName() + "'!");
ex.printStackTrace();
return false;
}
return true;
}
private static String formatByteLength(int len) {
if(len < 4096) {
return "" + len;
}else if(len < 1024 * 4096) {
return "" + (len / 1024) + "k";
}else {
return "" + (len / 1024 / 1024) + "M";
}
}
}

View File

@ -0,0 +1,81 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class MinecraftLocator {
private static boolean hasTriedToFind = false;
private static File directory = null;
private static File locateOrCopyFile(String name, String copyPath) {
File f = new File("./mcp918/" + name);
if(f.isFile()) {
return f;
}
if(!hasTriedToFind) {
hasTriedToFind = true;
String var0 = System.getProperty("os.name").toLowerCase();
if(var0.contains("win")) {
String ad = System.getenv("APPDATA");
if(ad != null) {
directory = new File(ad, ".minecraft");
}else {
directory = new File(System.getProperty("user.home"), ".minecraft");
}
}else if(var0.contains("mac")) {
directory = new File(System.getProperty("user.home"), "Library/Application Support/minecraft");
}else {
directory = new File(System.getProperty("user.home"), ".minecraft");
}
if(!directory.isDirectory()) {
directory = new File(System.getProperty("user.home"), "minecraft");
if(!directory.isDirectory()) {
directory = null;
}
}
}
if(directory == null) {
return null;
}else {
File f2 = new File(directory, copyPath);
if(f2.isFile()) {
try {
System.out.println("Copying '" + copyPath + "' from your .minecraft directory into './mcp918'...");
FileUtils.copyFile(f2, f, true);
return f;
} catch (IOException e) {
System.err.println("ERROR: failed to copy '" + copyPath + "' from your .minecraft directory into './mcp918'!");
e.printStackTrace();
return null;
}
}else {
return null;
}
}
}
public static File locateMinecraftVersionJar(String name) {
return locateOrCopyFile(name + ".jar", "versions/" + name + "/" + name + ".jar");
}
public static File locateMinecraftVersionAssets(String name) {
return locateOrCopyFile(name + ".json", "assets/indexes/" + name + ".json");
}
}

View File

@ -0,0 +1,228 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class OpenGLEnumManager {
private static boolean hasLoaded = false;
public static final Set<String> classNames = new HashSet();
public static final Map<String,String> enumsForGLStateManager = new HashMap();
public static final Map<String,Map<Integer,String>> enumsForFunctionKV = new HashMap();
public static final Map<String,Map<String,Integer>> enumsForFunctionVK = new HashMap();
public static boolean loadEnumMap() {
if(hasLoaded) {
return true;
}
hasLoaded = true;
try {
String enumsPath = "/lang/enums.json";
System.out.println("Loading OpenGL enums: " + enumsPath);
int fcnt = 0;
int ecnt = 0;
String jsonData;
try(InputStream is = OpenGLEnumManager.class.getResourceAsStream(enumsPath)) {
if(is == null) {
throw new FileNotFoundException("classpath:/" + enumsPath);
}
jsonData = IOUtils.toString(is, "UTF-8");
}
JSONArray enumJSON = (new JSONObject(jsonData)).getJSONArray("enums");
for(Object o : enumJSON.toList()) {
List<Object> enumData = (List<Object>) o;
List<String> functionsToAdd = new ArrayList();
Map<Integer,String> enumsToAddKV = new HashMap();
Map<String,Integer> enumsToAddVK = new HashMap();
Map<String,Object> functionSet = (Map<String,Object>)enumData.get(0);
for(Entry<String,Object> etr : functionSet.entrySet()) {
classNames.add(etr.getKey());
List<Object> functionArr = (List<Object>)etr.getValue();
for(Object func : functionArr) {
functionsToAdd.add(etr.getKey() + "." + (String)func);
}
}
Map<String,Object> enumSet = (Map<String,Object>)enumData.get(1);
for(Entry<String,Object> etr : enumSet.entrySet()) {
Map<String,Object> enumEnums = (Map<String,Object>)etr.getValue();
for(Entry<String,Object> etr2 : enumEnums.entrySet()) {
Integer intg = Integer.parseInt(etr2.getKey());
enumsToAddKV.put(intg, (String)etr2.getValue());
enumsToAddVK.put((String)etr2.getValue(), intg);
++ecnt;
}
}
for(String fn : functionsToAdd) {
if(!enumsForFunctionKV.containsKey(fn)) {
++fcnt;
enumsForFunctionKV.put(fn, enumsToAddKV);
enumsForFunctionVK.put(fn, enumsToAddVK);
}
}
}
String glStateEnumsPath = "/lang/statemgr.json";
System.out.println("Loading OpenGL enums: " + glStateEnumsPath);
try(InputStream is = OpenGLEnumManager.class.getResourceAsStream(glStateEnumsPath)) {
if(is == null) {
throw new FileNotFoundException("classpath:/" + glStateEnumsPath);
}
jsonData = IOUtils.toString(is, "UTF-8");
}
JSONObject enumStateJSON = (new JSONObject(jsonData)).getJSONObject("statemgr_mappings");
for(Entry<String,Object> etr : enumStateJSON.toMap().entrySet()) {
String f = etr.getKey();
String m = (String)etr.getValue();
enumsForGLStateManager.put(f, m);
if(!enumsForFunctionKV.containsKey(f) && enumsForFunctionKV.containsKey(m)) {
enumsForFunctionKV.put(f, enumsForFunctionKV.get(m));
enumsForFunctionVK.put(f, enumsForFunctionVK.get(m));
++fcnt;
}
}
for(String str : enumsForGLStateManager.keySet()) {
int idx = str.indexOf('.');
if(idx != -1) {
classNames.add(str.substring(0, idx));
}
}
System.out.println("Loaded " + ecnt + " enums for " + fcnt + " functions");
return true;
}catch(Throwable ex) {
System.err.println("ERROR: could not load opengl enum map!");
ex.printStackTrace();
return false;
}
}
public static String insertIntoLine(String input, Consumer<Integer> progressCallback) {
int idx1 = input.indexOf('.');
if(idx1 != -1) {
String pfx = input.substring(0, idx1);
String p2 = pfx.trim();
if(classNames.contains(p2)) {
String fn = input.substring(idx1 + 1);
int idx2 = fn.indexOf('(');
if(idx2 != -1) {
String argz = fn.substring(idx2 + 1);
fn = fn.substring(0, idx2);
int idx3 = argz.lastIndexOf(')');
String pofx = "";
if(idx3 == -1) {
idx3 = argz.length();
}else {
pofx = argz.substring(idx3);
}
Map<Integer,String> repValues = enumsForFunctionKV.get(p2 + "." + fn);
if(repValues != null) {
argz = argz.substring(0, idx3);
String[] args = argz.split(", ");
int cnt = 0;
for(int i = 0; i < args.length; ++i) {
Integer j;
try {
j = Integer.valueOf(args[i]);
}catch(NumberFormatException ex) {
continue;
}
String estr = repValues.get(j);
if(estr != null) {
args[i] = estr;
++cnt;
}
}
if(cnt > 0) {
input = pfx + "." + fn + "(" + String.join(", ", args) + pofx;
if(progressCallback != null) {
progressCallback.accept(cnt);
}
}
}
}
}
}
return input;
}
public static String stripFromLine(String input) {
int idx1 = input.indexOf('.');
if(idx1 != -1) {
String pfx = input.substring(0, idx1);
String p2 = pfx.trim();
if(classNames.contains(p2)) {
String fn = input.substring(idx1 + 1);
int idx2 = fn.indexOf('(');
if(idx2 != -1) {
String argz = fn.substring(idx2 + 1);
fn = fn.substring(0, idx2);
int idx3 = argz.lastIndexOf(')');
String pofx = "";
if(idx3 == -1) {
idx3 = argz.length();
}else {
pofx = argz.substring(idx3);
}
Map<String,Integer> repValues = enumsForFunctionVK.get(p2 + "." + fn);
if(repValues != null) {
argz = argz.substring(0, idx3);
String[] args = argz.split(", ");
int cnt = 0;
for(int i = 0; i < args.length; ++i) {
Integer estr = repValues.get(args[i]);
if(estr != null) {
args[i] = estr.toString();
++cnt;
}
}
if(cnt > 0) {
return pfx + "." + fn + "(" + String.join(", ", args) + pofx;
}
}
}
}
}
return null;
}
}

View File

@ -0,0 +1,125 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ResourceRulesList {
public static ResourceRulesList loadResourceRules(File conf) throws IOException {
List<ResourceRule> list = new ArrayList();
try {
JSONArray rulesArray = new JSONObject(FileUtils.readFileToString(conf, StandardCharsets.UTF_8)).getJSONArray("rules");
for(int i = 0, l = rulesArray.length(); i < l; ++i) {
JSONObject obj = rulesArray.getJSONObject(i);
Iterator<String> itr = obj.keys();
while(itr.hasNext()) {
String name = itr.next();
JSONObject a = obj.getJSONObject(name);
boolean wildcard = name.endsWith("*");
if(wildcard) {
name = name.substring(0, name.length() - 1);
}
Action action = Action.valueOf(a.getString("action").toUpperCase());
int ffmpegSamples = 16000;
int ffmpegBitrate = 48;
boolean ffmpegStereo = false;
if(action == Action.ENCODE) {
JSONObject ffmpegObj = a.optJSONObject("ffmpeg", null);
if(ffmpegObj != null) {
ffmpegSamples = ffmpegObj.optInt("samples", ffmpegSamples);
ffmpegBitrate = ffmpegObj.optInt("bitrate", ffmpegBitrate);
ffmpegStereo = ffmpegObj.optBoolean("stereo", ffmpegStereo);
}
}
list.add(new ResourceRule(name, wildcard, action, ffmpegSamples, ffmpegBitrate, ffmpegStereo));
}
}
}catch(JSONException ex) {
throw new IOException("Invalid JSON file: " + conf.getAbsolutePath(), ex);
}
return new ResourceRulesList(list);
}
private final List<ResourceRule> list;
private ResourceRulesList(List<ResourceRule> list) {
this.list = list;
}
public ResourceRule get(String str) {
for(int i = 0, l = list.size(); i < l; ++i) {
ResourceRule r = list.get(i);
if(r.wildcard) {
if(str.startsWith(r.path)) {
return r;
}
}else {
if(str.equals(r.path)) {
return r;
}
}
}
return defaultRule;
}
private static final ResourceRule defaultRule = new ResourceRule("", true, Action.EXCLUDE, 16000, 48, false);
public static class ResourceRule {
private final String path;
private final boolean wildcard;
public final Action action;
public final int ffmpegSamples;
public final int ffmpegBitrate;
public final boolean ffmpegStereo;
protected ResourceRule(String path, boolean wildcard, Action action, int ffmpegSamples, int ffmpegBitrate,
boolean ffmpegStereo) {
this.path = path;
this.wildcard = wildcard;
this.action = action;
this.ffmpegSamples = ffmpegSamples;
this.ffmpegBitrate = ffmpegBitrate;
this.ffmpegStereo = ffmpegStereo;
}
}
public static enum Action {
INCLUDE, EXCLUDE, ENCODE, LANGUAGES_ZIP
}
}

View File

@ -0,0 +1,396 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.ApplyPatchesToZip;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class SetupWorkspace {
public static boolean setupWorkspace() {
return setupWorkspace0(false);
}
public static boolean pullRequestTest() {
return setupWorkspace0(true);
}
private static boolean setupWorkspace0(boolean applyPullRequest) {
File tmp = EaglerBuildToolsConfig.getTemporaryDirectory();
File dst = EaglerBuildToolsConfig.getWorkspaceDirectory();
try {
return setupWorkspace1(tmp, dst, applyPullRequest);
}catch(Throwable t) {
System.err.println();
if(applyPullRequest) {
System.err.println("Exception encountered while running task 'pullrequest_test'!");
}else {
System.err.println("Exception encountered while running task 'workspace'!");
}
t.printStackTrace();
return false;
}
}
private static boolean setupWorkspace1(File btTmpDirectory, File workspaceDirectory, boolean applyPullRequest) throws Throwable {
boolean wsExist = workspaceDirectory.exists();
if(wsExist && !(workspaceDirectory.isDirectory() && workspaceDirectory.list().length == 0)) {
System.err.println();
System.err.println("WARNING: A workspace already exists in \"" + workspaceDirectory.getAbsolutePath() + "\"!");
System.err.println();
System.err.println("Any changes you've made to the code will be lost!");
System.err.println();
System.out.print("Do you want to reset the workspace? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("Ok nice, the workspace folder will not be reset. (thank god)");
System.out.println();
System.out.println("Edit 'buildtools_config.json' to set up a different workspace folder");
return true;
}else {
try {
FileUtils.deleteDirectory(workspaceDirectory);
wsExist = false;
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + workspaceDirectory.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
File mcTmpDirectory = new File(btTmpDirectory, "MinecraftSrc");
File minecraftResJar = new File(mcTmpDirectory, "minecraft_res_patch.jar");
File minecraftJavadocTmp = new File(mcTmpDirectory, "minecraft_src_javadoc.jar");
System.out.println();
System.out.println("Setting up dev workspace in \"" + workspaceDirectory.getAbsolutePath() + "\"...");
System.out.println();
if(!workspaceDirectory.isDirectory() && !workspaceDirectory.mkdirs()) {
System.err.println("ERROR: could not create \"" + workspaceDirectory.getAbsolutePath() + "\"!");
throw new IOException("Could not create \"" + workspaceDirectory.getAbsolutePath() + "\"!");
}
if(!minecraftJavadocTmp.isFile()) {
System.err.println("ERROR: could not find 'minecraft_src_javadoc.jar' in your current temporary directory!");
System.err.println("Run the 'init' command again to generate it");
return false;
}
if(!minecraftResJar.isFile()) {
System.err.println("ERROR: could not find 'minecraft_res_patch.jar' in your current temporary directory!");
System.err.println("Run the 'init' command again to generate it");
return false;
}
File repoSources = new File("./sources");
File repoSourcesSetup = new File(repoSources, "setup/workspace_template");
File repoSourcesGame = new File(repoSources, "main/java");
File repoSourcesTeaVM = new File(repoSources, "teavm/java");
File repoSourcesLWJGL = new File(repoSources, "lwjgl/java");
File repoSourcesResources = new File(repoSources, "resources");
File srcMainJava = new File(workspaceDirectory, "src/main/java");
File srcLWJGLJava = new File(workspaceDirectory, "src/lwjgl/java");
File srcTeaVMJava = new File(workspaceDirectory, "src/teavm/java");
File resourcesExtractTo = new File(workspaceDirectory, "desktopRuntime/resources");
File mcLanguagesZip = new File(mcTmpDirectory, "minecraft_languages.zip");
File mcLanguagesExtractTo = new File(workspaceDirectory, "javascript/lang");
System.out.println("Copying files from \"/setup/workspace_template/\" to \"" + workspaceDirectory.getName() + "\"...");
try {
FileUtils.copyDirectory(repoSourcesSetup, workspaceDirectory);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/setup/workspace_template/\" to \"" + workspaceDirectory.getAbsolutePath() + "\"!");
throw ex;
}
String os = System.getProperty("os.name").toLowerCase();
if(os.contains("linux") || os.contains("macos") || os.contains("osx")) {
File gradleW = new File(workspaceDirectory, "gradlew");
if(!gradleW.setExecutable(true)) {
System.err.println("ERROR: could not set executable bit on 'gradlew'!");
System.err.println("Enter the root directory of the repository and run 'chmod +x gradlew' if you need access to the gradlew command");
}
}
File existingGi = new File(workspaceDirectory, ".gitignore");
if((existingGi.exists() && !existingGi.delete()) || !(new File(workspaceDirectory, ".gitignore.default").renameTo(existingGi))) {
System.err.println("ERROR: Could not rename \".gitignore.default\" to \".gitignore\" in the workspace directory!");
}
if(repoSourcesTeaVM.isDirectory()) {
System.out.println("Copying files from \"/sources/teavm/java/\" to workspace...");
try {
if(!srcTeaVMJava.isDirectory() && !srcTeaVMJava.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
FileUtils.copyDirectory(repoSourcesTeaVM, srcTeaVMJava);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/teavm/java/\" to \"" + srcTeaVMJava.getAbsolutePath() + "\"!");
throw ex;
}
}
System.out.println("Copying files from \"/sources/main/java/\" to workspace...");
try {
FileUtils.copyDirectory(repoSourcesGame, srcMainJava);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/main/java/\" to \"" + srcMainJava.getAbsolutePath() + "\"!");
throw ex;
}
if(repoSourcesLWJGL.isDirectory()) {
System.out.println("Copying files from \"/sources/lwjgl/java/\" to workspace...");
try {
if(!srcLWJGLJava.isDirectory() && !srcLWJGLJava.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
FileUtils.copyDirectory(repoSourcesLWJGL, srcLWJGLJava);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/lwjgl/java/\" to \"" + srcLWJGLJava.getAbsolutePath() + "\"!");
throw ex;
}
}
System.out.println("Copying files from \"/sources/resources/\" to workspace...");
try {
if(!resourcesExtractTo.isDirectory() && !resourcesExtractTo.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
FileUtils.copyDirectory(repoSourcesResources, resourcesExtractTo);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/resources/\" to \"" + resourcesExtractTo.getAbsolutePath() + "\"!");
throw ex;
}
if(applyPullRequest) {
System.out.println();
System.out.println("Applying \"pullrequest\" directory to \"minecraft_src_patch.jar\"...");
File unpatchOut = new File(mcTmpDirectory, "minecraft_src.jar");
File patchOut = new File(mcTmpDirectory, "minecraft_src_patch.jar");
File unpatchResOut = new File(mcTmpDirectory, "minecraft_res.jar");
File patchResOut = new File(mcTmpDirectory, "minecraft_res_patch.jar");
File tmpPatchedPatchOut = new File(mcTmpDirectory, "minecraft_src_pullrequest_patch.jar");
File tmpPatchedPatchJavadocOut = new File(mcTmpDirectory, "minecraft_src_pullrequest_javadoc.jar");
File tmpPatchedPatchResOut = new File(mcTmpDirectory, "minecraft_res_pullrequest_patch.jar");
try {
ApplyPatchesToZip.applyPatches(patchOut, unpatchOut, new File("./pullrequest/source"), tmpPatchedPatchOut, false, false);
}catch(Throwable t) {
System.err.println();
System.err.println("ERROR: Could not apply pullrequest directory patches to: " + patchOut.getName());
System.err.println(t.toString());
tmpPatchedPatchOut.delete();
return false;
}
CSVMappings comments = new CSVMappings();
if(!InsertJavaDoc.processSource(tmpPatchedPatchOut, tmpPatchedPatchJavadocOut,
new File(btTmpDirectory, "ModCoderPack"), comments)) {
System.err.println();
System.err.println("ERROR: Could not create pullrequest javadoc!");
return false;
}
tmpPatchedPatchOut.delete();
try {
ApplyPatchesToZip.applyPatches(patchResOut, unpatchResOut, new File("./pullrequest/resources"), tmpPatchedPatchResOut, false, false);
}catch(Throwable t) {
System.err.println();
System.err.println("ERROR: Could not apply pullrequest directory patches to: " + patchResOut.getName());
System.err.println(t.toString());
tmpPatchedPatchOut.delete();
tmpPatchedPatchResOut.delete();
return false;
}
minecraftJavadocTmp = tmpPatchedPatchJavadocOut;
minecraftResJar = tmpPatchedPatchResOut;
}else {
System.out.println("Extracting files from \"minecraft_src_javadoc.jar\" to \"/src/main/java/\"...");
}
try {
if(!srcMainJava.isDirectory() && !srcMainJava.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
extractJarTo(minecraftJavadocTmp, srcMainJava);
}catch(IOException ex) {
System.err.println("ERROR: could not extract \"" + minecraftJavadocTmp.getName() + ".jar\" to \"" +
srcMainJava.getAbsolutePath() + "\"!");
throw ex;
}
System.out.println("Extracting files from \"minecraft_res_patch.jar\" to \"/desktopRuntime/resources/\"...");
try {
extractJarTo(minecraftResJar, resourcesExtractTo);
}catch(IOException ex) {
System.err.println("ERROR: could not extract \"" + minecraftResJar.getName() + "\" to \"" +
resourcesExtractTo.getAbsolutePath() + "\"!");
throw ex;
}
if(applyPullRequest) {
minecraftJavadocTmp.delete();
minecraftResJar.delete();
}
System.out.println("Extracting files from \"minecraft_languages.zip\" to \"/javascript/lang/\"...");
try {
extractJarTo(mcLanguagesZip, mcLanguagesExtractTo);
}catch(IOException ex) {
System.err.println("ERROR: could not extract \"" + mcLanguagesZip.getName() + "\" to \"" +
mcLanguagesExtractTo.getAbsolutePath() + "\"!");
throw ex;
}
System.out.println("Creating eclipse project for desktop runtime...");
if(!createDesktopRuntimeProject(new File(repoSources, "setup/eclipseProjectFiles"), workspaceDirectory)) {
System.err.println("ERROR: could not create eclipse project for desktop runtime!");
return false;
}
return true;
}
public static int extractJarTo(File in, File out) throws IOException {
int cnt = 0;
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(in))) {
ZipEntry e;
while((e = jarIn.getNextEntry()) != null) {
if(e.isDirectory()) {
continue;
}
String n = e.getName();
if(n.startsWith("/")) {
n = n.substring(1);
}
if(!n.startsWith("META-INF")) {
File o = new File(out, n);
if(!o.exists()) {
File p = o.getParentFile();
if(!p.isDirectory() && !p.mkdirs()) {
throw new IOException("Could not create directory: " + p.getAbsolutePath());
}
try(FileOutputStream os = new FileOutputStream(o)) {
IOUtils.copy(jarIn, os, 4096);
++cnt;
}
}
}
}
}
return cnt;
}
private static boolean createDesktopRuntimeProject(File templateFolderIn, File workspaceDirectory) throws Throwable {
File desktopRuntimeDirectory = new File(workspaceDirectory, "desktopRuntime");
File desktopRuntimeProjectDir = new File(desktopRuntimeDirectory, "eclipseProject");
if(!desktopRuntimeProjectDir.isDirectory() && !desktopRuntimeProjectDir.mkdirs()) {
System.err.println("ERROR: failed to create directory: \"" + desktopRuntimeProjectDir.getAbsolutePath() + "\"!");
return false;
}
File binFolder = new File(desktopRuntimeProjectDir, "bin");
if(!binFolder.isDirectory() && !binFolder.mkdir()) {
System.err.println("ERROR: failed to create directory: \"" + binFolder.getAbsolutePath() + "\"!");
return false;
}
String dotClasspathFile = FileUtils.readFileToString(new File(templateFolderIn, ".classpath"), "UTF-8");
String dotClasspathEntryFile = FileUtils.readFileToString(new File(templateFolderIn, "classpath_entry.txt"), "UTF-8");
String dotProjectFile = FileUtils.readFileToString(new File(templateFolderIn, ".project"), "UTF-8");
String debugRuntimeLaunchConfig = FileUtils.readFileToString(new File(templateFolderIn, "eaglercraftDebugRuntime.launch"), "UTF-8");
String mainClassConfFile = FileUtils.readFileToString(new File(templateFolderIn, "main_class.txt"), "UTF-8");
List<String> classpathEntries = new ArrayList();
File[] flist = desktopRuntimeDirectory.listFiles();
for(int i = 0; i < flist.length; ++i) {
File f = flist[i];
if(f.getName().endsWith(".jar")) {
classpathEntries.add(dotClasspathEntryFile.replace("${JAR_PATH}", bsToS(f.getAbsolutePath())));
}
}
dotClasspathFile = dotClasspathFile.replace("${LIBRARY_CLASSPATH}", String.join(System.lineSeparator(), classpathEntries));
FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, ".classpath"), dotClasspathFile, "UTF-8");
dotProjectFile = dotProjectFile.replace("${LWJGL_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/lwjgl/java")).getAbsolutePath()));
dotProjectFile = dotProjectFile.replace("${MAIN_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/main/java")).getAbsolutePath()));
FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, ".project"), dotProjectFile, "UTF-8");
debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${MAIN_CLASS_FILE}", mainClassConfFile);
String mainClassSubstr = mainClassConfFile.substring(mainClassConfFile.indexOf('/') + 1);
if(mainClassSubstr.endsWith(".java")) {
mainClassSubstr = mainClassSubstr.substring(0, mainClassSubstr.length() - 5);
}
mainClassSubstr = mainClassSubstr.replace('/', '.');
debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${MAIN_CLASS_NAME}", mainClassSubstr);
debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${WORKING_DIRECTORY}", bsToS(desktopRuntimeDirectory.getAbsolutePath()));
FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, "eaglercraftDebugRuntime.launch"), debugRuntimeLaunchConfig, "UTF-8");
File dotSettingsPrefFile = new File(templateFolderIn, "org.eclipse.jdt.core.prefs");
File destDotSettingsFolder = new File(desktopRuntimeProjectDir, ".settings");
if(!destDotSettingsFolder.isDirectory() && !destDotSettingsFolder.mkdir()) {
System.err.println("ERROR: failed to create directory: \"" + destDotSettingsFolder.getAbsolutePath() + "\"!");
return false;
}
FileUtils.copyFile(dotSettingsPrefFile, new File(destDotSettingsFolder, "org.eclipse.jdt.core.prefs"));
return true;
}
private static String bsToS(String in) {
return in.replace('\\', '/');
}
}

View File

@ -0,0 +1,84 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.io.FileUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
public class TaskClean {
public static boolean taskClean() {
try {
return taskClean0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'clean'!");
t.printStackTrace();
return false;
}
}
private static boolean taskClean0() throws Throwable {
File buildToolsTmp = EaglerBuildToolsConfig.getTemporaryDirectory();
File pullRequestTo = new File("pullrequest");
boolean btExist = buildToolsTmp.exists();
boolean prExist = pullRequestTo.exists();
if((btExist && !(buildToolsTmp.isDirectory() && buildToolsTmp.list().length == 0)) ||
(prExist && !(pullRequestTo.isDirectory() && pullRequestTo.list().length == 0))) {
System.out.println();
System.out.println("Notice: Clean will delete the init directory and also");
System.out.println("all of the files in the current pull request");
System.out.println();
System.out.println("you must revert all changes in the 'patches' directory of");
System.out.println("this repo back to the main repository's current commits,");
System.out.println("otherwise the 'pullrequest' command wll not work properly");
System.out.println();
System.out.print("Do you want to clean? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("Ok nice, the clean will be cancelled. (thank god)");
return true;
}else {
try {
if(prExist) {
System.out.println();
System.out.println("Deleting pull request...");
FileUtils.deleteDirectory(pullRequestTo);
prExist = false;
}
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + pullRequestTo.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
try {
if(btExist) {
System.out.println();
System.out.println("Deleting init directory...");
FileUtils.deleteDirectory(buildToolsTmp);
btExist = false;
}
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + buildToolsTmp.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,128 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class TeaVMBridge {
private static URLClassLoader classLoader = null;
/**
* <h3>List of required options:</h3>
* <table>
* <tr><td><b>classPathEntries</b></td><td>-&gt; BuildStrategy.setClassPathEntries(List&lt;String&gt;)</td></tr>
* <tr><td><b>entryPointName</b></td><td>-&gt; BuildStrategy.setEntryPointName(String)</td></tr>
* <tr><td><b>mainClass</b></td><td>-&gt; BuildStrategy.setMainClass(String)</td></tr>
* <tr><td><b>minifying</b></td><td>-&gt; BuildStrategy.setMinifying(boolean)</td></tr>
* <tr><td><b>optimizationLevel</b></td><td>-&gt; BuildStrategy.setOptimizationLevel(TeaVMOptimizationLevel)</td></tr>
* <tr><td><b>generateSourceMaps</b></td><td>-&gt; BuildStrategy.setSourceMapsFileGenerated(boolean)</td></tr>
* <tr><td><b>targetDirectory</b></td><td>-&gt; BuildStrategy.setTargetDirectory(String)</td></tr>
* <tr><td><b>targetFileName</b></td><td>-&gt; BuildStrategy.setTargetFileName(String)</td></tr>
* </table>
* <br>
*/
public static boolean compileTeaVM(Map<String, Object> options) throws TeaVMClassLoadException, TeaVMRuntimeException {
File[] cp = TeaVMBinaries.getTeaVMCompilerClasspath();
URL[] urls = new URL[cp.length];
for(int i = 0; i < cp.length; ++i) {
try {
urls[i] = cp[i].toURI().toURL();
} catch (MalformedURLException e) {
throw new TeaVMClassLoadException("Could not resolve URL for: " + cp[i].getAbsolutePath(), e);
}
}
Method found = null;
try {
if(classLoader == null) {
classLoader = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
}
Class c = classLoader.loadClass("net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridgeImpl");
Method[] methods = c.getDeclaredMethods();
for(int i = 0; i < methods.length; ++i) {
Method m = methods[i];
if(m.getName().equals("compileTeaVM")) {
found = m;
}
}
if(found == null) {
throw new NoSuchMethodException("compileTeaVM");
}
}catch(TeaVMClassLoadException | NoSuchMethodException | ClassNotFoundException t) {
throw new TeaVMClassLoadException("Could not link TeaVM compiler!", t);
}catch(RuntimeException t) {
String msg = t.getMessage();
if(msg.startsWith("[TeaVMBridge]")) {
throw new TeaVMRuntimeException(msg.substring(13).trim(), t.getCause());
}else {
throw new TeaVMRuntimeException("Uncaught exception was thrown!", t);
}
}catch(Throwable t) {
throw new TeaVMRuntimeException("Uncaught exception was thrown!", t);
}
try {
Object ret = found.invoke(null, options);
return ret != null && (ret instanceof Boolean) && ((Boolean)ret).booleanValue();
}catch(InvocationTargetException ex) {
throw new TeaVMRuntimeException("Uncaught exception was thrown!", ex.getCause());
} catch (Throwable t) {
throw new TeaVMRuntimeException("Failed to invoke 'compileTeaVM'!", t);
}
}
public static class TeaVMClassLoadException extends RuntimeException {
public TeaVMClassLoadException(String message, Throwable cause) {
super(message, cause);
}
public TeaVMClassLoadException(String message) {
super(message);
}
}
public static class TeaVMRuntimeException extends RuntimeException {
public TeaVMRuntimeException(String message, Throwable cause) {
super(message, cause);
}
public TeaVMRuntimeException(String message) {
super(message);
}
}
public static void free() {
if(classLoader != null) {
try {
classLoader.close();
classLoader = null;
} catch (IOException e) {
System.err.println("Memory leak, failed to release TeaVM JAR ClassLoader!");
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,28 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FileReaderUTF extends InputStreamReader {
public FileReaderUTF(File file) throws FileNotFoundException {
super(new FileInputStream(file), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,28 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FileWriterUTF extends OutputStreamWriter {
public FileWriterUTF(File file) throws IOException {
super(new FileOutputStream(file), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,116 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class JARSubprocess {
public static final char classPathSeperator;
static {
classPathSeperator = System.getProperty("os.name").toLowerCase().contains("windows") ? ';' : ':';
}
public static int runJava(File directory, String[] javaExeArguments, String logPrefix) throws IOException {
if(logPrefix.length() > 0 && !logPrefix.endsWith(" ")) {
logPrefix = logPrefix + " ";
}
String javaHome = System.getProperty("java.home");
if(classPathSeperator == ';') {
File javaExe = new File(javaHome, "bin/java.exe");
if(!javaExe.isFile()) {
javaExe = new File(javaHome, "java.exe");
if(!javaExe.isFile()) {
throw new IOException("Could not find /bin/java.exe equivelant on java.home! (java.home=" + javaHome + ")");
}
}
javaHome = javaExe.getAbsolutePath();
}else {
File javaExe = new File(javaHome, "bin/java");
if(!javaExe.isFile()) {
javaExe = new File(javaHome, "java");
if(!javaExe.isFile()) {
throw new IOException("Could not find /bin/java equivelant on java.home! (java.home=" + javaHome + ")");
}
}
javaHome = javaExe.getAbsolutePath();
}
String[] fullArgs = new String[javaExeArguments.length + 1];
fullArgs[0] = javaHome;
System.arraycopy(javaExeArguments, 0, fullArgs, 1, javaExeArguments.length);
ProcessBuilder exec = new ProcessBuilder(fullArgs);
exec.directory(directory);
Process ps = exec.start();
InputStream is = ps.getInputStream();
InputStream ise = ps.getErrorStream();
BufferedReader isb = new BufferedReader(new InputStreamReader(is));
BufferedReader iseb = new BufferedReader(new InputStreamReader(ise));
String isbl = "";
String isebl = "";
int maxReadPerLoop = 128;
int c = 0;
do {
boolean tick = false;
c = 0;
while(isb.ready() && (!iseb.ready() || ++c < maxReadPerLoop)) {
char cc = (char)isb.read();
if(cc != '\r') {
if(cc == '\n') {
System.out.println(logPrefix + isbl);
isbl = "";
}else {
isbl += cc;
}
}
tick = true;
}
c = 0;
while(iseb.ready() && (!isb.ready() || ++c < maxReadPerLoop)) {
char cc = (char)iseb.read();
if(cc != '\r') {
if(cc == '\n') {
System.err.println(logPrefix + isebl);
isebl = "";
}else {
isebl += cc;
}
}
tick = true;
}
if(!tick) {
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
}
} while(ps.isAlive());
while(true) {
try {
return ps.waitFor();
} catch (InterruptedException e) {
}
}
}
}