Merge pull request #254 from AngelAuraMC/feat/misc

misc bug fixes
This commit is contained in:
tomikun
2026-05-07 17:47:20 +08:00
committed by GitHub
65 changed files with 124 additions and 31 deletions

1
.gitignore vendored
View File

@@ -13,3 +13,4 @@ app_pojavlauncher/.cxx/
/jre_lwjgl3glfw/gradle/
/jre_lwjgl3glfw/**/build/
/jre_lwjgl3glfw/**/.gradle/
/app_pojavlauncher/curseforge_key.txt

View File

@@ -7,7 +7,7 @@ static def getDate() { return new Date().format('yyyyMMdd') }
def getVersionName = {
// Get the last version tag, as well as the short head of the last commit
ByteArrayOutputStream TAG = new ByteArrayOutputStream()
String semVer = "1.1.4"
String semVer = "1.1.5"
// Used by the fallback for github actions
ByteArrayOutputStream TAG_PART_COMMIT = new ByteArrayOutputStream()
String TAG_STRING
@@ -54,7 +54,7 @@ def getVersionName = {
def getCFApiKey = {
String key = System.getenv("CURSEFORGE_API_KEY");
if(key != null) return key;
File curseforgeKeyFile = new File("./curseforge_key.txt");
File curseforgeKeyFile = new File("$projectDir/curseforge_key.txt");
if(curseforgeKeyFile.canRead() && curseforgeKeyFile.isFile()) {
return curseforgeKeyFile.text;
}

View File

Binary file not shown.

View File

@@ -1 +1 @@
d562b83d28c54d14bbb2f0366ed428945100310e
7e958ece157c2208c2a8c715a4f92b684b112cfa

View File

@@ -1 +1 @@
3999dc44bce7e9d269e034e79c7e430f88a50f3e
80680c59be7562f6efefb301122e421068d6c652

View File

@@ -1 +1 @@
8fc4f7410f7ff1ebea0d604f69d13531814650ca
2be860186e97caa614b289022a73b9774adcb85b

View File

@@ -363,6 +363,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
mControlLayout.requestLayout();
mControlLayout.post(()->{
// Child of mControlLayout, so refreshing size here is correct
Tools.setFullscreen(this, setFullscreen());
minecraftGLView.refreshSize();
Tools.updateWindowSize(this);
mControlLayout.refreshControlButtonPositions();
@@ -418,7 +419,8 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
} catch (RuntimeException ignored){
assetVersion = "legacy";
} // If this fails.. oh well.
// FIXME: Automatic detection should be based on provided hint GLFW_CONTEXT_VERSION_MAJOR and GLFW_CONTEXT_VERSION_MINOR
// Autoselect renderer
if (Tools.LOCAL_RENDERER == null) {
// Preferably we could detect when it is modded and swap to zink however that would also
@@ -426,11 +428,13 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
// experience for no reason. We will compromise with just having users do it themselves.
Tools.LOCAL_RENDERER = "opengles2";
// MobileGlues becomes available post 1.17. It has superior compatibility with mods
// while having fairly similar performance performance compared to GL4ES-based forks.
// while having fairly similar performance compared to GL4ES-based forks.
if(assetVersion.matches("\\d+") || // Should match all digits, which is the modern assetVersioning
"1.17".equals(assetVersion) ||
"1.18".equals(assetVersion) ||
"1.19".equals(assetVersion)) Tools.LOCAL_RENDERER = "opengles_mobileglues";
"1.19".equals(assetVersion) ||
// Angelica gives us GL3.3core on 1.7.10, it's a unique case.
hasMods("angelica")) Tools.LOCAL_RENDERER = "opengles_mobileglues";
}
if(!Tools.checkRendererCompatible(this, Tools.LOCAL_RENDERER)) {
Tools.RenderersList renderersList = Tools.getCompatibleRenderers(this);

View File

@@ -147,7 +147,15 @@ public class MinecraftGLSurface extends View implements GrabListener, DirectGame
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {}
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
/*
Surface recreation in SurfaceView happens very often. When tabbing back in from
out, when minimizing floating window, when turning into floating window, etc.
Whenever the surface isn't in view, it is destroyed. When going into floating
window, it appears to automatically release the associated ANativeWindow. This
can cause a crash if not handled.
*/
}
});
((ViewGroup)getParent()).addView(surfaceView);
@@ -178,6 +186,11 @@ public class MinecraftGLSurface extends View implements GrabListener, DirectGame
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
/*
Surface recreation in TextureView can only really happen once, when turning
into a floating window. Subsequent turns to floating window no longer trigger
recreation. Tabbing out and in does not trigger recreation.
*/
return true;
}

View File

@@ -735,21 +735,44 @@ public final class Tools {
public static String[] getMinecraftJVMArgs(String versionName, File gameDir) {
JMinecraftVersionList.Version versionInfo = Tools.getVersionInfo(versionName, true);
// Parse Forge 1.17+ additional JVM Arguments
if (versionInfo.inheritsFrom == null || versionInfo.arguments == null || versionInfo.arguments.jvm == null) {
return new String[0];
}
Map<String, String> varArgMap = new ArrayMap<>();
varArgMap.put("classpath_separator", ":");
varArgMap.put("library_directory", DIR_HOME_LIBRARY);
varArgMap.put("version_name", versionInfo.id);
varArgMap.put("natives_directory", Tools.NATIVE_LIB_DIR);
varArgMap.put("natives_directory", Tools.DIR_CACHE.getAbsolutePath());
List<String> minecraftArgs = new ArrayList<>();
if (versionInfo.arguments != null) {
if (versionInfo.arguments.jvm != null) {
for (Object arg : versionInfo.arguments.jvm) {
if (arg instanceof String) {
// These are defined later on
if (((String) arg).contains("java.library.path")) {
continue;
}
if (arg.equals("-cp")) {
continue;
}
if (arg.equals("${classpath}")){
continue;
}
// Should fix Forge 1.17.1-37.0.12 and older from crashing
// Fixed in forge on https://github.com/MinecraftForge/MinecraftForge/pull/7919
// Released as Forge 1.17.1-37.0.13 in https://maven.minecraftforge.net/net/minecraftforge/forge/1.17.1-37.0.13/forge-1.17.1-37.0.13-changelog.txt
// yes this duplicates it, it's fine.
// FIXME: Workaround old bootstraplauncher <0.1.17 buggy behaviour. See FCL workaround
// https://github.com/FCL-Team/FoldCraftLauncher/blob/00e96bcf8ddc8a550e9aba6091a73d5bee973b54/FCLCore/src/main/java/com/tungsten/fclcore/download/MaintainTask.java#L198-L200
if (((String) arg).startsWith("-DignoreList=")){
minecraftArgs.add(arg+",${version_name}.jar");
continue;
}
// TODO: Implement adding launcher brand and version
if (((String) arg).contains("minecraft.launcher.brand") ||
((String) arg).contains("minecraft.launcher.version")) {
continue;
}
minecraftArgs.add((String) arg);
} //TODO: implement (?maybe?)
}
@@ -839,7 +862,7 @@ public final class Tools {
library.downloads.artifact.path != null)
return library.downloads.artifact.path;
String[] libInfos = library.name.split(":");
return libInfos[0].replaceAll("\\.", "/") + "/" + libInfos[1] + "/" + libInfos[2] + "/" + libInfos[1] + "-" + libInfos[2] + ".jar";
return libInfos[0].replaceAll("\\.", "/") + "/" + libInfos[1] + "/" + libInfos[2] + "/" + libInfos[1] + "-" + libInfos[2] + (libInfos.length == 4 ? "-" + libInfos[3] : "") + ".jar";
}
private static String getLibClasspath(JMinecraftVersionList.Version info){
@@ -862,9 +885,13 @@ public final class Tools {
String internalLwjglVersion = iLwjglVersion >= 341 ? "3.4.1" : "3.3.3";
File lwjgl3Folder = new File(Tools.DIR_GAME_HOME, "lwjgl3/"+internalLwjglVersion);
String lwjglCore = lwjgl3Folder.getAbsolutePath() + "/lwjgl.jar";
String lwjglMerged = lwjgl3Folder.getAbsolutePath() + "/lwjgl-"+internalLwjglVersion+"-merged-modules";
String lwjglxFile = lwjgl3Folder + "/lwjgl-lwjglx.jar";
launchClasspath.append(lwjglCore).append(":");
// 2nd in priority in case we need to merge lwjgl.jar again for testing
launchClasspath.append(lwjglMerged).append(":");
File[] lwjglModules = lwjgl3Folder.listFiles(pathname ->
pathname.getName().endsWith(".jar") &&

View File

@@ -227,6 +227,9 @@ public class JREUtils {
envMap.put("MG_DIR_PATH", Tools.DIR_DATA + "/MobileGlues");
envMap.put("POJAVEXEC_EGL","libmobileglues.so");
}
if(LOCAL_RENDERER.equals("opengles2")){
envMap.put("LIBGL_ES", "2"); // Krypton Wrapper crashes with 1
}
if (LOCAL_RENDERER.equals("opengles3_desktopgl_zink_kopper")){
envMap.put("POJAVEXEC_EGL","libEGL_mesa.so"); // Use Mesa EGL
if (Tools.shouldUseUBWC()) envMap.put("FD_DEV_FEATURES", "enable_tp_ubwc_flag_hint=1"); // Turnip fix for OneUI rendering issues

View File

@@ -11,6 +11,7 @@
#include "egl_loader.h"
#define TAG __FILE_NAME__
#include <unistd.h>
#include <log.h>
//
@@ -101,10 +102,33 @@ gl_render_window_t* gl_init_context(gl_render_window_t *share) {
}
void gl_swap_surface(gl_render_window_t* bundle) {
if(bundle->nativeSurface != NULL) {
ANativeWindow_release(bundle->nativeSurface);
/*
* In some cases (see MinecraftGLSurface.start(), android kills the surface automatically for
* us, if we try to release/destroy it, we SIGSEGV. Check if we are -19x-19 or some other
* invalid value and skip the release because Android decided to handle releasing it for us.
* This goes against every piece of documentation I have ever seen but who actually reads those?
*
* Some drivers take forever to properly destroy the surface, they do it part at a time or
* some other garbage while SIGSEGVing us if we try releasing while they're in the middle of
* turning the surface dead. This makes the width and height make it look valid when it actually
* isn't so we wait for them and hope there is no race condition of both us and Android trying
* to release the surface. This seems driver dependent as AVD and Waydroid do not need 0.75s
* to set the bloody height and width to their proper values. They just do it, instantly.
*/
usleep(750000); // An overkill amount of time to wait for a surface to finish dying
int32_t nativeWindowWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow);
int32_t nativeWindowHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow);
if ((nativeWindowWidth > 0) || (nativeWindowHeight > 0)) {
LOGI("Native surface dimensions (%d x %d)\n",
nativeWindowWidth, nativeWindowHeight);
if (bundle->nativeSurface != NULL) {
ANativeWindow_release(bundle->nativeSurface);
}
if (bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface);
} else {
LOGW("Native surface dimensions (%d x %d) are invalid! Assuming given nativeSurface is bad.\n",
nativeWindowWidth, nativeWindowHeight);
}
if(bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface);
if(bundle->newNativeSurface != NULL) {
LOGI("Switching to new native surface");
bundle->nativeSurface = bundle->newNativeSurface;

View File

@@ -48,6 +48,10 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
LOGI("Saving DVM environ...");
//Save dalvik global JavaVM pointer
pojav_environ->dalvikJavaVMPtr = vm;
// Sets up the stuff that GLFW/JVM needs to communicate to Android
// These methods are called from GLFW/JVM and connect to Android-side impls
// These aren't separated out into a method because these can be ran so long as we are in Android-land
// so that means this library must be loaded at least once in Android-land
JNIEnv *dvEnv;
(*vm)->GetEnv(vm, (void**) &dvEnv, JNI_VERSION_1_4);
pojav_environ->bridgeClazz = (*dvEnv)->NewGlobalRef(dvEnv,(*dvEnv) ->FindClass(dvEnv,"org/lwjgl/glfw/CallbackBridge"));
@@ -60,17 +64,7 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
LOGI("Saving JVM environ...");
pojav_environ->runtimeJavaVMPtr = vm;
JNIEnv *vmEnv;
(*vm)->GetEnv(vm, (void**) &vmEnv, JNI_VERSION_1_4);
pojav_environ->vmGlfwClass = (*vmEnv)->NewGlobalRef(vmEnv, (*vmEnv)->FindClass(vmEnv, "org/lwjgl/glfw/GLFW"));
pojav_environ->method_glftSetWindowAttrib = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "glfwSetWindowAttrib", "(JII)V");
pojav_environ->method_internalWindowSizeChanged = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "internalWindowSizeChanged", "(J)V");
pojav_environ->method_internalChangeMonitorSize = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "internalChangeMonitorSize", "(II)V");
jfieldID field_keyDownBuffer = (*vmEnv)->GetStaticFieldID(vmEnv, pojav_environ->vmGlfwClass, "keyDownBuffer", "Ljava/nio/ByteBuffer;");
jobject keyDownBufferJ = (*vmEnv)->GetStaticObjectField(vmEnv, pojav_environ->vmGlfwClass, field_keyDownBuffer);
pojav_environ->keyDownBuffer = (*vmEnv)->GetDirectBufferAddress(vmEnv, keyDownBufferJ);
jfieldID field_mouseDownBuffer = (*vmEnv)->GetStaticFieldID(vmEnv, pojav_environ->vmGlfwClass, "mouseDownBuffer", "Ljava/nio/ByteBuffer;");
jobject mouseDownBufferJ = (*vmEnv)->GetStaticObjectField(vmEnv, pojav_environ->vmGlfwClass, field_mouseDownBuffer);
pojav_environ->mouseDownBuffer = (*vmEnv)->GetDirectBufferAddress(vmEnv, mouseDownBufferJ);
(*pojav_environ->runtimeJavaVMPtr)->GetEnv(pojav_environ->runtimeJavaVMPtr, (void**) &vmEnv, JNI_VERSION_1_4);
hookExec(vmEnv);
installLwjglDlopenHook(vmEnv);
installEMUIIteratorMititgation(vmEnv);
@@ -87,6 +81,26 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
return JNI_VERSION_1_4;
}
// Sets up the stuff that Android needs to communicate to GLFW/JVM
// These methods are called from Android and connect to GLFW/JVM-side impls
// These are separated out into a method because GLFW loads much later than when we need to dlopen
// pojavexec since it does more than just GLFW.
// TODO: Add checks in case someone forgets to run this method. Probably see if pojav_environ->vmGlfwClass is null or not
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_GLFW_nativeInitializeGLFWNativeBridge(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz) {
JNIEnv *vmEnv;
(*pojav_environ->runtimeJavaVMPtr)->GetEnv(pojav_environ->runtimeJavaVMPtr, (void**) &vmEnv, JNI_VERSION_1_4);
pojav_environ->vmGlfwClass = (*vmEnv)->NewGlobalRef(vmEnv, (*vmEnv)->FindClass(vmEnv, "org/lwjgl/glfw/GLFW"));
pojav_environ->method_glftSetWindowAttrib = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "glfwSetWindowAttrib", "(JII)V");
pojav_environ->method_internalWindowSizeChanged = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "internalWindowSizeChanged", "(J)V");
pojav_environ->method_internalChangeMonitorSize = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "internalChangeMonitorSize", "(II)V");
jfieldID field_keyDownBuffer = (*vmEnv)->GetStaticFieldID(vmEnv, pojav_environ->vmGlfwClass, "keyDownBuffer", "Ljava/nio/ByteBuffer;");
jobject keyDownBufferJ = (*vmEnv)->GetStaticObjectField(vmEnv, pojav_environ->vmGlfwClass, field_keyDownBuffer);
pojav_environ->keyDownBuffer = (*vmEnv)->GetDirectBufferAddress(vmEnv, keyDownBufferJ);
jfieldID field_mouseDownBuffer = (*vmEnv)->GetStaticFieldID(vmEnv, pojav_environ->vmGlfwClass, "mouseDownBuffer", "Ljava/nio/ByteBuffer;");
jobject mouseDownBufferJ = (*vmEnv)->GetStaticObjectField(vmEnv, pojav_environ->vmGlfwClass, field_mouseDownBuffer);
pojav_environ->mouseDownBuffer = (*vmEnv)->GetDirectBufferAddress(vmEnv, mouseDownBufferJ);
}
#define ADD_CALLBACK_WWIN(NAME) \
JNIEXPORT jlong JNICALL Java_org_lwjgl_glfw_GLFW_nglfwSet##NAME##Callback(JNIEnv * env, jclass cls, jlong window, jlong callbackptr) { \
void** oldCallback = (void**) &pojav_environ->GLFW_invoke_##NAME; \

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -522,10 +522,13 @@ public class GLFW
private static final String PROP_WINDOW_HEIGHT= "glfwstub.windowHeight";
public static long mainContext = 0;
private static long gamepadDataPointer;
private static native void nativeInitializeGLFWNativeBridge();
static {
try {
// Mods like LWJGL3ify have more of a chance of overriding the other classes so
// lets just load it here again just to be safe.
System.loadLibrary("pojavexec");
nativeInitializeGLFWNativeBridge();
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}

View File

Binary file not shown.

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -529,9 +529,13 @@ public class GLFW
public static long mainContext = 0;
private static long gamepadDataPointer;
private static native void nativeInitializeGLFWNativeBridge();
static {
try {
// Mods like LWJGL3ify have more of a chance of overriding the other classes so
// lets just load it here again just to be safe.
System.loadLibrary("pojavexec");
nativeInitializeGLFWNativeBridge();
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}