mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2026-10-06 04:42:03 -04:00
Upload sources
This commit is contained in:
1 parent
86083535a8
commit
e1ce65eb29
2887 files changed
+85891
No files matched your search
@@ -0,0 +1,25 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class AccInfo
|
||||
{
|
||||
private String content;
|
||||
public static AccInfo create(String path)
|
||||
{
|
||||
return new AccInfo(path);
|
||||
}
|
||||
private AccInfo(String path)
|
||||
{
|
||||
try
|
||||
{
|
||||
content = Tools.read(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
public String getUuid()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import java.util.*;
|
||||
import org.lwjgl.input.*;
|
||||
import org.lwjgl.opengl.*;
|
||||
|
||||
public class AndroidLWJGLKeycode {
|
||||
private static final Map<Integer, Integer> androidToLwjglMap;
|
||||
static {
|
||||
androidToLwjglMap = new ArrayMap<Integer, Integer>();
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_0, Keyboard.KEY_0);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_1, Keyboard.KEY_1);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_2, Keyboard.KEY_2);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_3, Keyboard.KEY_3);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_4, Keyboard.KEY_4);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_5, Keyboard.KEY_5);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_6, Keyboard.KEY_6);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_7, Keyboard.KEY_7);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_8, Keyboard.KEY_8);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_9, Keyboard.KEY_9);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_A, Keyboard.KEY_A);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_B, Keyboard.KEY_B);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_C, Keyboard.KEY_C);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_D, Keyboard.KEY_D);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_E, Keyboard.KEY_E);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F, Keyboard.KEY_F);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_G, Keyboard.KEY_G);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_H, Keyboard.KEY_H);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_I, Keyboard.KEY_I);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_J, Keyboard.KEY_J);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_K, Keyboard.KEY_K);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_L, Keyboard.KEY_L);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_M, Keyboard.KEY_M);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_N, Keyboard.KEY_M);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_O, Keyboard.KEY_O);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_P, Keyboard.KEY_P);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_Q, Keyboard.KEY_Q);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_R, Keyboard.KEY_R);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_S, Keyboard.KEY_S);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_T, Keyboard.KEY_T);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_U, Keyboard.KEY_U);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_V, Keyboard.KEY_V);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_W, Keyboard.KEY_W);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_X, Keyboard.KEY_X);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_Y, Keyboard.KEY_Y);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_Z, Keyboard.KEY_Z);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_ALT_LEFT, Keyboard.KEY_LMENU);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_ALT_RIGHT, Keyboard.KEY_RMENU);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_BACK, Keyboard.KEY_ESCAPE); // Might not be correctly!
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_BACKSLASH, Keyboard.KEY_BACKSLASH);
|
||||
// androidToLwjglMap.put(KeyEvent.keyCode_del, Keyboard.KEY_DELETE);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_BREAK, Keyboard.KEY_PAUSE);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_CAPS_LOCK, Keyboard.KEY_CAPITAL);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_COMMA, Keyboard.KEY_COMMA);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_CTRL_LEFT, Keyboard.KEY_LCONTROL);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_CTRL_RIGHT, Keyboard.KEY_RCONTROL);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_DEL, Keyboard.KEY_BACK); // Backspace
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_ENTER, Keyboard.KEY_RETURN);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_EQUALS, Keyboard.KEY_EQUALS);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_ESCAPE, Keyboard.KEY_ESCAPE);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F1, Keyboard.KEY_F1);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F2, Keyboard.KEY_F2);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F3, Keyboard.KEY_F3);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F4, Keyboard.KEY_F4);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F5, Keyboard.KEY_F5);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F6, Keyboard.KEY_F6);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F7, Keyboard.KEY_F7);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F8, Keyboard.KEY_F8);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F9, Keyboard.KEY_F9);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F10, Keyboard.KEY_F10);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F11, Keyboard.KEY_F11);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_F12, Keyboard.KEY_F12);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_FUNCTION, Keyboard.KEY_FUNCTION);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_FORWARD, Keyboard.KEY_UP); // Might not be correctly;
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_GRAVE, Keyboard.KEY_GRAVE);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_HOME, Keyboard.KEY_HOME);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_INSERT, Keyboard.KEY_INSERT);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_KANA, Keyboard.KEY_KANA);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_LEFT_BRACKET, Keyboard.KEY_LBRACKET);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_MINUS, Keyboard.KEY_MINUS);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUM_LOCK, Keyboard.KEY_NUMLOCK);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_0, Keyboard.KEY_NUMPAD0);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_1, Keyboard.KEY_NUMPAD1);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_2, Keyboard.KEY_NUMPAD2);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_3, Keyboard.KEY_NUMPAD3);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_4, Keyboard.KEY_NUMPAD4);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_5, Keyboard.KEY_NUMPAD5);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_6, Keyboard.KEY_NUMPAD6);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_7, Keyboard.KEY_NUMPAD7);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_8, Keyboard.KEY_NUMPAD8);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_9, Keyboard.KEY_NUMPAD9);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ENTER, Keyboard.KEY_NUMPADENTER);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_EQUALS, Keyboard.KEY_NUMPADEQUALS);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_COMMA, Keyboard.KEY_NUMPADCOMMA);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ADD, Keyboard.KEY_ADD);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE, Keyboard.KEY_DIVIDE);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_DOT, Keyboard.KEY_PERIOD);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, Keyboard.KEY_MULTIPLY);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, Keyboard.KEY_SUBTRACT);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_PAGE_DOWN, Keyboard.KEY_NEXT);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_PAGE_UP, Keyboard.KEY_PRIOR);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_PERIOD, Keyboard.KEY_PERIOD);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_PLUS, Keyboard.KEY_ADD);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_POWER, Keyboard.KEY_POWER);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_RIGHT_BRACKET, Keyboard.KEY_RBRACKET);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SEMICOLON, Keyboard.KEY_SEMICOLON);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SHIFT_LEFT, Keyboard.KEY_LSHIFT);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SHIFT_RIGHT, Keyboard.KEY_RSHIFT);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SLASH, Keyboard.KEY_SLASH);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SLEEP, Keyboard.KEY_SLEEP);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SPACE, Keyboard.KEY_SPACE);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_SYSRQ, Keyboard.KEY_SYSRQ);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_TAB, Keyboard.KEY_TAB);
|
||||
androidToLwjglMap.put(KeyEvent.KEYCODE_YEN, Keyboard.KEY_YEN);
|
||||
}
|
||||
|
||||
public static void execKey(MainActivity mainActivity, KeyEvent keyEvent, int i, boolean isDown) {
|
||||
for (Map.Entry<Integer, Integer> perKey : androidToLwjglMap.entrySet()) {
|
||||
if (perKey.getKey() == i) {
|
||||
mainActivity.sendKeyPress(perKey.getValue(), isDown);
|
||||
}
|
||||
}
|
||||
|
||||
if (!AndroidDisplay.grab) {
|
||||
try {
|
||||
// Old method works without dead chars:
|
||||
if (isDown) {
|
||||
mainActivity.sendKeyPress((char) keyEvent.getUnicodeChar());
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class ArchitectureCheck
|
||||
{
|
||||
public static String getArch() {
|
||||
String arch = System.getProperty("os.arch");
|
||||
String archConverted = null;
|
||||
|
||||
if (arch.equals("aarch64") ||
|
||||
arch.endsWith("v8a") ||
|
||||
arch.startsWith("arm64")) {
|
||||
archConverted = "arm64";
|
||||
} else if (arch.startsWith("arm") || arch.endsWith("v7a")) {
|
||||
archConverted = "arm32";
|
||||
} else if (arch.startsWith("x86") || arch.startsWith("amd")) {
|
||||
archConverted = "x86";
|
||||
}
|
||||
|
||||
return archConverted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.support.annotation.*;
|
||||
|
||||
public abstract class AsyncThread<Params, Progress, Result> extends Thread
|
||||
{
|
||||
private boolean isCancelled = true;
|
||||
|
||||
@WorkerThread
|
||||
protected abstract Result doInBackground(Params... params);
|
||||
|
||||
@MainThread
|
||||
protected void onPreExecute() {}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
@MainThread
|
||||
protected void onPostExecute(Result result) {}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
@MainThread
|
||||
protected void onProgressUpdate(Progress... values) {}
|
||||
|
||||
@SuppressWarnings({"UnusedParameters"})
|
||||
@MainThread
|
||||
protected void onCancelled(Result result) {
|
||||
onCancelled();
|
||||
}
|
||||
|
||||
@MainThread
|
||||
protected void onCancelled() {}
|
||||
|
||||
public final boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
public final boolean cancel() {
|
||||
super.stop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class CancelException extends RuntimeException
|
||||
{
|
||||
@Override
|
||||
public CancelException() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CancelException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class ClassesNotFoundException extends ClassNotFoundException
|
||||
{
|
||||
private static String mMessage = "Failed to find a class from classes list";
|
||||
public ClassesNotFoundException()
|
||||
{
|
||||
super(mMessage);
|
||||
}
|
||||
public ClassesNotFoundException(String message)
|
||||
{
|
||||
super(message + ":" + mMessage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.text.method.*;
|
||||
import android.view.*;
|
||||
import android.view.inputmethod.*;
|
||||
import org.lwjgl.opengl.*;
|
||||
import org.lwjgl.input.*;
|
||||
|
||||
public class DroidToJavaKey {
|
||||
private static StringBuilder mComposing = new StringBuilder();
|
||||
private static long mMetaState;
|
||||
|
||||
public static void execKey(MainActivity mainActivity, KeyEvent keyEvent, int i, boolean status) {
|
||||
/*
|
||||
if (i >= KeyEvent.KEYCODE_F1 && i <= KeyEvent.KEYCODE_F12) {
|
||||
mainActivity.sendKeyPress(i - 72, status);
|
||||
} else if (i == KeyEvent.KEYCODE_DEL) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_DELETE, status);
|
||||
} else if (i == KeyEvent.KEYCODE_ENTER) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_RETURN, status);
|
||||
} else if (i == KeyEvent.KEYCODE_SHIFT_LEFT) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_LSHIFT, status);
|
||||
} else if (i == KeyEvent.KEYCODE_SHIFT_RIGHT) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_RSHIFT, status);
|
||||
} else if (i == KeyEvent.KEYCODE_DPAD_LEFT) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_LEFT, status);
|
||||
} else if (i == KeyEvent.KEYCODE_DPAD_UP) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_UP, status);
|
||||
} else if (i == keyEvent.KEYCODE_DPAD_RIGHT) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_RIGHT, status);
|
||||
} else if (i == KeyEvent.KEYCODE_DPAD_DOWN) {
|
||||
mainActivity.sendKeyPress(Keyboard.KEY_DOWN, status);
|
||||
} else if (i >= KeyEvent.KEYCODE_BUTTON_1 && i <= KeyEvent.KEYCODE_BUTTON_16) {
|
||||
mainActivity.sendKeyPress(i - 188, status);
|
||||
}
|
||||
|
||||
if (!AndroidDisplay.grab) {
|
||||
try {
|
||||
// Old method works without dead chars:
|
||||
mainActivity.sendKeyPress(keyEvent.getDisplayLabel(), status);
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
mainActivity.sendKeyPress(keyEvent.getDisplayLabel(), status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import java.security.*;
|
||||
import java.util.*;
|
||||
|
||||
public class FakeAccount
|
||||
{
|
||||
public static String[] generate()
|
||||
{
|
||||
String[] arr = {
|
||||
UUID.randomUUID().toString(),
|
||||
new RandomString(32).nextString()
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
private static class RandomString {
|
||||
|
||||
/**
|
||||
* Generate a random string.
|
||||
*/
|
||||
public String nextString() {
|
||||
for (int idx = 0; idx < buf.length; ++idx)
|
||||
buf[idx] = symbols[random.nextInt(symbols.length)];
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
public static final String lower = upper.toLowerCase(Locale.ROOT);
|
||||
|
||||
public static final String digits = "0123456789";
|
||||
|
||||
public static final String alphanum = upper + lower + digits;
|
||||
|
||||
private final Random random;
|
||||
|
||||
private final char[] symbols;
|
||||
|
||||
private final char[] buf;
|
||||
|
||||
public RandomString(int length, Random random, String symbols) {
|
||||
if (length < 1) throw new IllegalArgumentException();
|
||||
if (symbols.length() < 2) throw new IllegalArgumentException();
|
||||
this.random = Objects.requireNonNull(random);
|
||||
this.symbols = symbols.toCharArray();
|
||||
this.buf = new char[length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alphanumeric string generator.
|
||||
*/
|
||||
public RandomString(int length, Random random) {
|
||||
this(length, random, alphanum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alphanumeric strings from a secure generator.
|
||||
*/
|
||||
public RandomString(int length) {
|
||||
this(length, new SecureRandom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create session identifiers.
|
||||
*/
|
||||
public RandomString() {
|
||||
this(21);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import dalvik.system.*;
|
||||
|
||||
public class FakeURLClassLoader extends URLClassLoader
|
||||
{
|
||||
private DexClassLoader m;
|
||||
public FakeURLClassLoader(java.lang.String dexPath, java.lang.String optimizedDirectory, java.lang.String librarySearchPath, java.lang.ClassLoader parent) throws MalformedURLException {
|
||||
super(new URL[] { new File("test.jar").toURI().toURL() }, null);
|
||||
|
||||
m = new DexClassLoader(dexPath, optimizedDirectory, librarySearchPath, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String findLibrary(String name) {
|
||||
return m.findLibrary(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
return m.loadClass(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.content.res.*;
|
||||
import android.graphics.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
|
||||
public class FontChanger
|
||||
{
|
||||
private Typeface typeface;
|
||||
|
||||
public FontChanger(Typeface typeface)
|
||||
{
|
||||
this.typeface = typeface;
|
||||
}
|
||||
|
||||
public FontChanger(AssetManager assets, String assetsFontFileName)
|
||||
{
|
||||
typeface = Typeface.createFromAsset(assets, assetsFontFileName);
|
||||
}
|
||||
|
||||
public ViewGroup replaceFonts(ViewGroup viewTree)
|
||||
{
|
||||
View child;
|
||||
for(int i = 0; i < viewTree.getChildCount(); ++i)
|
||||
{
|
||||
child = viewTree.getChildAt(i);
|
||||
if(child instanceof ViewGroup)
|
||||
{
|
||||
// recursive call
|
||||
replaceFonts((ViewGroup)child);
|
||||
}
|
||||
else if(child instanceof TextView)
|
||||
{
|
||||
// base case
|
||||
replaceFont((TextView) child);
|
||||
}
|
||||
}
|
||||
return viewTree;
|
||||
}
|
||||
|
||||
public View replaceFont(TextView view) {
|
||||
view.setTypeface(typeface);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import android.os.*;
|
||||
|
||||
public class InstallerTask extends AsyncTask<String, Void, String>
|
||||
{
|
||||
@Override
|
||||
protected String doInBackground(String[] p1)
|
||||
{
|
||||
try
|
||||
{
|
||||
downloadLibraries(p1[0]);
|
||||
dexMinecraftLibs();
|
||||
downloadMinecraft(p1[0]);
|
||||
dexMinecraftClient(p1[0]);
|
||||
downloadAssets(p1[0]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.getMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(String result)
|
||||
{
|
||||
super.onPostExecute(result);
|
||||
|
||||
if(result == null){
|
||||
//No errors
|
||||
}
|
||||
}
|
||||
private void downloadLibraries(String versionName) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void dexMinecraftLibs() throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void downloadMinecraft(String versionName) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void dexMinecraftClient(String version) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
private void downloadAssets(String versionName) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class JAssetInfo
|
||||
{
|
||||
public String hash;
|
||||
public int size;
|
||||
//public String objects;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class JAssets {
|
||||
public Map<String, JAssetInfo> objects;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class JMinecraftVersionList {
|
||||
public static final String TYPE_OLD_ALPHA = "old_alpha";
|
||||
public static final String TYPE_OLD_BETA = "old_beta";
|
||||
public static final String TYPE_RELEASE = "release";
|
||||
public static final String TYPE_SNAPSHOT = "snapshot";
|
||||
public Map<String, String> latest;
|
||||
public Version[] versions;
|
||||
|
||||
public static class Version extends OfflineVersion {
|
||||
public String url;
|
||||
}
|
||||
|
||||
public static class OfflineVersion {
|
||||
public String id;
|
||||
public String releaseTime;
|
||||
public String time;
|
||||
public String type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class JVersion extends Object
|
||||
{
|
||||
private String version;
|
||||
private JVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
public static JVersion from(String version)
|
||||
{
|
||||
return new JVersion(version);
|
||||
}
|
||||
public boolean isVersionCode()
|
||||
{
|
||||
return !version.contains(".");
|
||||
}
|
||||
public JVersion toVersionCode()
|
||||
{
|
||||
if(!isVersionCode()){
|
||||
version = version.replace(".", "");
|
||||
return this;
|
||||
} else throw new RuntimeException("Can't convert version code to itself");
|
||||
}
|
||||
public JVersion toVersionName()
|
||||
{
|
||||
if(isVersionCode()){
|
||||
StringBuilder charList = new StringBuilder();
|
||||
for(int i=0; i<version.length(); i++){
|
||||
charList.append(version.substring(i, i+1));
|
||||
if(i != version.length() - 1){
|
||||
charList.append(".");
|
||||
}
|
||||
}
|
||||
version = charList.toString();
|
||||
return this;
|
||||
} else throw new RuntimeException("Can't convert version name to itself");
|
||||
}
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import dalvik.system.*;
|
||||
|
||||
public class LaunchClassLoaderAgruments
|
||||
{
|
||||
public static String launchDexPath, launchOptimizedDirectory, launchLibrarySearchPath;
|
||||
|
||||
public static void putAll(String dexPath, String optimizedDirectory, String librarySearchPath) {
|
||||
launchDexPath = dexPath;
|
||||
launchOptimizedDirectory = optimizedDirectory;
|
||||
launchLibrarySearchPath = librarySearchPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import java.io.*;
|
||||
|
||||
public class LoggerJava
|
||||
{
|
||||
public static interface OnCharPrintListener {
|
||||
public void onCharPrint(char c);
|
||||
}
|
||||
|
||||
public static class LoggerOutputStream extends FilterOutputStream
|
||||
{
|
||||
private OnCharPrintListener mListener;
|
||||
public LoggerOutputStream(OutputStream out, OnCharPrintListener listener)
|
||||
{
|
||||
super(out);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final int charCode) throws IOException
|
||||
{
|
||||
super.write(charCode);
|
||||
mListener.onCharPrint((char) charCode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,183 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import com.kdt.mojangauth.*;
|
||||
import java.io.*;
|
||||
|
||||
public class MCProfile
|
||||
{
|
||||
private static String[] emptyBuilder = new String[]{
|
||||
"1.9", //Version
|
||||
"ProfileIDEmpty",
|
||||
"AccessToken",
|
||||
"AccessTokenEmpty",
|
||||
"Steve"
|
||||
};
|
||||
|
||||
public static void launch(Activity ctx, Object o)
|
||||
{
|
||||
PojavProfile.setCurrentProfile(ctx, o);
|
||||
|
||||
Intent intent = new Intent(ctx, PojavV2ActivityManager.getLauncherRemakeVer(ctx)); //MCLauncherActivity.class);
|
||||
ctx.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void updateTokens(final Activity ctx, final String pofFilePath, RefreshListener listen) throws Exception
|
||||
{
|
||||
new RefreshTokenTask(ctx, listen).execute(pofFilePath);
|
||||
}
|
||||
|
||||
public static String build(MCProfile.Builder builder)
|
||||
{
|
||||
//System.out.println("build THE VER = " + builder.getVersion());
|
||||
|
||||
try {
|
||||
byte[] bFull = toString(builder).getBytes("UTF-8");
|
||||
Tools.write(Tools.mpProfiles + "/" + builder.getUsername(), bFull);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return Tools.mpProfiles + "/" + builder.getUsername();
|
||||
}
|
||||
|
||||
public static MCProfile.Builder load(String pofFilePath)
|
||||
{
|
||||
try {
|
||||
//String th = new String(new byte[]{-128});
|
||||
String pofContent = Tools.read(pofFilePath);
|
||||
return parse(pofContent);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to load Profile " + pofFilePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static MCProfile.Builder parse(String content) {
|
||||
MCProfile.Builder builder = new MCProfile.Builder();
|
||||
|
||||
String[] profileInfos = content.split(":");
|
||||
|
||||
String cltk = profileInfos[0];
|
||||
String prtk = profileInfos[1];
|
||||
String acct = profileInfos[2];
|
||||
String name = profileInfos[3];
|
||||
String vers = profileInfos[4];
|
||||
String isAc = profileInfos[5];
|
||||
|
||||
//System.out.println("parse THE VER = " + vers);
|
||||
|
||||
builder.setClientID(cltk);
|
||||
builder.setProfileID(prtk);
|
||||
builder.setAccessToken(acct);
|
||||
builder.setUsername(name);
|
||||
builder.setVersion(vers);
|
||||
builder.setIsAccount(Boolean.parseBoolean(isAc));
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static MCProfile.Builder loadSafety(String pofFilePath) {
|
||||
try {
|
||||
return load(pofFilePath);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
// return new MCProfile.Builder();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString(String pofFilePath) {
|
||||
return toString(load(pofFilePath));
|
||||
}
|
||||
|
||||
public static String toString(MCProfile.Builder builder) {
|
||||
//System.out.println("TOSTRING THE VER = " + builder.getVersion());
|
||||
|
||||
return
|
||||
builder.getClientID() + ":" +
|
||||
builder.getProfileID() + ":" +
|
||||
builder.getAccessToken() + ":" +
|
||||
builder.getUsername() + ":" +
|
||||
builder.getVersion() + ":" +
|
||||
Boolean.toString(builder.isAccount());
|
||||
}
|
||||
|
||||
public static class Builder implements Serializable
|
||||
{
|
||||
private String[] fullArgs = new String[6];
|
||||
private boolean isAccount = true;
|
||||
|
||||
public Builder()
|
||||
{
|
||||
fullArgs = emptyBuilder;
|
||||
String[] fakeTokens = FakeAccount.generate();
|
||||
setClientID(fakeTokens[0]);
|
||||
setProfileID(FakeAccount.generate()[0].replace("-", ""));
|
||||
setAccessToken(fakeTokens[1]);
|
||||
}
|
||||
|
||||
public boolean isAccount()
|
||||
{
|
||||
return isAccount;
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return fullArgs[0];
|
||||
}
|
||||
|
||||
public String getClientID()
|
||||
{
|
||||
return fullArgs[1];
|
||||
}
|
||||
|
||||
public String getProfileID()
|
||||
{
|
||||
return fullArgs[2];
|
||||
}
|
||||
|
||||
public String getAccessToken()
|
||||
{
|
||||
return fullArgs[3];
|
||||
}
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return fullArgs[4];
|
||||
}
|
||||
|
||||
public void setIsAccount(boolean value)
|
||||
{
|
||||
isAccount = value;
|
||||
}
|
||||
|
||||
public void setVersion(String value)
|
||||
{
|
||||
fullArgs[0] = value;
|
||||
}
|
||||
|
||||
public void setClientID(String value)
|
||||
{
|
||||
fullArgs[1] = value;
|
||||
}
|
||||
|
||||
public void setProfileID(String value)
|
||||
{
|
||||
fullArgs[2] = value;
|
||||
}
|
||||
|
||||
public void setAccessToken(String value)
|
||||
{
|
||||
fullArgs[3] = value;
|
||||
}
|
||||
|
||||
public void setUsername(String value)
|
||||
{
|
||||
fullArgs[4] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,48 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.content.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import com.kdt.glsupport.*;
|
||||
|
||||
public class MinecraftGLView extends GLTextureView
|
||||
{
|
||||
private View.OnTouchListener mTouchListener;
|
||||
public MinecraftGLView(Context context) {
|
||||
super(context);
|
||||
//setPreserveEGLContextOnPause(true);
|
||||
}
|
||||
|
||||
public MinecraftGLView(Context context, AttributeSet attributeSet) {
|
||||
super(context, attributeSet);
|
||||
//setPreserveEGLContextOnPause(true);
|
||||
}
|
||||
/*
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
|
||||
//super.surfaceDestroyed(surfaceHolder);
|
||||
System.out.println("Surface destroyed!");
|
||||
//new Throwable("Surface destroyed!").printStackTrace();
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
public void setOnTouchListener(View.OnTouchListener l)
|
||||
{
|
||||
super.setOnTouchListener(l);
|
||||
mTouchListener = l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClickListener(View.OnClickListener l)
|
||||
{
|
||||
super.setOnClickListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCapturedPointerEvent(MotionEvent event)
|
||||
{
|
||||
mTouchListener.onTouch(this, event);
|
||||
return super.onCapturedPointerEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
public class MultidojManager
|
||||
{
|
||||
private static Listen li;
|
||||
|
||||
public static interface Listen {
|
||||
public void onReceived(String msg, int max, int current);
|
||||
}
|
||||
|
||||
public static void setListener(Listen l) {
|
||||
li = l;
|
||||
}
|
||||
|
||||
public static void call(String msg, int max, int current) {
|
||||
if (li != null) li.onReceived(msg, max, current);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.app.Application;
|
||||
import android.os.*;
|
||||
import android.content.pm.PackageManager.*;
|
||||
import android.content.pm.*;
|
||||
|
||||
public class PojavApplication extends Application
|
||||
{
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
try {
|
||||
Tools.APP_NAME = getResources().getString(R.string.app_short_name);
|
||||
|
||||
PackageInfo thisApp = getPackageManager().getPackageInfo(getPackageName(), 0);
|
||||
|
||||
Tools.usingVerName = thisApp.versionName;
|
||||
Tools.usingVerCode = thisApp.versionCode;
|
||||
Tools.mainpath = getDir("files", MODE_PRIVATE).getParent();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,618 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.*;
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.content.pm.*;
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.support.v4.app.*;
|
||||
import android.support.v4.content.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import com.kdt.filermod.*;
|
||||
import com.kdt.mcgui.app.*;
|
||||
import com.kdt.mojangauth.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import android.widget.CompoundButton.*;
|
||||
import android.text.method.*;
|
||||
import android.system.*;
|
||||
import android.net.*;
|
||||
import static android.view.ViewGroup.LayoutParams.*;
|
||||
|
||||
public class PojavLoginActivity extends MineActivity
|
||||
{
|
||||
private EditText edit2, edit3;
|
||||
private int REQUEST_STORAGE_REQUEST_CODE = 1;
|
||||
private ProgressBar prb;
|
||||
private Switch sRemember, sOffline;
|
||||
|
||||
private boolean isPromptingGrant = false;
|
||||
// private boolean isPermGranted = false;
|
||||
|
||||
private SharedPreferences firstLaunchPrefs;
|
||||
private String PREF_IS_DONOTSHOWAGAIN_WARN = "isWarnDoNotShowAgain";
|
||||
private String PREF_IS_INSTALLED_LIBRARIES = "isLibrariesExtracted";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState, false);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
firstLaunchPrefs = getSharedPreferences("pojav_extract", MODE_PRIVATE);
|
||||
new File(Tools.mpProfiles).mkdir();
|
||||
|
||||
if (isAndroid7() && !firstLaunchPrefs.getBoolean(PREF_IS_DONOTSHOWAGAIN_WARN, false)) {
|
||||
AlertDialog.Builder startDlg = new AlertDialog.Builder(PojavLoginActivity.this);
|
||||
startDlg.setTitle(R.string.warning_title);
|
||||
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
|
||||
|
||||
LinearLayout conLay = new LinearLayout(this);
|
||||
conLay.setLayoutParams(params);
|
||||
conLay.setOrientation(LinearLayout.VERTICAL);
|
||||
TextView conText = new TextView(this);
|
||||
conText.setText(R.string.warning_msg);
|
||||
conText.setLayoutParams(params);
|
||||
final CheckBox conCheck = new CheckBox(this);
|
||||
conCheck.setText(R.string.warning_noshowagain);
|
||||
conCheck.setLayoutParams(params);
|
||||
conLay.addView(conCheck);
|
||||
|
||||
conLay.addView(conText);
|
||||
|
||||
startDlg.setView(conLay);
|
||||
startDlg.setCancelable(false);
|
||||
startDlg.setPositiveButton(R.string.warning_action_install, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
setPref(PREF_IS_DONOTSHOWAGAIN_WARN, conCheck.isChecked());
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse("market://details?id=com.vmos.glb"));
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
startDlg.setNegativeButton(R.string.warning_action_tryanyway, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
setPref(PREF_IS_DONOTSHOWAGAIN_WARN, conCheck.isChecked());
|
||||
|
||||
new InitTask().execute();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
startDlg.setNeutralButton(R.string.warning_action_exit, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
startDlg.show();
|
||||
} else {
|
||||
new InitTask().execute();
|
||||
}
|
||||
}
|
||||
|
||||
private class InitTask extends AsyncTask<Void, String, Integer>{
|
||||
private AlertDialog startAle;
|
||||
private ProgressBar progress;
|
||||
|
||||
private ProgressBar progressSpin;
|
||||
private EditText progressLog;
|
||||
private AlertDialog progDlg;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute()
|
||||
{
|
||||
LinearLayout startScr = new LinearLayout(PojavLoginActivity.this);
|
||||
LayoutInflater.from(PojavLoginActivity.this).inflate(R.layout.start_screen, startScr);
|
||||
|
||||
replaceFonts(startScr);
|
||||
|
||||
progress = (ProgressBar) startScr.findViewById(R.id.startscreenProgress);
|
||||
//startScr.addView(progress);
|
||||
|
||||
AlertDialog.Builder startDlg = new AlertDialog.Builder(PojavLoginActivity.this, R.style.AppTheme);
|
||||
startDlg.setView(startScr);
|
||||
startDlg.setCancelable(false);
|
||||
|
||||
startAle = startDlg.create();
|
||||
startAle.show();
|
||||
startAle.getWindow().setLayout(
|
||||
WindowManager.LayoutParams.MATCH_PARENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
}
|
||||
|
||||
private int revokeCount = -1;
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void[] p1)
|
||||
{
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {}
|
||||
|
||||
publishProgress("visible");
|
||||
|
||||
while (Build.VERSION.SDK_INT >= 23 && !isStorageAllowed()){
|
||||
try {
|
||||
revokeCount++;
|
||||
if (revokeCount >= 3) {
|
||||
Toast.makeText(PojavLoginActivity.this, R.string.toast_permission_denied, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
isPromptingGrant = true;
|
||||
requestStoragePermission();
|
||||
while (isPromptingGrant) {
|
||||
Thread.sleep(200);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
|
||||
initMain();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(String... obj)
|
||||
{
|
||||
|
||||
if (obj[0].equals("visible")) {
|
||||
progress.setVisibility(View.VISIBLE);
|
||||
} else if (obj.length == 2 && obj[1] != null) {
|
||||
progressLog.append(obj[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer obj) {
|
||||
startAle.dismiss();
|
||||
if (progressSpin != null) progressSpin.setVisibility(View.GONE);
|
||||
if (obj == 0) {
|
||||
if (progDlg != null) progDlg.dismiss();
|
||||
uiInit();
|
||||
} else if (progressLog != null) {
|
||||
progressLog.setText(getResources().getString(R.string.error_checklog, "\n\n" + progressLog.getText()));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
private void appendlnToLog(String txt) {
|
||||
publishProgress("", txt + "\n");
|
||||
}
|
||||
|
||||
private void execCmd(String cmd) throws Exception {
|
||||
appendlnToLog("> " + cmd);
|
||||
ShellProcessOperation mainProcess = new ShellProcessOperation(new ShellProcessOperation.OnPrintListener(){
|
||||
|
||||
@Override
|
||||
public void onPrintLine(String text)
|
||||
{
|
||||
publishProgress(text);
|
||||
}
|
||||
}, cmd);
|
||||
mainProcess.initInputStream(MCLoginActivity.this);
|
||||
String msgExit = cmd.split(" ")[0] + " has exited with code " + mainProcess.waitFor();
|
||||
if (mainProcess.exitCode() != 0) {
|
||||
throw new Error("(ERROR) " + msgExit);
|
||||
} else {
|
||||
appendlnToLog("(SUCCESS) " + msgExit);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private void uiInit() {
|
||||
setContentView(R.layout.launcher_login);
|
||||
|
||||
edit2 = (EditText) findViewById(R.id.launcherAccEmail);
|
||||
edit3 = (EditText) findViewById(R.id.launcherAccPassword);
|
||||
if(prb == null) prb = (ProgressBar) findViewById(R.id.launcherAccProgress);
|
||||
|
||||
sRemember = (Switch) findViewById(R.id.launcherAccRememberSwitch);
|
||||
sOffline = (Switch) findViewById(R.id.launcherAccOffSwitch);
|
||||
sOffline.setOnCheckedChangeListener(new OnCheckedChangeListener(){
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton p1, boolean p2)
|
||||
{
|
||||
// May delete later
|
||||
edit3.setEnabled(!p2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isAndroid7()
|
||||
{
|
||||
return Build.VERSION.SDK_INT >= 24;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
long lastTime = System.currentTimeMillis();
|
||||
long lastDel = 0;
|
||||
|
||||
|
||||
private void deAnr(String msg) {
|
||||
long currt = System.currentTimeMillis();
|
||||
lastDel = currt - lastTime;
|
||||
lastTime = currt;
|
||||
System.out.println("Time:" + lastDel + "ms||" + (lastDel / 1000) + "s: " + msg);
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Clear current profile
|
||||
PojavProfile.setCurrentProfile(this, null);
|
||||
}
|
||||
/*
|
||||
private boolean isOpenJDKInstalled() {
|
||||
return firstLaunchPrefs.getBoolean(PREF_IS_INSTALLED_OPENJDK, false);
|
||||
}
|
||||
*/
|
||||
private boolean isLibrariesExtracted() {
|
||||
return firstLaunchPrefs.getBoolean(PREF_IS_INSTALLED_LIBRARIES, false);
|
||||
}
|
||||
|
||||
private boolean setPref(String prefName, boolean value) {
|
||||
return firstLaunchPrefs.edit().putBoolean(prefName, value).commit();
|
||||
}
|
||||
|
||||
private void initMain()
|
||||
{
|
||||
File file0 = new File(Tools.mpProfiles);
|
||||
File file1 = new File(Tools.mpModEnable);
|
||||
File file2 = new File(Tools.mpModDisable);
|
||||
File file3 = new File(Tools.mpModAddNewMo);
|
||||
|
||||
file0.mkdir();
|
||||
file1.mkdirs();
|
||||
file2.mkdir();
|
||||
try {
|
||||
file3.createNewFile();
|
||||
} catch (IOException e){}
|
||||
|
||||
try {
|
||||
mkdirs(Tools.MAIN_PATH);
|
||||
|
||||
Tools.copyAssetOptional(this, "options.txt", Tools.MAIN_PATH + "/gamedir");
|
||||
//Tools.copyAssetToFolderIfNonExist(this, "dx-f" + (isAndroid7() ? "7" : "4") + ".0.jar", Tools.worksDir, "dx.jar");
|
||||
Tools.copyAssetOptional(this, "multidoj.dex", Tools.worksDir);
|
||||
|
||||
// Copy ZIP!!!
|
||||
|
||||
//FileAccess.copyAssetToFolderIfNonExist(this, "1.0.jar", Tools.versnDir + "/1.0");
|
||||
//FileAccess.copyAssetToFolderIfNonExist(this, "1.7.3.jar", Tools.versnDir + "/1.7.3");
|
||||
//FileAccess.copyAssetToFolderIfNonExist(this, "1.7.10.jar", Tools.versnDir + "/1.7.10");
|
||||
|
||||
// Extract libraries
|
||||
if (!isLibrariesExtracted()) {
|
||||
mkdirs(Tools.worksDir);
|
||||
mkdirs(Tools.versnDir);
|
||||
|
||||
Tools.extractAssetFolder(this, "libraries", Tools.worksDir);
|
||||
|
||||
setPref(PREF_IS_INSTALLED_LIBRARIES, true);
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
Tools.showError(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mkdirs(String path)
|
||||
{
|
||||
File mFileeee = new File(path);
|
||||
if(mFileeee.getParentFile().exists())
|
||||
return mFileeee.mkdir();
|
||||
else return mFileeee.mkdirs();
|
||||
}
|
||||
|
||||
/*
|
||||
public void loginUsername(View view)
|
||||
{
|
||||
LinearLayout mainLaun = new LinearLayout(this);
|
||||
LayoutInflater.from(this).inflate(R.layout.launcher_user, mainLaun, true);
|
||||
replaceFonts(mainLaun);
|
||||
|
||||
//edit1 = mainLaun.findViewById(R.id.launcherAccUsername);
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Register with username")
|
||||
.setView(mainLaun)
|
||||
.show();
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
// developer methods
|
||||
// end dev methods
|
||||
public void loginSavedAcc(View view)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.login_select_account);
|
||||
|
||||
if (Tools.enableDevFeatures) {
|
||||
/*
|
||||
builder.setNegativeButton("Toggle v2", new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
int ver = PojavV2ActivityManager.getLauncherRemakeInt(MCLoginActivity.this) == 0 ? 1 : 0;
|
||||
PojavV2ActivityManager.setLauncherRemakeVer(MCLoginActivity.this, ver);
|
||||
Toast.makeText(MCLoginActivity.this, "Changed to use v" + (ver + 1), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
builder.setPositiveButton(android.R.string.cancel, null);
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
|
||||
/*
|
||||
LinearLayout.LayoutParams lpHint, lpFlv;
|
||||
|
||||
lpHint = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lpFlv = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
lpHint.weight = 1;
|
||||
lpFlv.weight = 1;
|
||||
*/
|
||||
LinearLayout dialay = new LinearLayout(this);
|
||||
dialay.setOrientation(LinearLayout.VERTICAL);
|
||||
TextView fhint = new TextView(this);
|
||||
fhint.setText(R.string.hint_select_account);
|
||||
// fhint.setLayoutParams(lpHint);
|
||||
|
||||
final MFileListView flv = new MFileListView(this, dialog);
|
||||
// flv.setLayoutParams(lpFlv);
|
||||
|
||||
flv.listFileAt(Tools.mpProfiles);
|
||||
flv.setFileSelectedListener(new MFileSelectedListener(){
|
||||
|
||||
@Override
|
||||
public void onFileLongClick(final File file, String path, String name, String extension)
|
||||
{
|
||||
AlertDialog.Builder builder2 = new AlertDialog.Builder(PojavLoginActivity.this);
|
||||
builder2.setTitle(name);
|
||||
builder2.setMessage(R.string.warning_remove_account);
|
||||
builder2.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
// TODO: Implement this method
|
||||
file.delete();
|
||||
flv.refreshPath();
|
||||
}
|
||||
});
|
||||
builder2.setNegativeButton(android.R.string.cancel, null);
|
||||
builder2.show();
|
||||
}
|
||||
@Override
|
||||
public void onFileSelected(File file, final String path, String nane, String extension)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(MCProfile.load(path).isAccount()){
|
||||
MCProfile.updateTokens(PojavLoginActivity.this, path, new RefreshListener(){
|
||||
|
||||
@Override
|
||||
public void onFailed(Throwable e)
|
||||
{
|
||||
Tools.showError(PojavLoginActivity.this, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess()
|
||||
{
|
||||
MCProfile.launch(PojavLoginActivity.this, path);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
MCProfile.launch(PojavLoginActivity.this, path);
|
||||
}
|
||||
|
||||
dialog.hide();
|
||||
//Tools.throwError(MCLoginActivity.this, new Exception(builder.getAccessToken() + "," + builder.getUUID() + "," + builder.getNickname() + "," + builder.getEmail() + "," + builder.getPassword()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Tools.showError(PojavLoginActivity.this, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
dialay.addView(fhint);
|
||||
dialay.addView(flv);
|
||||
|
||||
dialog.setView(dialay);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private MCProfile.Builder loginOffline() {
|
||||
new File(Tools.mpProfiles).mkdir();
|
||||
|
||||
String text = edit2.getText().toString();
|
||||
if(text.isEmpty()){
|
||||
edit2.setError(getResources().getString(R.string.login_error_empty_username));
|
||||
} else if(text.length() <= 2){
|
||||
edit2.setError(getResources().getString(R.string.login_error_short_username));
|
||||
} else if(new File(Tools.mpProfiles + "/" + text).exists()){
|
||||
edit2.setError(getResources().getString(R.string.login_error_exist_username));
|
||||
} else{
|
||||
MCProfile.Builder builder = new MCProfile.Builder();
|
||||
builder.setIsAccount(false);
|
||||
builder.setUsername(text);
|
||||
|
||||
return builder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private MCProfile.Builder mProfile = null;
|
||||
private AlertDialog warning;
|
||||
public void loginMC(final View v)
|
||||
{
|
||||
/*skip it
|
||||
|
||||
String proFilePath = MCProfile.build(builder);
|
||||
MCProfile.launchWithProfile(this, proFilePath);
|
||||
end skip*/
|
||||
|
||||
if (sOffline.isChecked()) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(this);
|
||||
alert.setTitle(R.string.warning_title);
|
||||
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
sRemember.setChecked(true);
|
||||
mProfile = loginOffline();
|
||||
playProfile();
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNegativeButton(R.string.login_offline_alert_skip, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
mProfile = loginOffline();
|
||||
playProfile();
|
||||
}
|
||||
});
|
||||
|
||||
alert.setNeutralButton(android.R.string.cancel, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
mProfile = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (!sRemember.isChecked()) {
|
||||
alert.setMessage(R.string.login_offline_warning_1);
|
||||
warning = alert.show();
|
||||
} else {
|
||||
mProfile = loginOffline();
|
||||
playProfile();
|
||||
}
|
||||
|
||||
/*
|
||||
while (warning != null && warning.isShowing()) {
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
new LoginTask().setLoginListener(new LoginListener(){
|
||||
|
||||
@Override
|
||||
public void onBeforeLogin()
|
||||
{
|
||||
// TODO: Implement this method
|
||||
v.setEnabled(false);
|
||||
prb.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginDone(String[] result)
|
||||
{
|
||||
// TODO: Implement this method
|
||||
if(result[0].equals("ERROR")){
|
||||
new AlertDialog.Builder(PojavLoginActivity.this)
|
||||
.setTitle(R.string.error_title)
|
||||
.setMessage(strArrToString(result))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
else{
|
||||
MCProfile.Builder builder = new MCProfile.Builder();
|
||||
builder.setAccessToken(result[1]);
|
||||
builder.setClientID(result[2]);
|
||||
builder.setProfileID(result[3]);
|
||||
builder.setUsername(result[4]);
|
||||
builder.setVersion("1.7.10");
|
||||
|
||||
mProfile = builder;
|
||||
}
|
||||
v.setEnabled(true);
|
||||
prb.setVisibility(View.GONE);
|
||||
|
||||
playProfile();
|
||||
}
|
||||
}).execute(edit2.getText().toString(), edit3.getText().toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void playProfile() {
|
||||
if (mProfile != null) {
|
||||
String profilePath = null;
|
||||
if (sRemember.isChecked()) {
|
||||
profilePath = MCProfile.build(mProfile);
|
||||
}
|
||||
|
||||
MCProfile.launch(PojavLoginActivity.this, profilePath == null ? mProfile : profilePath);
|
||||
}
|
||||
}
|
||||
|
||||
public static String strArrToString(String[] strArr)
|
||||
{
|
||||
String[] strArrEdit = strArr;
|
||||
strArrEdit[0] = "";
|
||||
|
||||
String str = Arrays.toString(strArrEdit);
|
||||
str = str.substring(1, str.length() - 1).replace(",", "\n");
|
||||
|
||||
return str;
|
||||
}
|
||||
//We are calling this method to check the permission status
|
||||
private boolean isStorageAllowed() {
|
||||
//Getting the permission status
|
||||
int result1 = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
int result2 = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
|
||||
//If permission is granted returning true
|
||||
return result1 == PackageManager.PERMISSION_GRANTED &&
|
||||
result2 == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
//Requesting permission
|
||||
private void requestStoragePermission()
|
||||
{
|
||||
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_STORAGE_REQUEST_CODE);
|
||||
}
|
||||
|
||||
//This method will be called when the user will tap on allow or deny
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
|
||||
//Checking the request code of our request
|
||||
if(requestCode == REQUEST_STORAGE_REQUEST_CODE){
|
||||
isPromptingGrant = false;
|
||||
// isPermGranted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import java.io.*;
|
||||
import android.content.*;
|
||||
|
||||
public class PojavProfile
|
||||
{
|
||||
private static String PROFILE_PREF = "pojav_profile";
|
||||
private static String PROFILE_PREF_FILE = "file";
|
||||
private static String PROFILE_PREF_CONTENT = "content";
|
||||
|
||||
private static SharedPreferences getPrefs(Context ctx) {
|
||||
return ctx.getSharedPreferences(PROFILE_PREF, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static MCProfile.Builder getCurrentProfileContent(Context ctx) {
|
||||
return MCProfile.parse(getPrefs(ctx).getString(PROFILE_PREF_CONTENT, ""));
|
||||
}
|
||||
|
||||
public static String getCurrentProfilePath(Context ctx) {
|
||||
return getPrefs(ctx).getString(PROFILE_PREF_FILE, "");
|
||||
}
|
||||
|
||||
public static boolean setCurrentProfile(Context ctx, Object obj) {
|
||||
SharedPreferences.Editor pref = getPrefs(ctx).edit();
|
||||
|
||||
try {
|
||||
if (obj instanceof MCProfile.Builder) {
|
||||
pref.putString(PROFILE_PREF_CONTENT, MCProfile.toString((MCProfile.Builder) obj));
|
||||
} else if (obj instanceof String) {
|
||||
pref.putString(PROFILE_PREF_FILE, (String) obj);
|
||||
pref.putString(PROFILE_PREF_CONTENT, MCProfile.toString((String) obj));
|
||||
} else if (obj == null) {
|
||||
pref.putString(PROFILE_PREF_FILE, "");
|
||||
pref.putString(PROFILE_PREF_CONTENT, "");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Profile must be MCProfile.Builder.class, String.class or null");
|
||||
}
|
||||
} finally {
|
||||
return pref.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFileType(Context ctx) {
|
||||
String profilePath = PojavProfile.getCurrentProfilePath(ctx);
|
||||
String profileCon = MCProfile.toString(getCurrentProfileContent(ctx));
|
||||
if (profileCon.equals(":::::")) {
|
||||
throw new RuntimeException("Profile not set or reset.");
|
||||
}
|
||||
/*
|
||||
if (true) {
|
||||
throw new RuntimeException(profilePath + ":" + new File(profilePath).exists());
|
||||
}
|
||||
*/
|
||||
return new File(profilePath).exists();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
import android.content.*;
|
||||
|
||||
public class PojavV2ActivityManager
|
||||
{
|
||||
public static String CATEGORY_LAUNCHER = "launcher";
|
||||
public static Class<?> LAUNCHER_V1 = MCLauncherActivity.class;
|
||||
public static Class<?> LAUNCHER_V2 = LAUNCHER_V1; // PojavLauncherActivity.class;
|
||||
|
||||
public static boolean setLauncherRemakeClass(Context context, Class<?> cls) {
|
||||
return setLauncherRemakeVer(context, cls.getName().equals(LAUNCHER_V1.getName()) ? 0 : 1);
|
||||
}
|
||||
|
||||
public static boolean setLauncherRemakeVer(Context context, int i) {
|
||||
Context context2 = context;
|
||||
int i2 = i;
|
||||
if (i2 >= 0 && i2 <= 1) {
|
||||
return getPref(context2).edit().putInt(CATEGORY_LAUNCHER, i2).commit();
|
||||
} else throw new IllegalArgumentException("ver must be 0 or 1");
|
||||
}
|
||||
|
||||
public static int getLauncherRemakeInt(Context context) {
|
||||
if (Tools.enableDevFeatures) {
|
||||
return getPref(context).getInt(CATEGORY_LAUNCHER, 0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getLauncherRemakeVer(Context context) {
|
||||
return getLauncherRemakeInt(context) == 0 ? LAUNCHER_V1 : LAUNCHER_V2;
|
||||
}
|
||||
|
||||
private static SharedPreferences getPref(Context ctx) {
|
||||
return ctx.getSharedPreferences("remake", Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import java.io.*;
|
||||
import android.app.*;
|
||||
|
||||
public class ShellProcessOperation
|
||||
{
|
||||
private OnPrintListener listener;
|
||||
private Process process;
|
||||
|
||||
public ShellProcessOperation(OnPrintListener listener) throws IOException {
|
||||
this.listener = listener;
|
||||
process = Runtime.getRuntime().exec("/system/bin/sh");
|
||||
}
|
||||
|
||||
public ShellProcessOperation(OnPrintListener listener, String command) throws IOException {
|
||||
this.listener = listener;
|
||||
process = Runtime.getRuntime().exec(
|
||||
command
|
||||
); //"/system/bin/sh -c \"" + command + "\"");
|
||||
}
|
||||
|
||||
public void writeToProcess(String cmd) throws IOException {
|
||||
DataOutputStream os = new DataOutputStream(process.getOutputStream());
|
||||
os.writeBytes(cmd + "\n");
|
||||
os.flush();
|
||||
}
|
||||
|
||||
public void initInputStream(Activity ctx) {
|
||||
ctx.runOnUiThread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
printStream(process.getInputStream());
|
||||
printStream(process.getErrorStream());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public int exitCode() {
|
||||
return process.exitValue();
|
||||
}
|
||||
|
||||
public int waitFor() throws InterruptedException {
|
||||
return process.waitFor();
|
||||
}
|
||||
|
||||
public int exit() throws InterruptedException, IOException {
|
||||
writeToProcess("exit");
|
||||
return waitFor();
|
||||
}
|
||||
|
||||
private void printStream(final InputStream stream) {
|
||||
new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
BufferedReader buffStream = new BufferedReader(new InputStreamReader(stream));
|
||||
String line = null;
|
||||
while ((line = buffStream.readLine()) != null) {
|
||||
listener.onPrintLine(line + "\n");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
listener.onPrintLine(e.getMessage() + "\n");
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static interface OnPrintListener {
|
||||
public void onPrintLine(String text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,507 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.content.res.*;
|
||||
import android.net.*;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
import com.google.gson.*;
|
||||
import dalvik.system.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.charset.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import net.kdt.pojavlaunch.util.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
import org.apache.commons.codec.digest.*;
|
||||
import android.widget.*;
|
||||
|
||||
public final class Tools
|
||||
{
|
||||
public static boolean enableDevFeatures = true;
|
||||
|
||||
public static String APP_NAME = "null";
|
||||
public static String MAIN_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/games/minecraft";
|
||||
public static String ASSETS_PATH = MAIN_PATH + "/gamedir/assets";
|
||||
|
||||
public static int usingVerCode = 1;
|
||||
public static String usingVerName = "2.0";
|
||||
public static String mhomeUrl = "http://mineup.eu5.net"; // "http://kdtjavacraft.eu5.net";
|
||||
public static String mainpath = "/data/data/net.kdt.pojavlaunch";
|
||||
public static String worksDir = mainpath + "/app_working_dir";
|
||||
public static String versnDir = worksDir + "/version";
|
||||
public static String libraries = worksDir + "/libraries";
|
||||
public static String mpProfiles = mainpath + "/Users";
|
||||
public static String crashPath = Tools.MAIN_PATH + "/gamedir/crash-reports";
|
||||
|
||||
public static String mpModEnable = mainpath + "/ModsManager/✅Enabled";
|
||||
public static String mpModDisable = mainpath + "/ModsManager/❌Disabled";
|
||||
public static String mpModAddNewMo = mainpath + "/ModsManager/➕Add mod";
|
||||
|
||||
public static String[] versionList = {
|
||||
"1.7.3",
|
||||
"1.7.10",
|
||||
"1.8",
|
||||
"1.9"
|
||||
};
|
||||
|
||||
public static String artifactToPath(String group, String artifact, String version) {
|
||||
return group.replaceAll("\\.", "/") + "/" + artifact + "/" + version + "/" + artifact + "-" + version + ".jar";
|
||||
}
|
||||
|
||||
public static String getPatchedFile(String version) {
|
||||
return versnDir + "/" + version + "/multidoj/patched" + version + ".jar";
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements to get multidoj dexed folder
|
||||
*/
|
||||
//private static boolean isPatched = false;
|
||||
public static String returnMultidojOrFile(String jarPath, final boolean isClient)
|
||||
{
|
||||
//isPatched = false;
|
||||
|
||||
if (new File(jarPath).exists()) {
|
||||
// Check if jar file is exists
|
||||
return ":" + jarPath;// + ":";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
File file = new File(jarPath.substring(0, jarPath.lastIndexOf("/")) + "/multidoj");
|
||||
|
||||
File[] classes = file.listFiles(new FilenameFilter(){
|
||||
|
||||
@Override
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
if (isClient) {
|
||||
if (name.endsWith(".dex") || name.startsWith("patched")) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (name.endsWith(".dex") || name.endsWith(".jar")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
try {
|
||||
for (File f : classes) {
|
||||
sb.append(":" + f.getAbsolutePath());// + ":");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// skip broken library
|
||||
return "";
|
||||
}
|
||||
return ":" + sb.toString();
|
||||
}
|
||||
|
||||
// May useless
|
||||
public static boolean isOptifineInstalled(String version)
|
||||
{
|
||||
return new File(versnDir + "/" + version + "/multidoj/optifine.jar").exists();
|
||||
}
|
||||
|
||||
public static String generate(String version) throws IOException
|
||||
{
|
||||
StringBuilder libStr = new StringBuilder(); //versnDir + "/" + version + "/" + version + ".jar:";
|
||||
String[] classpath = Tools.generateLibClasspath(Tools.getVersionInfo(version).libraries);
|
||||
|
||||
libStr.append(returnMultidojOrFile(versnDir + "/" + version + "/" + version + ".jar", true).substring(1));
|
||||
//libStr.append(getPatchedFile(version));
|
||||
for (String perclass : classpath) {
|
||||
libStr.append(returnMultidojOrFile(perclass, false));
|
||||
}
|
||||
|
||||
return libStr.toString();
|
||||
}
|
||||
|
||||
public static DisplayMetrics getDisplayMetrics(Activity ctx) {
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
ctx.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||
return displayMetrics;
|
||||
}
|
||||
|
||||
public static void extractAssetFolder(Activity ctx, String path, String output) throws Exception
|
||||
{
|
||||
AssetManager assetManager = ctx.getAssets();
|
||||
String assets[] = null;
|
||||
try {
|
||||
assets = assetManager.list(path);
|
||||
if (assets.length == 0) {
|
||||
Tools.copyAssetOptional(ctx, path, output);
|
||||
} else {
|
||||
String fullPath = output + "/" + path;
|
||||
File dir = new File(fullPath);
|
||||
if (!dir.exists())
|
||||
dir.mkdir();
|
||||
for (String sub : assets) {
|
||||
extractAssetFolder(ctx, path + "/" + sub, output);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
showError(ctx, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static void extractLibraries(Activity ctx) throws Exception
|
||||
{
|
||||
extractAssetFolder(ctx, "libraries", worksDir);
|
||||
}
|
||||
*/
|
||||
|
||||
public static void showError(Activity ctx, Throwable e)
|
||||
{
|
||||
showError(ctx, e, false);
|
||||
}
|
||||
|
||||
public static void showError(final Activity ctx, final Throwable e, final boolean exitIfOk)
|
||||
{
|
||||
showError(ctx, e, exitIfOk, false);
|
||||
}
|
||||
|
||||
private static void showError(final Activity ctx, final Throwable e, final boolean exitIfOk, final boolean showMore)
|
||||
{
|
||||
ctx.runOnUiThread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final String errMsg = showMore ? Log.getStackTraceString(e): e.getMessage();
|
||||
new AlertDialog.Builder((Context) ctx)
|
||||
.setTitle(R.string.error_title)
|
||||
.setMessage(errMsg)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
if(exitIfOk) MainActivity.fullyExit();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
showError(ctx, e, exitIfOk, !showMore);
|
||||
}
|
||||
})
|
||||
.setNeutralButton(android.R.string.copy, new DialogInterface.OnClickListener(){
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
ClipboardManager clipboard = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("Error", errMsg);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
|
||||
Toast.makeText(ctx, "Copied to clipboard", Toast.LENGTH_SHORT).show();
|
||||
|
||||
if(exitIfOk) MainActivity.fullyExit();
|
||||
}
|
||||
})
|
||||
//.setNegativeButton("Report (not available)", null)
|
||||
.setCancelable(!exitIfOk)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void dialogOnUiThread(final Activity ctx, final CharSequence title, final CharSequence message)
|
||||
{
|
||||
ctx.runOnUiThread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
// TODO: Implement this method
|
||||
new AlertDialog.Builder(ctx)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void openURL(Activity act, String url) {
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
act.startActivity(browserIntent);
|
||||
}
|
||||
|
||||
public static void clearDuplicateFiles(File f) throws IOException {
|
||||
List<File> list = Arrays.asList(f.listFiles());
|
||||
for (File file : list) {
|
||||
if (!file.exists()) {
|
||||
// The file was deleted by duplicate
|
||||
list.remove(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
String md5 = DigestUtils.md5Hex(new FileInputStream(file));
|
||||
list.remove(file);
|
||||
clearDuplicateFilesByMD5(list.toArray(new File[0]), md5);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearDuplicateFilesByMD5(File[] list, String md5Find) throws IOException {
|
||||
for (File file : list) {
|
||||
String md5Other = DigestUtils.md5Hex(new FileInputStream(file));
|
||||
if (md5Find.equals(md5Other)) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] generateLibClasspath(DependentLibrary[] libs)
|
||||
{
|
||||
List<String> libDir = new ArrayList<String>();
|
||||
for (DependentLibrary libItem: libs) {
|
||||
String[] libInfos = libItem.name.split(":");
|
||||
if (libItem.name.equals("net.minecraft:launchwrapper:1.5")) {
|
||||
libInfos[2] = "1.6";
|
||||
libDir.add(Tools.libraries + "/" + Tools.artifactToPath(libInfos[0], libInfos[1], libInfos[2]));
|
||||
} else {
|
||||
libDir.add(Tools.libraries + "/" + Tools.artifactToPath(libInfos[0], libInfos[1], libInfos[2]));
|
||||
}
|
||||
}
|
||||
return libDir.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static void runDx(final Activity ctx, String fileIn, String fileOut, MultidojManager.Listen listener) throws Exception
|
||||
{
|
||||
MultidojManager.setListener(listener);
|
||||
|
||||
File optDir = ctx.getDir("dalvik-cache", 0);
|
||||
optDir.mkdirs();
|
||||
|
||||
File out = new File(fileOut);
|
||||
File newFileOut = new File(out.getParent() + File.separator + "multidoj" + File.separator + "resources" + (System.currentTimeMillis()) + ".jar");
|
||||
newFileOut.getParentFile().mkdirs();
|
||||
//Class
|
||||
DexClassLoader mainLoader = new DexClassLoader(Tools.worksDir + "/multidoj.dex", optDir.getAbsolutePath(), ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0).applicationInfo.nativeLibraryDir, MainActivity.class.getClassLoader());
|
||||
|
||||
String receiveMethod = "net.kdt.pojavlaunch.MultidojManager->call(message:String, max:Integer, current:Integer)";
|
||||
mainLoader.loadClass("com.android.dx.observer.ObserverStatus").getMethod("setReceiver", String.class).invoke(null, receiveMethod);
|
||||
Class mainClass = mainLoader.loadClass("com.android.dx.command.Main");
|
||||
Method mainMethod = mainClass.getMethod("main", new String[]{}.getClass());
|
||||
mainMethod.invoke(null, new Object[]{new String[]{"--dex", "--output", newFileOut.getAbsolutePath(), fileIn}});
|
||||
//com.android.dx.mod.Main.dexTheJar(fileIn, fileOut, ctx.getCacheDir().getAbsolutePath(), listener);
|
||||
|
||||
|
||||
//return Runtime.getRuntime().exec("echo IN:" + fileIn + ";OUT:" + fileOut);
|
||||
}
|
||||
|
||||
public static MinecraftVersion getVersionInfo(String versionName) throws IOException {
|
||||
File versionFile = new File(Tools.versnDir + "/" + versionName + "/" + versionName + ".json");
|
||||
/*
|
||||
if (!versionFile.exists()) {
|
||||
return downloadVersionInfo(versionName);
|
||||
}
|
||||
*/
|
||||
byte[] versionDat = new byte[((int) versionFile.length())];
|
||||
FileInputStream is = new FileInputStream(versionFile);
|
||||
is.read(versionDat);
|
||||
is.close();
|
||||
return new Gson().fromJson(new String(versionDat, Charset.forName("UTF-8")), MinecraftVersion.class);
|
||||
}
|
||||
|
||||
public static String convertStream(InputStream inputStream, Charset charset) throws IOException {
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String line = null;
|
||||
|
||||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, charset))) {
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
stringBuilder.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
// Current Useless below but keep it for future usage.
|
||||
public static void deleteRecursive(File fileOrDirectory) {
|
||||
try {
|
||||
if (fileOrDirectory.isDirectory()) {
|
||||
for (File child : fileOrDirectory.listFiles()) {
|
||||
deleteRecursive(child);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
fileOrDirectory.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static File lastFileModified(String dir) {
|
||||
File fl = new File(dir);
|
||||
File[] files = fl.listFiles(new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.isFile();
|
||||
}
|
||||
});
|
||||
long lastMod = Long.MIN_VALUE;
|
||||
File choice = null;
|
||||
for (File file : files) {
|
||||
if (file.lastModified() > lastMod) {
|
||||
choice = file;
|
||||
lastMod = file.lastModified();
|
||||
}
|
||||
}
|
||||
return choice;
|
||||
}
|
||||
|
||||
public static byte[] getByteArray(String filePath) throws Exception
|
||||
{
|
||||
return getByteArray(new FileInputStream(filePath));
|
||||
}
|
||||
|
||||
public static byte[] getByteArray(InputStream stream) throws IOException
|
||||
{
|
||||
byte[] bytes = new byte[stream.available()];
|
||||
BufferedInputStream buf = new BufferedInputStream(stream);
|
||||
buf.read(bytes, 0, bytes.length);
|
||||
buf.close();
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String read(String path) throws Exception
|
||||
{
|
||||
return new String(getByteArray(path));
|
||||
}
|
||||
|
||||
public static void write(String path, byte[] content) throws Exception
|
||||
{
|
||||
FileOutputStream fos = new FileOutputStream(path);
|
||||
fos.write(content);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
public static void write(String path, String content) throws Exception
|
||||
{
|
||||
write(path, content.getBytes());
|
||||
}
|
||||
|
||||
public static byte[] loadFromAssetToByte(Context ctx, String inFile) {
|
||||
byte[] tContents = {};
|
||||
|
||||
try {
|
||||
InputStream stream = ctx.getAssets().open(inFile);
|
||||
|
||||
int size = stream.available();
|
||||
byte[] buffer = new byte[size];
|
||||
stream.read(buffer);
|
||||
stream.close();
|
||||
tContents = buffer;
|
||||
} catch (IOException e) {
|
||||
// Handle exceptions here
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tContents;
|
||||
}
|
||||
|
||||
public static void copyAssetOptional(Context ctx, String fileName, String output) throws Exception
|
||||
{
|
||||
copyAssetOptional(ctx, fileName, output, fileName);
|
||||
}
|
||||
|
||||
public static void copyAssetOptional(Context ctx, String fileName, String output, String outputName) throws Exception
|
||||
{
|
||||
try {
|
||||
File file = new File(output);
|
||||
if(!file.exists()) file.mkdirs();
|
||||
File file2 = new File(output + "/" + outputName);
|
||||
if(!file2.exists()){
|
||||
if (!file2.createNewFile()) throw new RuntimeException("Unable to write " + output + "/" + outputName);
|
||||
write(file2.getAbsolutePath(), loadFromAssetToByte(ctx, fileName));
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
throw new RuntimeException("Unable to copy " + fileName + " to " + output + "/" + outputName, th);
|
||||
}
|
||||
}
|
||||
public static void downloadFile(String urlInput, String nameOutput, boolean requireNonExist) throws Throwable
|
||||
{
|
||||
File fileDDD = new File(nameOutput);
|
||||
if(requireNonExist && !fileDDD.exists())
|
||||
{
|
||||
DownloadUtils.downloadFile(urlInput, fileDDD);
|
||||
}
|
||||
}
|
||||
public static class ZipTool
|
||||
{
|
||||
private ZipTool(){}
|
||||
public static void zip(List<File> files, File zipFile) throws IOException {
|
||||
final int BUFFER_SIZE = 2048;
|
||||
|
||||
BufferedInputStream origin = null;
|
||||
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
|
||||
|
||||
try {
|
||||
byte data[] = new byte[BUFFER_SIZE];
|
||||
|
||||
for (File file : files) {
|
||||
FileInputStream fileInputStream = new FileInputStream( file );
|
||||
|
||||
origin = new BufferedInputStream(fileInputStream, BUFFER_SIZE);
|
||||
|
||||
try {
|
||||
ZipEntry entry = new ZipEntry(file.getName());
|
||||
|
||||
out.putNextEntry(entry);
|
||||
|
||||
int count;
|
||||
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
origin.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
public static void unzip(File zipFile, File targetDirectory) throws IOException {
|
||||
final int BUFFER_SIZE = 1024;
|
||||
ZipInputStream zis = new ZipInputStream(
|
||||
new BufferedInputStream(new FileInputStream(zipFile)));
|
||||
try {
|
||||
ZipEntry ze;
|
||||
int count;
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
File file = new File(targetDirectory, ze.getName());
|
||||
File dir = ze.isDirectory() ? file : file.getParentFile();
|
||||
if (!dir.isDirectory() && !dir.mkdirs())
|
||||
throw new FileNotFoundException("Failed to ensure directory: " +
|
||||
dir.getAbsolutePath());
|
||||
if (ze.isDirectory())
|
||||
continue;
|
||||
FileOutputStream fout = new FileOutputStream(file);
|
||||
try {
|
||||
while ((count = zis.read(buffer)) != -1)
|
||||
fout.write(buffer, 0, count);
|
||||
} finally {
|
||||
fout.close();
|
||||
}
|
||||
/* if time should be restored as well
|
||||
long time = ze.getTime();
|
||||
if (time > 0)
|
||||
file.setLastModified(time);
|
||||
*/
|
||||
}
|
||||
} finally {
|
||||
zis.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.app.*;
|
||||
import android.graphics.*;
|
||||
import android.os.*;
|
||||
import android.widget.*;
|
||||
import dalvik.system.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import net.kdt.pojavlaunch.libs.*;
|
||||
import android.util.*;
|
||||
|
||||
public class UpdateAppActivity extends Activity
|
||||
{
|
||||
private ProgressBar progress;
|
||||
private TextView logView;
|
||||
private boolean cancelable = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.launcher_update);
|
||||
|
||||
progress = (ProgressBar) findViewById(R.id.launcherupdateProgressBar);
|
||||
logView = (TextView) findViewById(R.id.launcherupdateLogView);
|
||||
logView.setTypeface(Typeface.MONOSPACE);
|
||||
|
||||
File inst = new File(Tools.worksDir + "/installer.jar");
|
||||
|
||||
try {
|
||||
File optDir = getDir("dalvik-cache", 0);
|
||||
optDir.mkdirs();
|
||||
|
||||
DexClassLoader mainLoader = new DexClassLoader(inst.getAbsolutePath(), optDir.getAbsolutePath(), getPackageManager().getPackageInfo(getPackageName(), 0).applicationInfo.nativeLibraryDir, MainActivity.class.getClassLoader());
|
||||
Class mClass = mainLoader.loadClass("Main");
|
||||
Method method = mClass.getMethod("main", UpdateAppActivity.class);
|
||||
method.invoke(null, this);
|
||||
|
||||
} catch (Throwable th) {
|
||||
putLog("----- AN ERROR OCCURRED -----");
|
||||
putLog(Log.getStackTraceString(th));
|
||||
putLog("----- FAILED TO UPDATE! -----");
|
||||
} finally {
|
||||
cancelable = true;
|
||||
}
|
||||
}
|
||||
public void putLog(String message)
|
||||
{
|
||||
logView.append(message + "\n");
|
||||
}
|
||||
public ProgressBar getProgressBar()
|
||||
{
|
||||
return progress;
|
||||
}
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
if (cancelable) super.onBackPressed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.view.*;
|
||||
|
||||
public class WindowAnimation
|
||||
{
|
||||
public static void fadeIn(final View view, int duration) {
|
||||
// 0.1 -> 1.0
|
||||
doFade(view, true, duration);
|
||||
}
|
||||
|
||||
public static void fadeOut(final View view, int duration) {
|
||||
// 1.0 -> 0.1
|
||||
doFade(view, false, duration);
|
||||
}
|
||||
|
||||
private static void doFade(final View view, final boolean fadeIn, int duration) {
|
||||
final long millis = ((long) duration) / 10l;
|
||||
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setAlpha(fadeIn ? 0 : 1);
|
||||
view.setEnabled(false);
|
||||
new Thread(new Runnable(){
|
||||
private float alpha = fadeIn ? 0 : 1;
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try {
|
||||
while (fadeIn ? alpha < 1 : alpha > 0) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {}
|
||||
|
||||
if (fadeIn) alpha += 0.1;
|
||||
else alpha -= 0.1;
|
||||
|
||||
view.post(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
view.setAlpha(alpha);
|
||||
}
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
view.post(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (fadeIn) view.setEnabled(true);
|
||||
else {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.kdt.pojavlaunch.exit;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class ExitManager {
|
||||
private static boolean stopLoop = false;
|
||||
|
||||
private static ExitTrappedListener listener;
|
||||
private static Thread exitTrappedHook = new Thread(new Runnable(){
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (listener != null) listener.onExitTrapped();
|
||||
// Pre-check
|
||||
// if (stopLoop) stopLoop = false;
|
||||
|
||||
while (true) {
|
||||
if (stopLoop) {
|
||||
stopLoop = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Make Thread hook never stop, then System.exit() never continue!
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
|
||||
stopLoop = false;
|
||||
}
|
||||
});
|
||||
|
||||
public static void setExitTrappedListener(ExitTrappedListener l) {
|
||||
listener = l;
|
||||
}
|
||||
|
||||
public static void stopExitLoop() {
|
||||
stopLoop = true;
|
||||
}
|
||||
|
||||
public static void disableSystemExit() // throws NoSuchFieldException, IllegalAccessException, IllegalArgumentException
|
||||
{
|
||||
// changeRuntimeExitDisabled(true);
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(exitTrappedHook);
|
||||
}
|
||||
|
||||
public static void enableSystemExit() // throws NoSuchFieldException, IllegalAccessException, IllegalArgumentException
|
||||
{
|
||||
// changeRuntimeExitDisabled(false);
|
||||
|
||||
|
||||
Runtime.getRuntime().removeShutdownHook(exitTrappedHook);
|
||||
}
|
||||
|
||||
// It's not safe. Add/Remove shutdown hooks will cause error.
|
||||
private static void changeRuntimeExitDisabled(boolean value) throws NoSuchFieldException, IllegalAccessException, IllegalArgumentException {
|
||||
Runtime run = Runtime.getRuntime();
|
||||
Field shutdownField = run.getClass().getDeclaredField("shuttingDown");
|
||||
shutdownField.setAccessible(true);
|
||||
shutdownField.set(run, value);
|
||||
}
|
||||
|
||||
|
||||
public static interface ExitTrappedListener {
|
||||
public void onExitTrapped();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.kdt.pojavlaunch.exit;
|
||||
|
||||
public class ExitTrappedException extends RuntimeException
|
||||
{
|
||||
public ExitTrappedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ExitTrappedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.kdt.pojavlaunch.libs;
|
||||
|
||||
import com.google.gson.*;
|
||||
import java.io.*;
|
||||
import java.nio.charset.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class LibrariesManager
|
||||
{
|
||||
public static MinecraftVersion getVersionInfo(String versionJsonDir) throws Exception {
|
||||
String versionStr = Tools.read(versionJsonDir);
|
||||
return new Gson().fromJson(versionStr, MinecraftVersion.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package net.kdt.pojavlaunch.mcfragments;
|
||||
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.support.v4.app.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import java.io.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import android.util.*;
|
||||
import android.graphics.*;
|
||||
|
||||
public class ConsoleFragment extends Fragment
|
||||
{
|
||||
public TextView consoleView;
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.lmaintab_consolelog, container, false);
|
||||
|
||||
consoleView = (TextView) view.findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
consoleView.setTypeface(Typeface.MONOSPACE);
|
||||
consoleView.setHint("No log");
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle p1)
|
||||
{
|
||||
super.onActivityCreated(p1);
|
||||
/*
|
||||
new Thread(new Runnable(){
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {}
|
||||
|
||||
final String popLog = ConsoleFragmentHelper.popLog();
|
||||
if (!popLog.isEmpty()) {
|
||||
getActivity().runOnUiThread(new Runnable(){
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
consoleView.append(popLog);
|
||||
System.out.println("OKAY? " + popLog);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
consoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
}
|
||||
|
||||
public void putLog(String str) {
|
||||
if (consoleView == null) {
|
||||
consoleView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogTextView);
|
||||
}
|
||||
|
||||
consoleView.append(str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package net.kdt.pojavlaunch.mcfragments;
|
||||
|
||||
import android.os.*;
|
||||
import android.support.annotation.*;
|
||||
import android.support.v4.app.*;
|
||||
import android.view.*;
|
||||
import android.widget.*;
|
||||
import java.io.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import android.util.*;
|
||||
import android.graphics.*;
|
||||
|
||||
public class CrashFragment extends Fragment
|
||||
{
|
||||
public static String lastCrashSaved = "";
|
||||
private String crashContent;
|
||||
public boolean resetCrashLog = false;
|
||||
|
||||
private TextView crashView;
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.lmaintab_crashlog, container, false);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle p1)
|
||||
{
|
||||
super.onActivityCreated(p1);
|
||||
crashView = (TextView) getView().findViewById(R.id.lmaintabconsoleLogCrashTextView);
|
||||
crashView.setTypeface(Typeface.MONOSPACE);
|
||||
crashView.setHint("No crash detected.");
|
||||
|
||||
//new File(crashPath).mkdirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
refreshCrashFile();
|
||||
}
|
||||
|
||||
public static boolean isNewCrash(File crashLog) throws Exception {
|
||||
String content = Tools.read(crashLog.getAbsolutePath());
|
||||
return crashLog != null && content.startsWith("---- Minecraft Crash Report ----");
|
||||
}
|
||||
|
||||
public void refreshCrashFile()
|
||||
{
|
||||
try {
|
||||
if(!resetCrashLog){
|
||||
File crashLog = Tools.lastFileModified(Tools.crashPath);
|
||||
|
||||
if (isNewCrash(crashLog)) {
|
||||
crashContent = Tools.read(crashLog.getAbsolutePath());
|
||||
Tools.write(crashLog.getAbsolutePath(), "\n" + crashContent);
|
||||
lastCrashSaved = crashLog.getName();
|
||||
crashView.setText(crashContent);
|
||||
} else if(crashLog.getName().equals(lastCrashSaved)){
|
||||
crashView.setText(crashContent);
|
||||
}
|
||||
else throw new Exception();
|
||||
}
|
||||
else throw new Exception();
|
||||
} catch (Exception e) {
|
||||
// Can't find crash or no NEW crashes
|
||||
crashView.setText(""/*Log.getStackTraceString(e)*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.kdt.pojavlaunch.mcfragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.LayoutInflater;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebChromeClient;
|
||||
|
||||
import net.kdt.pojavlaunch.R;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class LauncherFragment extends Fragment
|
||||
{
|
||||
private WebView webNews;
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
View view = inflater.inflate(R.layout.lmaintab_news, container, false);
|
||||
return view;
|
||||
}
|
||||
@Override
|
||||
public void onActivityCreated(Bundle p1)
|
||||
{
|
||||
super.onActivityCreated(p1);
|
||||
|
||||
webNews = (WebView) getView().findViewById(R.id.lmaintabnewsNewsView);
|
||||
webNews.setWebChromeClient(new WebChromeClient(){});
|
||||
webNews.clearCache(true);
|
||||
webNews.getSettings().setJavaScriptEnabled(true);
|
||||
webNews.loadUrl(Tools.mhomeUrl + "/changelog.html");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.kdt.pojavlaunch.optifine;
|
||||
|
||||
import com.google.gson.*;
|
||||
import java.nio.charset.*;
|
||||
import net.kdt.pojavlaunch.value.*;
|
||||
import net.kdt.pojavlaunch.util.*;
|
||||
import java.io.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class Optifine
|
||||
{
|
||||
public static OptifineVersion.VersionList getList() throws Exception
|
||||
{
|
||||
String optifineStr = DownloadUtils.downloadString(Tools.mhomeUrl + "/optifine.json");
|
||||
return new Gson().fromJson(optifineStr, OptifineVersion.VersionList.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.kdt.pojavlaunch.optifine;
|
||||
|
||||
public class OptifineVersion
|
||||
{
|
||||
public VersionList[] versions;
|
||||
public static class VersionList {
|
||||
public String version;
|
||||
public String linkUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package net.kdt.pojavlaunch.signer;
|
||||
|
||||
import android.util.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.jar.*;
|
||||
import java.util.zip.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
//import org.apache.commons.codec.digest.*;
|
||||
import net.kdt.pojavlaunch.util.*;
|
||||
|
||||
public class JarSigner
|
||||
{
|
||||
private static final String DEX_IN_JAR_NAME = "classes.dex";
|
||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||
|
||||
private TreeMap<String, byte[]> outputResources = new TreeMap<String, byte[]>();
|
||||
|
||||
public static void sign(String inputJar, String outputJar) throws Exception
|
||||
{
|
||||
new JarSigner(inputJar, outputJar);
|
||||
}
|
||||
private JarSigner(String inputJar, String outputJar) throws Exception
|
||||
{
|
||||
ZipFile jarFile = new ZipFile(inputJar);
|
||||
Enumeration<? extends ZipEntry> entries = jarFile.entries();
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
outputResources.put(entry.getName(), Tools.getByteArray(jarFile.getInputStream(entry)));
|
||||
}
|
||||
createJar(outputJar);
|
||||
}
|
||||
private byte[] makeManifest() {
|
||||
StringBuilder baos = new StringBuilder();
|
||||
|
||||
// First, put some general information:
|
||||
baos.append("Manifest-Version: 1.0\n");
|
||||
baos.append("Created-By: " + Tools.usingVerName + " (" + Tools.APP_NAME + ": JarSigner)\n");
|
||||
baos.append("Build-Jdk: 1.6.0_29");
|
||||
baos.append("Dex-Location: " + DEX_IN_JAR_NAME + "\n");
|
||||
|
||||
return baos.toString().getBytes();
|
||||
}
|
||||
private boolean createJar(String fileName) {
|
||||
/*
|
||||
* Make or modify the manifest (as appropriate), put the dex
|
||||
* array into the resources map, and then process the entire
|
||||
* resources map in a uniform manner.
|
||||
*/
|
||||
|
||||
try {
|
||||
byte[] manifest = makeManifest();
|
||||
OutputStream out = new FileOutputStream(fileName);
|
||||
JarOutputStream jarOut = new JarOutputStream(out);
|
||||
|
||||
try {
|
||||
for (Map.Entry<String, byte[]> e : outputResources.entrySet()) {
|
||||
String name = e.getKey();
|
||||
byte[] contents = e.getValue();
|
||||
JarEntry entry = new JarEntry(name);
|
||||
int length = contents.length;
|
||||
entry.setSize(length);
|
||||
/*
|
||||
if (args.verbose) {
|
||||
context.out.println("writing " + name + "; size " + length + "...");
|
||||
}
|
||||
*/
|
||||
if (name.endsWith(".SF") ||
|
||||
name.endsWith(".RSA")) {
|
||||
// Remove these files.
|
||||
continue;
|
||||
} else if (name.endsWith(MANIFEST_PATH)) {
|
||||
length = manifest.length;
|
||||
jarOut.putNextEntry(entry);
|
||||
jarOut.write(manifest);
|
||||
jarOut.closeEntry();
|
||||
} else {
|
||||
jarOut.putNextEntry(entry);
|
||||
jarOut.write(contents);
|
||||
jarOut.closeEntry();
|
||||
}
|
||||
|
||||
}
|
||||
} finally {
|
||||
jarOut.finish();
|
||||
jarOut.flush();
|
||||
closeOutput(out);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Trouble writing output:", ex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
private void closeOutput(OutputStream stream) throws IOException {
|
||||
if (stream == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream.flush();
|
||||
|
||||
if (stream != System.out) {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package net.kdt.pojavlaunch.util;
|
||||
|
||||
import android.util.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.charset.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class DownloadUtils {
|
||||
public static final String USER_AGENT = Tools.APP_NAME;
|
||||
public static final Charset utf8 = Charset.forName("UTF-8");
|
||||
|
||||
public static void download(String url, OutputStream os) {
|
||||
try {
|
||||
download(new URL(url), os);
|
||||
} catch (Throwable malformed) {
|
||||
throw new RuntimeException(malformed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void download(URL url, OutputStream os) throws Throwable {
|
||||
InputStream is = null;
|
||||
byte[] buf; // 16384
|
||||
try {
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestProperty("User-Agent", USER_AGENT);
|
||||
conn.setConnectTimeout(2000);
|
||||
conn.setDoInput(true);
|
||||
conn.connect();
|
||||
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
|
||||
throw new RuntimeException("Server returned HTTP " + conn.getResponseCode()
|
||||
+ ": " + conn.getResponseMessage());
|
||||
}
|
||||
buf = new byte[conn.getContentLength()];
|
||||
is = conn.getInputStream();
|
||||
IoUtil.pipe(is, os, buf);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String downloadString(String url) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
download(url, bos);
|
||||
return new String(bos.toByteArray(), utf8);
|
||||
}
|
||||
|
||||
public static void downloadFile(String url, File out) throws Throwable {
|
||||
out.getParentFile().mkdirs();
|
||||
File tempOut = File.createTempFile(out.getName(), ".part", out.getParentFile());
|
||||
BufferedOutputStream bos = null;
|
||||
try {
|
||||
OutputStream bos2 = new BufferedOutputStream(new FileOutputStream(tempOut));
|
||||
try {
|
||||
download(url, bos2);
|
||||
tempOut.renameTo(out);
|
||||
if (bos2 != null) {
|
||||
bos2.close();
|
||||
}
|
||||
if (tempOut.exists()) {
|
||||
tempOut.delete();
|
||||
}
|
||||
} catch (Throwable th2) {
|
||||
if (bos != null) {
|
||||
bos.close();
|
||||
}
|
||||
if (tempOut.exists()) {
|
||||
tempOut.delete();
|
||||
}
|
||||
throw th2;
|
||||
}
|
||||
} catch (Throwable th3) {
|
||||
|
||||
if (bos != null) {
|
||||
bos.close();
|
||||
}
|
||||
if (tempOut.exists()) {
|
||||
tempOut.delete();
|
||||
}
|
||||
throw th3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package net.kdt.pojavlaunch.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
import android.os.*;
|
||||
|
||||
public class IoUtil {
|
||||
|
||||
//public static volatile boolean cancel = false;
|
||||
|
||||
private IoUtil() {
|
||||
}
|
||||
|
||||
public static void pipe( /*PojavLauncherActivity activity,*/ InputStream is, OutputStream out, byte[] buf) throws IOException {
|
||||
while (true) {
|
||||
//if (cancel) throw new CancelException();
|
||||
|
||||
int amt = is.read(buf);
|
||||
if (amt >= 0) {
|
||||
out.write(buf, 0, amt);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copy(File from, File to, byte[] buf) throws IOException {
|
||||
InputStream in = new FileInputStream(from);
|
||||
OutputStream out;
|
||||
try {
|
||||
out = new FileOutputStream(to);
|
||||
pipe(in, out, buf);
|
||||
out.close();
|
||||
in.close();
|
||||
} catch (Throwable th) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyZipWithoutEmptyDirectories(File inputFile, File outputFile) throws IOException {
|
||||
byte[] buf = new byte[8192];
|
||||
ZipFile inputZip = new ZipFile(inputFile);
|
||||
ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile));
|
||||
try {
|
||||
Enumeration<? extends ZipEntry> e = inputZip.entries();
|
||||
ArrayList<ZipEntry> sortedList = new ArrayList();
|
||||
while (e.hasMoreElements()) {
|
||||
sortedList.add((ZipEntry) e.nextElement());
|
||||
}
|
||||
Collections.sort(sortedList, new Comparator<ZipEntry>() {
|
||||
public int compare(ZipEntry o1, ZipEntry o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
for (int i = sortedList.size() - 1; i >= 0; i--) {
|
||||
boolean isEmptyDirectory;
|
||||
ZipEntry inputEntry = (ZipEntry) sortedList.get(i);
|
||||
String name = inputEntry.getName();
|
||||
if (!inputEntry.isDirectory()) {
|
||||
isEmptyDirectory = false;
|
||||
} else if (i == sortedList.size() - 1) {
|
||||
isEmptyDirectory = true;
|
||||
} else {
|
||||
isEmptyDirectory = !((ZipEntry) sortedList.get(i + 1)).getName().startsWith(name);
|
||||
}
|
||||
if (isEmptyDirectory) {
|
||||
sortedList.remove(inputEntry);
|
||||
} else {
|
||||
outputStream.putNextEntry(new ZipEntry(inputEntry));
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = inputZip.getInputStream(inputEntry);
|
||||
pipe(is, baos, buf);
|
||||
is.close();
|
||||
outputStream.write(baos.toByteArray());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearDirectory(File dir) {
|
||||
File[] fileList = dir.listFiles();
|
||||
if (fileList != null) {
|
||||
for (File f : fileList) {
|
||||
if (f.isDirectory()) {
|
||||
clearDirectory(f);
|
||||
}
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.kdt.pojavlaunch.value;
|
||||
|
||||
public class DependentLibrary {
|
||||
public String name;
|
||||
public MDownloads downloads;
|
||||
|
||||
public static class MDownloads
|
||||
{
|
||||
public MinecraftLibraryArtifact artifact;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.kdt.pojavlaunch.value;
|
||||
|
||||
public class MinecraftClientInfo
|
||||
{
|
||||
public String sha1;
|
||||
public int size;
|
||||
public String url;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.kdt.pojavlaunch.value;
|
||||
|
||||
public class MinecraftLibraryArtifact extends MinecraftClientInfo
|
||||
{
|
||||
public String path;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.kdt.pojavlaunch.value;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class MinecraftVersion
|
||||
{
|
||||
public String assets;
|
||||
public Map<String, MinecraftClientInfo> downloads;
|
||||
public DependentLibrary[] libraries;
|
||||
public String mainClass;
|
||||
public String minecraftArguments;
|
||||
public int minimumLauncherVersion;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.kdt.pojavlaunch.views;
|
||||
|
||||
public class MineButton
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.minecraft.client;
|
||||
|
||||
public class ClientBrandRetriever {
|
||||
public ClientBrandRetriever() {
|
||||
//ClientBrandRetriever clientBrandRetriever = this;
|
||||
}
|
||||
|
||||
public static String getClientModName() {
|
||||
return "PojavLauncher";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class AlphaVanillaTweaker implements ITweaker {
|
||||
private List<String> args;
|
||||
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
classLoader.registerTransformer("net.minecraft.launchwrapper.injector.AlphaVanillaTweakInjector");
|
||||
}
|
||||
|
||||
public String getLaunchTarget() {
|
||||
return "net.minecraft.launchwrapper.injector.AlphaVanillaTweakInjector";
|
||||
}
|
||||
|
||||
public String[] getLaunchArguments() {
|
||||
return (String[]) this.args.toArray(new String[this.args.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
public interface IClassNameTransformer {
|
||||
String remapClassName(String str);
|
||||
|
||||
String unmapClassName(String str);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
public interface IClassTransformer {
|
||||
byte[] transform(String str, String str2, byte[] bArr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public interface ITweaker {
|
||||
void acceptOptions(List<String> list, File file, File file2, String str);
|
||||
|
||||
String[] getLaunchArguments();
|
||||
|
||||
String getLaunchTarget();
|
||||
|
||||
void injectIntoClassLoader(LaunchClassLoader launchClassLoader);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class IndevVanillaTweaker implements ITweaker {
|
||||
private List<String> args;
|
||||
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
classLoader.registerTransformer("net.minecraft.launchwrapper.injector.IndevVanillaTweakInjector");
|
||||
}
|
||||
|
||||
public String getLaunchTarget() {
|
||||
return "net.minecraft.launchwrapper.injector.AlphaVanillaTweakInjector";
|
||||
}
|
||||
|
||||
public String[] getLaunchArguments() {
|
||||
return (String[]) this.args.toArray(new String[this.args.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.logging.*;
|
||||
import java.util.logging.Level;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
public class Launch {
|
||||
private static final String DEFAULT_TWEAK = "net.minecraft.launchwrapper.VanillaTweaker";
|
||||
public static File assetsDir;
|
||||
public static LaunchClassLoader classLoader;
|
||||
public static File minecraftHome;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Launch().launch(args);
|
||||
}
|
||||
|
||||
private Launch() {
|
||||
classLoader = (LaunchClassLoader) Thread.currentThread().getContextClassLoader(); // getClass().getClassLoader(); //((URLClassLoader) getClass().getClassLoader()).getURLs());
|
||||
}
|
||||
|
||||
private void launch(String[] args) {
|
||||
OptionParser parser = new OptionParser();
|
||||
parser.allowsUnrecognizedOptions();
|
||||
OptionSpec<String> profileOption = parser.accepts("version", "The version we launched with").withRequiredArg();
|
||||
OptionSpec<File> gameDirOption = parser.accepts("gameDir", "Alternative game directory").withRequiredArg().ofType(File.class);
|
||||
OptionSpec<File> assetsDirOption = parser.accepts("assetsDir", "Assets directory").withRequiredArg().ofType(File.class);
|
||||
OptionSpec<String> tweakClassOption = parser.accepts("tweakClass", "Tweak class to load").withRequiredArg().defaultsTo(DEFAULT_TWEAK, new String[0]);
|
||||
OptionSpec<String> nonOption = parser.nonOptions();
|
||||
OptionSet options = parser.parse(args);
|
||||
minecraftHome = (File) options.valueOf(gameDirOption);
|
||||
assetsDir = (File) options.valueOf(assetsDirOption);
|
||||
String profileName = (String) options.valueOf(profileOption);
|
||||
String tweakClassName = (String) options.valueOf(tweakClassOption);
|
||||
try {
|
||||
LogWrapper.log(Level.INFO, "Using tweak class name %s", new Object[]{tweakClassName});
|
||||
classLoader.addClassLoaderExclusion(tweakClassName.substring(0, tweakClassName.lastIndexOf(46)));
|
||||
ITweaker tweaker = (ITweaker) Class.forName(tweakClassName, true, classLoader).newInstance();
|
||||
tweaker.acceptOptions(options.valuesOf(nonOption), minecraftHome, assetsDir, profileName);
|
||||
tweaker.injectIntoClassLoader(classLoader);
|
||||
Method mainMethod = Class.forName(tweaker.getLaunchTarget(), false, classLoader).getMethod("main", new Class[]{String[].class});
|
||||
LogWrapper.info("Launching wrapped minecraft", new Object[0]);
|
||||
mainMethod.invoke(null, new Object[]{tweaker.getLaunchArguments()});
|
||||
} catch (Exception e) {
|
||||
LogWrapper.log(Level.SEVERE, e, "Unable to launch", new Object[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,489 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import dalvik.system.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.security.*;
|
||||
import java.util.*;
|
||||
import java.util.jar.*;
|
||||
import java.util.jar.Attributes.*;
|
||||
import java.util.logging.*;
|
||||
import net.kdt.pojavlaunch.*;
|
||||
|
||||
public class LaunchClassLoader extends DexClassLoader {
|
||||
public static final int BUFFER_SIZE = 4096;
|
||||
private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("legacy.debugClassLoading", "false"));
|
||||
private static final boolean DEBUG_FINER;
|
||||
private static final boolean DEBUG_SAVE;
|
||||
private static final Manifest EMPTY = new Manifest();
|
||||
private static final String[] RESERVED_NAMES = new String[]{"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"};
|
||||
private static File tempFolder = null;
|
||||
private Map<String, Class> cachedClasses = new HashMap<String, Class>(1000);
|
||||
private Set<String> classLoaderExceptions = new HashSet<String>();
|
||||
private Set<String> invalidClasses = new HashSet<String>(1000);
|
||||
private final ThreadLocal<byte[]> loadBuffer = new ThreadLocal<byte[]>();
|
||||
private Map<Package, Manifest> packageManifests = new HashMap<Package, Manifest>();
|
||||
//private ClassLoader parent = getClass().getClassLoader();
|
||||
private IClassNameTransformer renameTransformer;
|
||||
private List<URL> sources;
|
||||
private Set<String> transformerExceptions = new HashSet<String>();
|
||||
private List<IClassTransformer> transformers = new ArrayList<IClassTransformer>(2);
|
||||
|
||||
static {
|
||||
boolean z;
|
||||
boolean z2 = true;
|
||||
if (DEBUG && Boolean.parseBoolean(System.getProperty("legacy.debugClassLoadingFiner", "false"))) {
|
||||
z = true;
|
||||
} else {
|
||||
z = false;
|
||||
}
|
||||
DEBUG_FINER = z;
|
||||
if (!(DEBUG && Boolean.parseBoolean(System.getProperty("legacy.debugClassLoadingSave", "false")))) {
|
||||
z2 = false;
|
||||
}
|
||||
DEBUG_SAVE = z2;
|
||||
}
|
||||
|
||||
protected Package definePackage(String packageName, Manifest manifest,
|
||||
URL url) throws IllegalArgumentException {
|
||||
Attributes mainAttributes = manifest.getMainAttributes();
|
||||
String dirName = packageName.replace('.', '/') + "/";
|
||||
Attributes packageAttributes = manifest.getAttributes(dirName);
|
||||
boolean noEntry = false;
|
||||
if (packageAttributes == null) {
|
||||
noEntry = true;
|
||||
packageAttributes = mainAttributes;
|
||||
}
|
||||
String specificationTitle = packageAttributes
|
||||
.getValue(Attributes.Name.SPECIFICATION_TITLE);
|
||||
if (specificationTitle == null && !noEntry) {
|
||||
specificationTitle = mainAttributes
|
||||
.getValue(Attributes.Name.SPECIFICATION_TITLE);
|
||||
}
|
||||
String specificationVersion = packageAttributes
|
||||
.getValue(Attributes.Name.SPECIFICATION_VERSION);
|
||||
if (specificationVersion == null && !noEntry) {
|
||||
specificationVersion = mainAttributes
|
||||
.getValue(Attributes.Name.SPECIFICATION_VERSION);
|
||||
}
|
||||
String specificationVendor = packageAttributes
|
||||
.getValue(Attributes.Name.SPECIFICATION_VENDOR);
|
||||
if (specificationVendor == null && !noEntry) {
|
||||
specificationVendor = mainAttributes
|
||||
.getValue(Attributes.Name.SPECIFICATION_VENDOR);
|
||||
}
|
||||
String implementationTitle = packageAttributes
|
||||
.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
|
||||
if (implementationTitle == null && !noEntry) {
|
||||
implementationTitle = mainAttributes
|
||||
.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
|
||||
}
|
||||
String implementationVersion = packageAttributes
|
||||
.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||
if (implementationVersion == null && !noEntry) {
|
||||
implementationVersion = mainAttributes
|
||||
.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||
}
|
||||
String implementationVendor = packageAttributes
|
||||
.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
|
||||
if (implementationVendor == null && !noEntry) {
|
||||
implementationVendor = mainAttributes
|
||||
.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
|
||||
}
|
||||
return definePackage(packageName, specificationTitle,
|
||||
specificationVersion, specificationVendor,
|
||||
implementationTitle, implementationVersion,
|
||||
implementationVendor, //isSealed(manifest, dirName) ? url : null);
|
||||
isSealed(dirName, manifest) ? url : null);
|
||||
}
|
||||
|
||||
// ENDED modding part
|
||||
|
||||
public LaunchClassLoader() { //String launchDexPath, String launchOptimizedDirectory, String launchLibrarySearchPath, ClassLoader parentClassLoader) {
|
||||
super(LaunchClassLoaderAgruments.launchDexPath, LaunchClassLoaderAgruments.launchOptimizedDirectory, LaunchClassLoaderAgruments.launchLibrarySearchPath, LaunchClassLoader.class.getClassLoader());
|
||||
//super(launchDexPath, launchOptimizedDirectory, launchLibrarySearchPath, parentClassLoader);
|
||||
//System.out.println("MinecraftLaunchWrapper: How did Minecraft generated it: " + LaunchClassLoaderAgruments.launchDexPath);
|
||||
|
||||
this.sources = new ArrayList<URL>(Arrays.asList(sources));
|
||||
Thread.currentThread().setContextClassLoader(this);
|
||||
addClassLoaderExclusion("java.");
|
||||
addClassLoaderExclusion("sun.");
|
||||
addClassLoaderExclusion("org.lwjgl.");
|
||||
addClassLoaderExclusion("net.minecraft.launchwrapper.");
|
||||
addTransformerExclusion("javax.");
|
||||
addTransformerExclusion("argo.");
|
||||
addTransformerExclusion("org.objectweb.asm.");
|
||||
addTransformerExclusion("com.google.common.");
|
||||
addTransformerExclusion("org.bouncycastle.");
|
||||
addTransformerExclusion("net.minecraft.launchwrapper.injector.");
|
||||
if (DEBUG_SAVE) {
|
||||
int x = 1;
|
||||
tempFolder = new File(Launch.minecraftHome, "CLASSLOADER_TEMP");
|
||||
while (tempFolder.exists() && x <= 10) {
|
||||
int x2 = x + 1;
|
||||
tempFolder = new File(Launch.minecraftHome, "CLASSLOADER_TEMP" + x);
|
||||
x = x2;
|
||||
}
|
||||
if (tempFolder.exists()) {
|
||||
LogWrapper.info("DEBUG_SAVE enabled, but 10 temp directories already exist, clean them and try again.", new Object[0]);
|
||||
tempFolder = null;
|
||||
return;
|
||||
}
|
||||
LogWrapper.info("DEBUG_SAVE Enabled, saving all classes to \"%s\"", new Object[]{tempFolder.getAbsolutePath().replace('\\', '/')});
|
||||
tempFolder.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerTransformer(String transformerClassName) {
|
||||
try {
|
||||
IClassTransformer transformer = (IClassTransformer) loadClass(transformerClassName).newInstance();
|
||||
this.transformers.add(transformer);
|
||||
if ((transformer instanceof IClassNameTransformer) && this.renameTransformer == null) {
|
||||
this.renameTransformer = (IClassNameTransformer) transformer;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogWrapper.log(Level.SEVERE, e, "A critical problem occurred registering the ASM transformer class %s", new Object[]{transformerClassName});
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
if (this.invalidClasses.contains(name)) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
for (String exception : this.classLoaderExceptions) {
|
||||
if (name.startsWith(exception)) {
|
||||
return LaunchClassLoader.class.getClassLoader().loadClass(name);
|
||||
}
|
||||
}
|
||||
if (this.cachedClasses.containsKey(name)) {
|
||||
return (Class<?>) this.cachedClasses.get(name);
|
||||
}
|
||||
for (String exception2 : this.transformerExceptions) {
|
||||
if (name.startsWith(exception2)) {
|
||||
try {
|
||||
Class<?> clazz = super.findClass(name);
|
||||
this.cachedClasses.put(name, clazz);
|
||||
return clazz;
|
||||
} catch (ClassNotFoundException e) {
|
||||
this.invalidClasses.add(name);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
String packageName;
|
||||
String transformedName = transformName(name);
|
||||
String untransformedName = untransformName(name);
|
||||
int lastDot = untransformedName.lastIndexOf(46);
|
||||
if (lastDot == -1) {
|
||||
packageName = "";
|
||||
} else {
|
||||
packageName = untransformedName.substring(0, lastDot);
|
||||
}
|
||||
String fileName = untransformedName.replace('.', '/').concat(".class");
|
||||
URLConnection urlConnection = findCodeSourceConnectionFor(fileName);
|
||||
CodeSigner[] signers = null;
|
||||
if (lastDot > -1) {
|
||||
if (!untransformedName.startsWith("net.minecraft.")) {
|
||||
Package pkg;
|
||||
if (urlConnection instanceof JarURLConnection) {
|
||||
JarURLConnection jarURLConnection = (JarURLConnection) urlConnection;
|
||||
JarFile jarFile = jarURLConnection.getJarFile();
|
||||
if (!(jarFile == null || jarFile.getManifest() == null)) {
|
||||
Manifest manifest = jarFile.getManifest();
|
||||
JarEntry entry = jarFile.getJarEntry(fileName);
|
||||
pkg = getPackage(packageName);
|
||||
getClassBytes(untransformedName);
|
||||
signers = entry.getCodeSigners();
|
||||
if (pkg == null) {
|
||||
this.packageManifests.put(definePackage(packageName, manifest, jarURLConnection.getJarFileURL()), manifest);
|
||||
} else {//JarURLConnection aj;
|
||||
if (pkg.isSealed()) {
|
||||
if (!pkg.isSealed(jarURLConnection.getJarFileURL())) {
|
||||
LogWrapper.severe("The jar file %s is trying to seal already secured path %s", new Object[]{jarFile.getName(), packageName});
|
||||
}
|
||||
}
|
||||
if (isSealed(packageName, manifest)) {
|
||||
LogWrapper.severe("The jar file %s has a security seal for path %s, but that path is defined and not secure", new Object[]{jarFile.getName(), packageName});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pkg = getPackage(packageName);
|
||||
if (pkg == null) {
|
||||
this.packageManifests.put(definePackage(packageName, null, null, null, null, null, null, null), EMPTY);
|
||||
} else if (pkg.isSealed()) {
|
||||
LogWrapper.severe("The URL %s is defining elements for sealed path %s", new Object[]{urlConnection.getURL(), packageName});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] transformedClass = runTransformers(untransformedName, transformedName, getClassBytes(untransformedName));
|
||||
if (DEBUG_SAVE) {
|
||||
saveTransformedClass(transformedClass, transformedName);
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = defineClass(transformedName, transformedClass, 0, transformedClass.length); //, new ProtectionDomain(urlConnection == null ? null : new CodeSource(urlConnection.getURL(), signers), getClass().getProtectionDomain().getPermissions()));
|
||||
this.cachedClasses.put(transformedName, clazz);
|
||||
return clazz;
|
||||
} catch (Throwable th) {
|
||||
// MODDING HERE!
|
||||
Class<?> clazz = loadClassAnyway(name);
|
||||
this.cachedClasses.put(transformedName, clazz);
|
||||
return clazz;
|
||||
}
|
||||
} catch (Throwable e2) {
|
||||
this.invalidClasses.add(name);
|
||||
if (DEBUG) {
|
||||
LogWrapper.log(Level.FINEST, e2, "Exception encountered attempting classloading of %s", new Object[]{name});
|
||||
}
|
||||
//ClassNotFoundException classNotFoundException = new ClassNotFoundException(name, e2);
|
||||
throw new ClassNotFoundException(name, e2);
|
||||
}
|
||||
}
|
||||
|
||||
// Mod:
|
||||
private Class<?> loadClassAnyway(String pkg) {
|
||||
try {
|
||||
return Class.forName(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return super.findClass(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return super.loadClass(pkg, true);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return getClass().forName(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return getParent().loadClass(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return getSystemClassLoader().loadClass(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return getClass().getClassLoader().loadClass(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
try {
|
||||
return Thread.currentThread().getContextClassLoader().loadClass(pkg);
|
||||
} catch (Throwable th) {}
|
||||
|
||||
throw new RuntimeException("Unable to find class, out of 9 times");
|
||||
}
|
||||
|
||||
private void saveTransformedClass(byte[] data, String transformedName) {
|
||||
if (tempFolder != null) {
|
||||
File outFile = new File(tempFolder, transformedName.replace('.', File.separatorChar) + ".class");
|
||||
File outDir = outFile.getParentFile();
|
||||
if (!outDir.exists()) {
|
||||
outDir.mkdirs();
|
||||
}
|
||||
if (outFile.exists()) {
|
||||
outFile.delete();
|
||||
}
|
||||
try {
|
||||
LogWrapper.fine("Saving transformed class \"%s\" to \"%s\"", new Object[]{transformedName, outFile.getAbsolutePath().replace('\\', '/')});
|
||||
OutputStream output = new FileOutputStream(outFile);
|
||||
output.write(data);
|
||||
output.close();
|
||||
} catch (IOException ex) {
|
||||
LogWrapper.log(Level.WARNING, ex, "Could not save transformed class \"%s\"", new Object[]{transformedName});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String untransformName(String name) {
|
||||
if (this.renameTransformer != null) {
|
||||
return this.renameTransformer.unmapClassName(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String transformName(String name) {
|
||||
if (this.renameTransformer != null) {
|
||||
return this.renameTransformer.remapClassName(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private boolean isSealed(String path, Manifest manifest) {
|
||||
Attributes attributes = manifest.getAttributes(path);
|
||||
String sealed = null;
|
||||
if (attributes != null) {
|
||||
sealed = attributes.getValue(Name.SEALED);
|
||||
}
|
||||
if (sealed == null) {
|
||||
attributes = manifest.getMainAttributes();
|
||||
if (attributes != null) {
|
||||
sealed = attributes.getValue(Name.SEALED);
|
||||
}
|
||||
}
|
||||
return "true".equalsIgnoreCase(sealed);
|
||||
}
|
||||
|
||||
private URLConnection findCodeSourceConnectionFor(String name) {
|
||||
URL resource = findResource(name);
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return resource.openConnection();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] runTransformers(String name, String transformedName, byte[] basicClass) {
|
||||
int i = 0;
|
||||
if (DEBUG_FINER) {
|
||||
String str = "Beginning transform of %s (%s) Start Length: %d";
|
||||
Object[] objArr = new Object[3];
|
||||
objArr[0] = name;
|
||||
objArr[1] = transformedName;
|
||||
objArr[2] = Integer.valueOf(basicClass == null ? 0 : basicClass.length);
|
||||
LogWrapper.finest(str, objArr);
|
||||
for (IClassTransformer transformer : this.transformers) {
|
||||
int i2;
|
||||
String transName = transformer.getClass().getName();
|
||||
str = "Before Transformer %s: %d";
|
||||
objArr = new Object[2];
|
||||
objArr[0] = transName;
|
||||
objArr[1] = Integer.valueOf(basicClass == null ? 0 : basicClass.length);
|
||||
LogWrapper.finest(str, objArr);
|
||||
basicClass = transformer.transform(name, transformedName, basicClass);
|
||||
str = "After Transformer %s: %d";
|
||||
objArr = new Object[2];
|
||||
objArr[0] = transName;
|
||||
if (basicClass == null) {
|
||||
i2 = 0;
|
||||
} else {
|
||||
i2 = basicClass.length;
|
||||
}
|
||||
objArr[1] = Integer.valueOf(i2);
|
||||
LogWrapper.finest(str, objArr);
|
||||
}
|
||||
String str2 = "Ending transform of %s (%s) Start Length: %d";
|
||||
Object[] objArr2 = new Object[3];
|
||||
objArr2[0] = name;
|
||||
objArr2[1] = transformedName;
|
||||
if (basicClass != null) {
|
||||
i = basicClass.length;
|
||||
}
|
||||
objArr2[2] = Integer.valueOf(i);
|
||||
LogWrapper.finest(str2, objArr2);
|
||||
} else {
|
||||
for (IClassTransformer transformer2 : this.transformers) {
|
||||
basicClass = transformer2.transform(name, transformedName, basicClass);
|
||||
}
|
||||
}
|
||||
return basicClass;
|
||||
}
|
||||
|
||||
public void addURL(URL url) {
|
||||
//super.addURL(url);
|
||||
this.sources.add(url);
|
||||
}
|
||||
|
||||
public List<URL> getSources() {
|
||||
return this.sources;
|
||||
}
|
||||
|
||||
private byte[] readFully(InputStream stream) {
|
||||
try {
|
||||
byte[] buffer = getOrCreateBuffer();
|
||||
int totalLength = 0;
|
||||
while (true) {
|
||||
int read = stream.read(buffer, totalLength, buffer.length - totalLength);
|
||||
if (read != -1) {
|
||||
totalLength += read;
|
||||
if (totalLength >= buffer.length - 1) {
|
||||
byte[] newBuffer = new byte[(buffer.length + BUFFER_SIZE)];
|
||||
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
|
||||
buffer = newBuffer;
|
||||
}
|
||||
} else {
|
||||
byte[] result = new byte[totalLength];
|
||||
System.arraycopy(buffer, 0, result, 0, totalLength);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
LogWrapper.log(Level.WARNING, t, "Problem loading class", new Object[0]);
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getOrCreateBuffer() {
|
||||
byte[] buffer = (byte[]) this.loadBuffer.get();
|
||||
if (buffer != null) {
|
||||
return buffer;
|
||||
}
|
||||
this.loadBuffer.set(new byte[BUFFER_SIZE]);
|
||||
return (byte[]) this.loadBuffer.get();
|
||||
}
|
||||
|
||||
public List<IClassTransformer> getTransformers() {
|
||||
return Collections.unmodifiableList(this.transformers);
|
||||
}
|
||||
|
||||
public void addClassLoaderExclusion(String toExclude) {
|
||||
this.classLoaderExceptions.add(toExclude);
|
||||
}
|
||||
|
||||
public void addTransformerExclusion(String toExclude) {
|
||||
this.transformerExceptions.add(toExclude);
|
||||
}
|
||||
|
||||
public byte[] getClassBytes(String name) throws IOException {
|
||||
byte[] data;
|
||||
if (name.indexOf(46) == -1) {
|
||||
for (String reservedName : RESERVED_NAMES) {
|
||||
if (name.toUpperCase(Locale.ENGLISH).startsWith(reservedName)) {
|
||||
data = getClassBytes("_" + name);
|
||||
if (data != null) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
URL classResource = findResource(name.replace('.', '/').concat(".class"));
|
||||
if (classResource == null) {
|
||||
if (DEBUG) {
|
||||
LogWrapper.finest("Failed to find class resource"); // %s", new Object[]{resourcePath});
|
||||
}
|
||||
closeSilently(null);
|
||||
return null;
|
||||
}
|
||||
InputStream classStream = classResource.openStream();
|
||||
if (DEBUG) {
|
||||
LogWrapper.finest("Loading class %s from resource %s", new Object[]{name, classResource.toString()});
|
||||
}
|
||||
data = readFully(classStream);
|
||||
closeSilently(classStream);
|
||||
return data;
|
||||
} catch (Throwable th) {
|
||||
closeSilently(null);
|
||||
// Mod
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeSilently(Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import java.util.logging.*;
|
||||
import net.minecraft.launchwrapper.LogWrapper.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import android.util.*;
|
||||
|
||||
public class LogWrapper {
|
||||
private static boolean configured;
|
||||
public static LogWrapper log = new LogWrapper();
|
||||
|
||||
private Logger myLog;
|
||||
private SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss");
|
||||
|
||||
// Make Android compatible with java logger
|
||||
private LogWrapper.AndroidLogger androidLogger;
|
||||
|
||||
private static void configureLogging() {
|
||||
log.myLog = Logger.getLogger("LaunchWrapper");
|
||||
configured = true;
|
||||
}
|
||||
|
||||
public static void retarget(Logger to) {
|
||||
log.myLog = to;
|
||||
}
|
||||
|
||||
public static void log(String logChannel, Level level, String format, Object... data) {
|
||||
makeLog(logChannel);
|
||||
String logData = String.format(format, data);
|
||||
Logger.getLogger(logChannel).log(level, logData);
|
||||
androidLog(logChannel, level.getName(), logData);
|
||||
}
|
||||
|
||||
public static void log(Level level, String format, Object... data) {
|
||||
if (!configured) {
|
||||
configureLogging();
|
||||
}
|
||||
String logData = String.format(format, data);
|
||||
log.myLog.log(level, logData);
|
||||
androidLog("LaunchWrapper", level.getName(), logData);
|
||||
}
|
||||
|
||||
public static void log(String logChannel, Level level, Throwable ex, String format, Object... data) {
|
||||
makeLog(logChannel);
|
||||
String logData = String.format(format, data);
|
||||
Logger.getLogger(logChannel).log(level, logData, ex);
|
||||
androidLog(logChannel, level.getName(), logData + "\n" + Log.getStackTraceString(ex));
|
||||
}
|
||||
|
||||
public static void log(Level level, Throwable ex, String format, Object... data) {
|
||||
if (!configured) {
|
||||
configureLogging();
|
||||
}
|
||||
String logData = String.format(format, data);
|
||||
log.myLog.log(level, logData, ex);
|
||||
androidLog("LaunchWrapper", level.getName(), logData + "\n" + Log.getStackTraceString(ex));
|
||||
}
|
||||
|
||||
public static void severe(String format, Object... data) {
|
||||
log(Level.SEVERE, format, data);
|
||||
}
|
||||
|
||||
public static void warning(String format, Object... data) {
|
||||
log(Level.WARNING, format, data);
|
||||
}
|
||||
|
||||
public static void info(String format, Object... data) {
|
||||
log(Level.INFO, format, data);
|
||||
}
|
||||
|
||||
public static void fine(String format, Object... data) {
|
||||
log(Level.FINE, format, data);
|
||||
}
|
||||
|
||||
public static void finer(String format, Object... data) {
|
||||
log(Level.FINER, format, data);
|
||||
}
|
||||
|
||||
public static void finest(String format, Object... data) {
|
||||
log(Level.FINEST, format, data);
|
||||
}
|
||||
|
||||
public static void makeLog(String logChannel) {
|
||||
Logger.getLogger(logChannel).setParent(log.myLog);
|
||||
}
|
||||
|
||||
// Android compatible add:
|
||||
private static void androidLog(String name, String level, String data) {
|
||||
String timeStr = log.time.format(new Date());
|
||||
log.androidLogger.onPrint(timeStr, name, level, data);
|
||||
}
|
||||
|
||||
public static void setAndroidLogReceiver(AndroidLogger logger) {
|
||||
log.androidLogger = logger;
|
||||
}
|
||||
|
||||
public static interface AndroidLogger {
|
||||
public void onPrint(String time, String name, String level, String message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.minecraft.launchwrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class VanillaTweaker implements ITweaker {
|
||||
private List<String> args;
|
||||
|
||||
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
|
||||
classLoader.registerTransformer("net.minecraft.launchwrapper.injector.VanillaTweakInjector");
|
||||
}
|
||||
|
||||
public String getLaunchTarget() {
|
||||
return "net.minecraft.client.Minecraft";
|
||||
}
|
||||
|
||||
public String[] getLaunchArguments() {
|
||||
return (String[]) this.args.toArray(new String[this.args.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package net.minecraft.launchwrapper.injector;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.applet.AppletStub;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.swing.JPanel;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
|
||||
public class AlphaVanillaTweakInjector implements IClassTransformer {
|
||||
|
||||
private static class LauncherFake extends Applet implements AppletStub {
|
||||
final /* synthetic */ Map map;
|
||||
|
||||
public LauncherFake(Map map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public void appletResize(int width, int height) {
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public URL getDocumentBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public URL getCodeBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getParameter(String paramName) {
|
||||
if (this.map.containsKey(paramName)) {
|
||||
return (String) this.map.get(paramName);
|
||||
}
|
||||
System.err.println("Client asked for parameter: " + paramName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
Class clazz;
|
||||
try {
|
||||
clazz = getaClass("net.minecraft.client.MinecraftApplet");
|
||||
} catch (ClassNotFoundException e) {
|
||||
clazz = getaClass("com.mojang.minecraft.MinecraftApplet");
|
||||
}
|
||||
System.out.println("AlphaVanillaTweakInjector.class.getClassLoader() = " + AlphaVanillaTweakInjector.class.getClassLoader());
|
||||
Object object = clazz.getConstructor(new Class[0]).newInstance(new Object[0]);
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
String name = field.getType().getName();
|
||||
if (!(name.contains("awt") || name.contains("java") || name.equals("long"))) {
|
||||
System.out.println("Found likely Minecraft candidate: " + field);
|
||||
Field fileField = getWorkingDirField(name);
|
||||
if (fileField != null) {
|
||||
System.out.println("Found File, changing to " + Launch.minecraftHome);
|
||||
fileField.setAccessible(true);
|
||||
fileField.set(null, Launch.minecraftHome);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
startMinecraft((Applet) object, args);
|
||||
}
|
||||
|
||||
private static void startMinecraft(final Applet applet, String[] args) {
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
String name = "Player" + (System.currentTimeMillis() % 1000);
|
||||
if (args.length > 0) {
|
||||
name = args[0];
|
||||
}
|
||||
String sessionId = "-";
|
||||
if (args.length > 1) {
|
||||
sessionId = args[1];
|
||||
}
|
||||
params.put("username", name);
|
||||
params.put("sessionid", sessionId);
|
||||
Frame launcherFrameFake = new Frame();
|
||||
launcherFrameFake.setTitle("Minecraft");
|
||||
launcherFrameFake.setBackground(Color.BLACK);
|
||||
JPanel panel = new JPanel();
|
||||
launcherFrameFake.setLayout(new BorderLayout());
|
||||
panel.setPreferredSize(new Dimension(854, 480));
|
||||
launcherFrameFake.add(panel, "Center");
|
||||
launcherFrameFake.pack();
|
||||
launcherFrameFake.setLocationRelativeTo(null);
|
||||
launcherFrameFake.setVisible(true);
|
||||
launcherFrameFake.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
System.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
LauncherFake fakeLauncher = new LauncherFake(params);
|
||||
applet.setStub(fakeLauncher);
|
||||
fakeLauncher.setLayout(new BorderLayout());
|
||||
fakeLauncher.add(applet, "Center");
|
||||
fakeLauncher.validate();
|
||||
launcherFrameFake.removeAll();
|
||||
launcherFrameFake.setLayout(new BorderLayout());
|
||||
launcherFrameFake.add(fakeLauncher, "Center");
|
||||
launcherFrameFake.validate();
|
||||
|
||||
applet.init();
|
||||
applet.start();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
public void run() {
|
||||
applet.stop();
|
||||
}
|
||||
});
|
||||
VanillaTweakInjector.loadIconsOnFrames();
|
||||
}
|
||||
|
||||
private static Class<?> getaClass(String name) throws ClassNotFoundException {
|
||||
return Launch.classLoader.loadClass(name);
|
||||
}
|
||||
|
||||
private static Field getWorkingDirField(String name) throws ClassNotFoundException {
|
||||
for (Field field : getaClass(name).getDeclaredFields()) {
|
||||
if (Modifier.isStatic(field.getModifiers()) && field.getType().getName().equals("java.io.File")) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package net.minecraft.launchwrapper.injector;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.ListIterator;
|
||||
import javax.imageio.ImageIO;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
public class IndevVanillaTweakInjector implements IClassTransformer {
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
ClassNode classNode = new ClassNode();
|
||||
new ClassReader(bytes).accept(classNode, 8);
|
||||
if (!classNode.interfaces.contains("java/lang/Runnable")) {
|
||||
return bytes;
|
||||
}
|
||||
MethodNode runMethod = null;
|
||||
Iterator i$ = classNode.methods.iterator();
|
||||
while (true) {
|
||||
if (!i$.hasNext()) {
|
||||
break;
|
||||
}
|
||||
MethodNode methodNode = (MethodNode) i$.next();
|
||||
if ("run".equals(methodNode.name)) {
|
||||
runMethod = methodNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (runMethod == null) {
|
||||
return bytes;
|
||||
}
|
||||
System.out.println("Probably the minecraft class (it has run && is applet!): " + name);
|
||||
ListIterator<AbstractInsnNode> iterator = runMethod.instructions.iterator();
|
||||
int firstSwitchJump = -1;
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode instruction = (AbstractInsnNode) iterator.next();
|
||||
if (instruction.getOpcode() == 170) {
|
||||
firstSwitchJump = runMethod.instructions.indexOf((AbstractInsnNode) ((TableSwitchInsnNode) instruction).labels.get(0));
|
||||
} else if (firstSwitchJump >= 0 && runMethod.instructions.indexOf(instruction) == firstSwitchJump) {
|
||||
int endOfSwitch = -1;
|
||||
while (true) {
|
||||
if (!iterator.hasNext()) {
|
||||
break;
|
||||
}
|
||||
instruction = (AbstractInsnNode) iterator.next();
|
||||
if (instruction.getOpcode() == 167) {
|
||||
endOfSwitch = runMethod.instructions.indexOf(((JumpInsnNode) instruction).label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (endOfSwitch >= 0) {
|
||||
while (runMethod.instructions.indexOf(instruction) != endOfSwitch && iterator.hasNext()) {
|
||||
instruction = (AbstractInsnNode) iterator.next();
|
||||
}
|
||||
AbstractInsnNode instruction2 = (AbstractInsnNode) iterator.next();
|
||||
runMethod.instructions.insertBefore(instruction2, new MethodInsnNode(184, "net/minecraft/launchwrapper/injector/IndevVanillaTweakInjector", "inject", "()Ljava/io/File;"));
|
||||
runMethod.instructions.insertBefore(instruction2, new VarInsnNode(58, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
ClassWriter writer = new ClassWriter(3);
|
||||
classNode.accept(writer);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
public static File inject() {
|
||||
System.out.println("Turning of ImageIO disk-caching");
|
||||
ImageIO.setUseCache(false);
|
||||
VanillaTweakInjector.loadIconsOnFrames();
|
||||
System.out.println("Setting gameDir to: " + Launch.minecraftHome);
|
||||
return Launch.minecraftHome;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package net.minecraft.launchwrapper.injector;
|
||||
|
||||
import java.awt.Frame;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import javax.imageio.ImageIO;
|
||||
import net.minecraft.launchwrapper.IClassTransformer;
|
||||
import net.minecraft.launchwrapper.Launch;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.FieldNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public class VanillaTweakInjector implements IClassTransformer {
|
||||
public byte[] transform(String name, String transformedName, byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
if (!"net.minecraft.client.Minecraft".equals(name)) {
|
||||
return bytes;
|
||||
}
|
||||
ClassNode classNode = new ClassNode();
|
||||
new ClassReader(bytes).accept(classNode, 8);
|
||||
MethodNode mainMethod = null;
|
||||
for (MethodNode methodNode : classNode.methods) {
|
||||
if ("main".equals(methodNode.name)) {
|
||||
mainMethod = methodNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mainMethod == null) {
|
||||
return bytes;
|
||||
}
|
||||
FieldNode workDirNode = null;
|
||||
for (FieldNode fieldNode : classNode.fields) {
|
||||
if (Type.getDescriptor(File.class).equals(fieldNode.desc) && (fieldNode.access & 8) == 8) {
|
||||
workDirNode = fieldNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MethodNode injectedMethod = new MethodNode();
|
||||
Label label = new Label();
|
||||
injectedMethod.visitLabel(label);
|
||||
injectedMethod.visitLineNumber(9001, label);
|
||||
injectedMethod.visitMethodInsn(184, "net/minecraft/launchwrapper/injector/VanillaTweakInjector", "inject", "()Ljava/io/File;");
|
||||
injectedMethod.visitFieldInsn(179, "net/minecraft/client/Minecraft", workDirNode.name, "Ljava/io/File;");
|
||||
ListIterator<AbstractInsnNode> iterator = mainMethod.instructions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AbstractInsnNode insn = (AbstractInsnNode) iterator.next();
|
||||
if (insn.getOpcode() == 177) {
|
||||
mainMethod.instructions.insertBefore(insn, injectedMethod.instructions);
|
||||
}
|
||||
}
|
||||
ClassWriter writer = new ClassWriter(3);
|
||||
classNode.accept(writer);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
public static File inject() {
|
||||
System.out.println("Turning off ImageIO disk-caching");
|
||||
ImageIO.setUseCache(false);
|
||||
loadIconsOnFrames();
|
||||
System.out.println("Setting gameDir to: " + Launch.minecraftHome);
|
||||
return Launch.minecraftHome;
|
||||
}
|
||||
|
||||
public static void loadIconsOnFrames() {
|
||||
try {
|
||||
File smallIcon = new File(Launch.assetsDir, "icons/icon_16x16.png");
|
||||
File bigIcon = new File(Launch.assetsDir, "icons/icon_32x32.png");
|
||||
System.out.println("Loading current icons for window from: " + smallIcon + " and " + bigIcon);
|
||||
Display.setIcon(new ByteBuffer[]{loadIcon(smallIcon), loadIcon(bigIcon)});
|
||||
Frame[] frames = Frame.getFrames();
|
||||
if (frames != null) {
|
||||
List<Image> icons = Arrays.asList(new Image[]{ImageIO.read(smallIcon), ImageIO.read(bigIcon)});
|
||||
for (Frame frame : frames) {
|
||||
try {
|
||||
frame.setIconImages(icons);
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static ByteBuffer loadIcon(File iconFile) throws IOException {
|
||||
BufferedImage icon = ImageIO.read(iconFile);
|
||||
int[] rgb = icon.getRGB(0, 0, icon.getWidth(), icon.getHeight(), null, 0, icon.getWidth());
|
||||
ByteBuffer buffer = ByteBuffer.allocate(rgb.length * 4);
|
||||
for (int color : rgb) {
|
||||
buffer.putInt((color << 8) | ((color >> 24) & 255));
|
||||
}
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.zhuoweizhang.boardwalk;
|
||||
|
||||
import android.os.Build.VERSION;
|
||||
|
||||
public class DalvikTweaks {
|
||||
public static native void crashTheLogger();
|
||||
|
||||
public static native void nativeSetDefaultStackSize(int i, int i2);
|
||||
|
||||
public static native void nativeSetHeapMaxFree(long j, int i);
|
||||
|
||||
public static native void nativeSetHeapMinFree(long j, int i);
|
||||
|
||||
public static native void setenv(String str, String str2, boolean z);
|
||||
|
||||
public static void setDefaultStackSize(int i) {
|
||||
nativeSetDefaultStackSize(i, VERSION.SDK_INT);
|
||||
}
|
||||
|
||||
public static void setHeapMaxFree(long j) {
|
||||
nativeSetHeapMaxFree(j, VERSION.SDK_INT);
|
||||
}
|
||||
|
||||
public static void setHeapMinFree(long j) {
|
||||
nativeSetHeapMinFree(j, VERSION.SDK_INT);
|
||||
}
|
||||
|
||||
public static boolean isDalvik() {
|
||||
String property = System.getProperty("java.vm.version");
|
||||
return property != null && property.startsWith("1");
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("boardwalk");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user