Merge branch 'dalvikvm_gl4es' into dalvikvm_gl4es_fixc

This commit is contained in:
Tran Khanh Duy
2020-08-09 17:33:48 +07:00
committed by GitHub
24 changed files with 146577 additions and 26 deletions

View File

@@ -9,8 +9,14 @@ Discord server: https://discord.gg/6RpEJda
- Impossible for directly run. There's RoboVM but is AOT Compiler. You could also try UTM with Android-x86.
- OpenJDK 9 and GL4ES has iOS port so maybe run in a jailbreaked device. I don't have a Mac OS X device to build one.
## Installing OptiFine?
Follow steps [here](https://github.com/khanhduytran0/PojavLauncher/wiki/Install-OptiFine).
## About this branch
- This branch attempt to launch Minecraft using command line like `dalvikvm` and `app_process`.
- Status: working partial, EGL Context not yet shared, process get crashed if attempt to execute OpenGL command.
## Anything if this successful?
- Able to custom min/max RAM heap.
- Solve some incompatible issues.
## Installing Forge?
Not implemented yet.
@@ -131,6 +137,9 @@ Increase max DX references. Launcher Options -> Settings -> Increase max DX refe
## A note about 1.12.x
- Minecraft 1.12.x can be run on Android 8.0 and above by use d8 for desugar and dexing in the latest v2, but will crash in singleplayer.
## Solution found!
- [twaik/libcw](https://github.com/twaik/libcw) or [shodruky-rhyammer/gl-streaming](https://github.com/shodruky-rhyammer/gl-streaming) but I'm busy at v3.
## License
- PojavLauncher is licensed under [GNU GPLv3](https://github.com/khanhduytran0/PojavLauncher/blob/master/LICENSE).
@@ -144,3 +153,4 @@ Increase max DX references. Launcher Options -> Settings -> Increase max DX refe
- (v3) PRoot: [GNU GPLv2 License](https://github.com/termux/proot/blob/master/COPYING).<br>
- (v3) XVnc: [GNU GPLv3 License](https://github.com/theqvd/qvd-client-android/blob/master/LICENSE.txt).
- (all) LWJGL 2: [Legacy LWJGL License](http://legacy.lwjgl.org/license.php.html).<br>

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
/** Automatically generated file. DO NOT MODIFY */
package net.kdt.pojavlaunch;
public final class BuildConfig {
public final static boolean DEBUG = true;
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
package com.kdt.minecraftegl;
import android.app.*;
import android.content.*;
import android.os.*;
import android.system.*;
import dalvik.system.*;
import java.lang.reflect.*;
import java.util.*;
import javax.microedition.khronos.egl.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.exit.*;
import static org.lwjgl.opengl.AndroidContextImplementation.*;
import android.content.pm.*;
public class MinecraftEGLInitializer
{
public static void main(String[] args) throws Throwable {
try {
// long surfaceAddress = Long.parseLong(args[0]);
// Disable for testing
ExitManager.disableSystemExit();
MainActivity.launchClassPath = args[0];
MainActivity.launchOptimizedDirectory = args[1];
MainActivity.launchLibrarySearchPath = args[2];
// System.out.println("Received EGL context address: " + Long.toString(eglAddress));
String minecraftMainClass = args[3];
List<String> minecraftArgs = new ArrayList<String>();
for (int i = 5; i < args.length; i++) {
if (args[i] != null && !args[i].isEmpty())
minecraftArgs.add(args[i]);
}
initEnvs();
EGL10 egl;
theEgl = egl = (EGL10) EGLContext.getEGL(); // context.getEGL();
context = egl.eglGetCurrentContext(); // new EGLContextImpl(eglAddress);
display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
read = egl.eglGetCurrentSurface(EGL10.EGL_READ);
draw = egl.eglGetCurrentSurface(EGL10.EGL_DRAW);
boolean makeCurrBool = theEgl.eglMakeCurrent(display, read, draw, context);
System.out.println("Gave up context: " + context + ", makeCurrent: " + Boolean.toString(makeCurrBool));
int eglGetError = egl.eglGetError();
System.out.println("eglGetError: " + Integer.toString(eglGetError) + ", success: " + Boolean.toString(eglGetError == EGL10.EGL_SUCCESS));
System.out.println("user.home: " + System.getProperty("user.home"));
ActivityThread.currentActivityThread().getSystemContext().startActivity(new Intent().setComponent(new ComponentName("net.kdt.pojavlaunch", ".CustomControlsActivity")));
/*
GL10 gl = ((GL10) context.getGL());
gl.glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
int glErr = gl.glGetError();
*/
DexClassLoader classLoader = new DexClassLoader(args[0], args[1], args[2], MinecraftEGLInitializer.class.getClassLoader());
Class minecraftClass = classLoader.loadClass(minecraftMainClass);
Method minecraftMethod = minecraftClass.getMethod("main", String[].class);
minecraftMethod.invoke(null, new Object[]{minecraftArgs.toArray(new String[0])});
} catch (Throwable th) {
System.err.println("UNEXCEPTED SHUTTING DOWN");
th.printStackTrace();
System.exit(1);
}
}
private static EGLConfig getEglConfig(EGL10 egl, EGLDisplay eglDisplay, int[] configAttributes) {
EGLConfig[] configs = new EGLConfig[1];
int[] numConfigs = new int[1];
if (!egl.eglChooseConfig(eglDisplay, configAttributes, configs, configs.length, numConfigs)) {
throw new RuntimeException(
"eglChooseConfig failed: 0x" + Integer.toHexString(egl.eglGetError()));
}
if (numConfigs[0] <= 0) {
throw new RuntimeException("Unable to find any matching EGL config");
}
final EGLConfig eglConfig = configs[0];
if (eglConfig == null) {
throw new RuntimeException("eglChooseConfig returned null");
}
return eglConfig;
}
public static void forceUserHome(String s) throws Exception {
Properties props = System.getProperties();
Class clazz = props.getClass();
Field f = null;
while (clazz != null) {
try {
f = clazz.getDeclaredField("defaults");
break;
} catch (Exception e) {
clazz = clazz.getSuperclass();
}
}
if (f != null) {
f.setAccessible(true);
Properties p = ((Properties) f.get(props));
p.put("user.home", s);
// p.put("user.dir", s);
}
}
public static void initEnvs() throws Exception {
Os.setenv("LIBGL_MIPMAP", "3", true);
System.setProperty("user.home", Tools.MAIN_PATH);
if (!System.getProperty("user.home", "/").equals(Tools.MAIN_PATH)) {
forceUserHome(Tools.MAIN_PATH);
}
System.setProperty("org.apache.logging.log4j.level", "INFO");
System.setProperty("org.apache.logging.log4j.simplelog.level", "INFO");
// Disable javax management for smaller launcher.
System.setProperty("log4j2.disable.jmx", "true");
//System.setProperty("net.zhuoweizhang.boardwalk.org.apache.logging.log4j.level", "INFO");
//System.setProperty("net.zhuoweizhang.boardwalk.org.apache.logging.log4j.simplelog.level", "INFO");
// Change info for useful dump
System.setProperty("java.vm.info", Build.MANUFACTURER + " " + Build.MODEL + ", Android " + Build.VERSION.RELEASE);
}
}

View File

@@ -0,0 +1,32 @@
package com.kdt.minecraftegl;
import android.view.*;
import java.lang.reflect.*;
public class SurfaceUtils
{
public static long getSurfaceAddress(Surface surface) {
try {
Field field = surface.getClass().getDeclaredField("mNativeObject");
field.setAccessible(true);
return field.get(surface);
} catch (Throwable th) {
System.err.println("Unable to get surface address!");
th.printStackTrace();
}
return -1;
}
public static Surface createSurfaceByAddress(long surfaceAddress) {
try {
Constructor c = Surface.class.getDeclaredConstructor(long.class);
c.setAccessible(true);
return (Surface) c.newInstance(surfaceAddress);
} catch (Throwable th) {
System.err.println("Unable to create surface by address!");
th.printStackTrace();
}
return null;
}
}

View File

@@ -37,6 +37,10 @@ import android.graphics.*;
import java.awt.image.*;
import javax.imageio.stream.*;
import java.io.*;
import libcore.net.url.*;
import java.lang.reflect.*;
import java.util.jar.*;
import java.util.zip.*;
/**
* The ImageIO class provides static methods to perform reading and writing
@@ -428,7 +432,26 @@ public final class ImageIO {
if (input == null) {
throw new IllegalArgumentException("input == null!");
}
// DEBUG
/*
if (input.getClass().getName().equals("libcore.net.url.JarURLConnectionImpl$JarURLConnectionInputStream")) {
try {
Field f = input.getClass().getDeclaredField("jarFile");
f.setAccessible(true);
JarFile jf = (JarFile) f.get(input);
Field f2 = input.getClass().getField("fileName");
f2.setAccessible(true);
System.out.println("Found JarFile = " + f2.get(jf).toString());
} catch (Throwable th) {
System.err.println("Unable to get jarFile.");
System.err.println("__________ BEGIN ERR");
th.printStackTrace();
System.err.println("__________ ENDED ERR");
}
}
*/
ImageInputStream stream = createImageInputStream(input);
return read(stream);
}

View File

@@ -24,6 +24,7 @@ package javax.imageio.spi;
import java.io.File;
import java.io.IOException;
import javax.imageio.stream.ImageInputStream;
import net.kdt.pojavlaunch.*;
/**
* The ImageInputStreamSpi abstract class is a service provider interface (SPI)
@@ -126,6 +127,6 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider implements
* if an I/O exception has occurred.
*/
public ImageInputStream createInputStreamInstance(Object input) throws IOException {
return createInputStreamInstance(input, true, null);
return createInputStreamInstance(input, true, new File(Tools.datapath, "cache"));
}
}

View File

@@ -33,6 +33,11 @@ import org.lwjgl.opengl.*;
import sun.security.jca.*;
import android.app.AlertDialog;
import android.graphics.drawable.Drawable;
import net.kdt.pojavlaunch.value.customcontrols.*;
import com.google.android.gles_jni.*;
import com.kdt.minecraftegl.*;
public class MainActivity extends AppCompatActivity implements OnTouchListener, OnClickListener
{
@@ -151,6 +156,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
}
});
/*
ExitManager.setExitTrappedListener(new ExitManager.ExitTrappedListener(){
@Override
public void onExitTrapped()
@@ -202,16 +208,17 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
Log.w(Tools.APP_NAME, "Could not disable System.exit() method!", th);
}
*/
File optDir = getDir("dalvik-cache", 0);
optDir.mkdirs();
launchOptimizedDirectory = optDir.getAbsolutePath();
mProfile = PojavProfile.getCurrentProfileContent(this);
mVersionInfo = Tools.getVersionInfo(mProfile.getVersion());
setTitle("Minecraft " + mProfile.getVersion());
initEnvs();
//System.loadLibrary("gl4es");
/*
if (mVersionInfo.arguments != null) {
@@ -659,6 +666,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
});
glSurfaceView.setOnTouchListener(glTouchListener);
glSurfaceView.setRenderer(new GLTextureView.Renderer() {
private volatile long eglContext = 0l;
@Override
public void onSurfaceDestroyed(GL10 gl) {
Log.d(Tools.APP_NAME, "Surface destroyed.");
@@ -670,6 +678,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
calculateMcScale();
EGL10 egl10 = (EGL10) EGLContext.getEGL();
/*
AndroidContextImplementation.theEgl = egl10;
AndroidContextImplementation.context = egl10.eglGetCurrentContext();
AndroidContextImplementation.display = egl10.eglGetCurrentDisplay();
@@ -678,7 +688,20 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
egl10.eglMakeCurrent(AndroidContextImplementation.display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
System.out.println(new StringBuffer().append("Gave up context: ").append(AndroidContextImplementation.context).toString());
AndroidDisplay.windowWidth += navBarHeight;
*/
EGLContextImpl eglContextImpl = (EGLContextImpl) egl10.eglGetCurrentContext();
try {
Field eglContextField = eglContextImpl.getClass().getDeclaredField("mEGLContext");
eglContextField.setAccessible(true);
eglContext = eglContextField.get(eglContextImpl);
} catch (Throwable th) {
Tools.showError(MainActivity.this, th, true);
}
new Thread(new Runnable(){
@@ -687,7 +710,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
{
try {
Thread.sleep(200);
runCraft();
runCraft(eglContext);
} catch (Throwable e) {
Tools.showError(MainActivity.this, e, true);
}
@@ -905,7 +928,6 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
Tools.showError(MainActivity.this, e, true);
}
}
private boolean isPointerCaptureSupported() {
return Build.VERSION.SDK_INT >= 26;
}
@@ -1001,7 +1023,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
public static String launchClassPath;
public static String launchOptimizedDirectory;
public static String launchLibrarySearchPath;
private void runCraft() throws Throwable //oncreate
private void runCraft(long eglContext) throws Throwable
{
LoggerJava.OnStringPrintListener printLog = new LoggerJava.OnStringPrintListener(){
@Override
@@ -1027,6 +1050,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
launchClassPath = Tools.generateLaunchClassPath(mProfile.getVersion());
launchLibrarySearchPath = getApplicationInfo().nativeLibraryDir;
/* gl4es
if (mVersionInfo.mainClass.equals("net.minecraft.launchwrapper.Launch")) {
net.minecraft.launchwrapper.Launch.main(launchArgs);
@@ -1042,17 +1066,76 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
// Load classpath
DexClassLoader launchBaseLoader = new DexClassLoader(launchClassPath, launchOptimizedDirectory, launchLibrarySearchPath, getClassLoader());
// Launch Minecraft
Class mainClass = launchBaseLoader.loadClass(mVersionInfo.mainClass);
Method mainMethod = mainClass.getMethod("main", String[].class);
mainMethod.setAccessible(true);
mainMethod.invoke(null, new Object[]{launchArgs});
LoggerJava.OnStringPrintListener printLog = new LoggerJava.OnStringPrintListener(){
@Override
public void onCharPrint(char c) {
appendToLog(Character.toString(c));
*/
fixRSAPadding();
System.out.println("> Running Minecraft with classpath:");
System.out.println(launchClassPath);
System.out.println();
ShellProcessOperation shell = new ShellProcessOperation(new ShellProcessOperation.OnPrintListener(){
@Override
public void onPrintLine(String text) {
appendToLog(text);
}
}, "sh");
shell.initInputStream(this);
shell.writeToProcess("base=/system");
shell.writeToProcess("export CLASSPATH=" + getApplicationInfo().publicSourceDir); // ":" + launchClassPath + "\n");
shell.writeToProcess("export HOME=" + Tools.MAIN_PATH);
String argStr = "";
for (String arg : launchArgs) {
argStr = argStr + " " + arg;
}
// app_process32 because this app is 32-bit only.
String execAppProcessStr = (
"exec app_process32 " +
"-Xmx512M " + // Max heap
"-Djava.library.path=/system/lib:" + getApplicationInfo().nativeLibraryDir + " " +
"$base/bin com.kdt.minecraftegl.MinecraftEGLInitializer " +
/* Long.toString(SurfaceUtils.getSurfaceAddress(((SurfaceView) glSurfaceView).getHolder().getSurface())) + "" + */ launchClassPath + " " + launchOptimizedDirectory + " " + launchLibrarySearchPath + " " +
this.mVersionInfo.mainClass + argStr
);
System.out.println(execAppProcessStr);
shell.writeToProcess(execAppProcessStr);
final int waitFor = shell.waitFor();
runOnUiThread(new Runnable(){
@Override
public void run()
{
AlertDialog.Builder d = new AlertDialog.Builder(MainActivity.this);
d.setTitle(R.string.mcn_exit_title);
d.setMessage("Exited with code " + waitFor);
d.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface p1, int p2)
{
// finish();
}
});
d.setCancelable(false);
d.show();
}
});
}
public static void fixRSAPadding(final Activity act) {
/*
private void createEGLHackStuff() {
}
*/
// welcome to the territory of YOLO; I'll be your tour guide for today.
final boolean isLegacyPatch = Build.VERSION.SDK_INT < 24;
@@ -1324,6 +1407,10 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
private void appendToLog(final String text, boolean checkAllow) {
if (checkAllow && !isLogAllow) return;
/*
private void appendToLog(final String text) {
*/
// if (!isLogAllow) r
textLog.post(new Runnable(){
@Override
public void run()
@@ -1418,6 +1505,11 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
// Toast.makeText(MainActivity.this, "Could not exit. Please force close this app.", Toast.LENGTH_LONG).show();
}
private void fullyExit()
{
// TODO: Implement this method
}
})
.show();
}

View File

@@ -9,15 +9,18 @@ public class ShellProcessOperation
private Process process;
public ShellProcessOperation(OnPrintListener listener) throws IOException {
this.listener = listener;
process = Runtime.getRuntime().exec("/system/bin/sh");
this(listener, "sh");
}
public ShellProcessOperation(OnPrintListener listener, String command) throws IOException {
this.listener = listener;
process = Runtime.getRuntime().exec(
command
); //"/system/bin/sh -c \"" + command + "\"");
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
process = builder.start();
//"/system/bin/sh -c \"" + command + "\"");
}
public void writeToProcess(String cmd) throws IOException {

View File

@@ -7,12 +7,12 @@ public class ExitManager {
private static ExitTrappedListener listener;
private static Thread exitTrappedHook = new Thread(new Runnable(){
private boolean isFirst = true;
@Override
public void run()
{
if (listener != null) listener.onExitTrapped();
stopLoop = false;
while (!stopLoop) {
@@ -47,8 +47,11 @@ public class ExitManager {
{
// changeRuntimeExitDisabled(false);
Runtime.getRuntime().removeShutdownHook(exitTrappedHook);
try {
Runtime.getRuntime().removeShutdownHook(exitTrappedHook);
} catch (Throwable th) {
stopExitLoop();
}
}
// It's not safe. Add/Remove shutdown hooks will cause error.

View File

@@ -26,6 +26,7 @@ public class AlphaVanillaTweakInjector implements IClassTransformer {
public LauncherFake(Map map) {
this.map = map;
this.map.put("fullscreen", "true");
}
public void appletResize(int width, int height) {

View File

@@ -115,7 +115,8 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_margin="10dp">
android:layout_margin="10dp"
android:visibility="gone">
<TextView
android:layout_height="wrap_content"