diff --git a/.gitignore b/.gitignore index 235cf03e66..9fb5d26a8a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ local.properties app_pojavlauncher/.cxx/ .vs/ /curseforge_key.txt +/app_pojavlauncher/libs/ltw-release.aar diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java index dd9f5f10f2..b54d28f8e3 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/MinecraftGLSurface.java @@ -239,7 +239,7 @@ public boolean dispatchGenericMotionEvent(MotionEvent event) { CallbackBridge.sendCursorPos(CallbackBridge.mouseX, CallbackBridge.mouseY); return true; case MotionEvent.ACTION_SCROLL: - CallbackBridge.sendScroll((double) event.getAxisValue(MotionEvent.AXIS_HSCROLL), (double) event.getAxisValue(MotionEvent.AXIS_VSCROLL)); + CallbackBridge.sendScroll(event.getAxisValue(MotionEvent.AXIS_HSCROLL), event.getAxisValue(MotionEvent.AXIS_VSCROLL)); return true; case MotionEvent.ACTION_BUTTON_PRESS: return sendMouseButtonUnconverted(event.getActionButton(),true); @@ -338,8 +338,14 @@ public void refreshSize(boolean immediate) { // Use the width and height of the View instead of display dimensions to avoid // getting squiched/stretched due to inconsistencies between the layout and // screen dimensions. - windowWidth = Tools.getDisplayFriendlyRes(getWidth(), LauncherPreferences.PREF_SCALE_FACTOR); - windowHeight = Tools.getDisplayFriendlyRes(getHeight(), LauncherPreferences.PREF_SCALE_FACTOR); + int newWidth = Tools.getDisplayFriendlyRes(getWidth(), LauncherPreferences.PREF_SCALE_FACTOR); + int newHeight = Tools.getDisplayFriendlyRes(getHeight(), LauncherPreferences.PREF_SCALE_FACTOR); + if (newHeight < 1 || newWidth < 1) { + Log.e("MGLSurface", String.format("Impossible resolution : %dx%d", newWidth, newHeight)); + return; + } + windowWidth = newWidth; + windowHeight = newHeight; if(mSurface == null){ Log.w("MGLSurface", "Attempt to refresh size on null surface"); return; diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 0167492123..a66c61ed1b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -22,11 +22,6 @@ import android.hardware.Sensor; import android.hardware.SensorManager; import android.net.Uri; -import android.opengl.EGL14; -import android.opengl.EGLConfig; -import android.opengl.EGLContext; -import android.opengl.EGLDisplay; -import android.opengl.GLES30; import android.os.Build; import android.os.Bundle; import android.os.Environment; @@ -48,10 +43,6 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.NotificationManagerCompat; -import androidx.core.view.ViewCompat; -import androidx.core.view.WindowCompat; -import androidx.core.view.WindowInsetsCompat; -import androidx.core.view.WindowInsetsControllerCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; @@ -70,6 +61,7 @@ import net.kdt.pojavlaunch.utils.DateUtils; import net.kdt.pojavlaunch.utils.DownloadUtils; import net.kdt.pojavlaunch.utils.FileUtils; +import net.kdt.pojavlaunch.utils.GLInfoUtils; import net.kdt.pojavlaunch.utils.JREUtils; import net.kdt.pojavlaunch.utils.JSONUtils; import net.kdt.pojavlaunch.utils.MCOptionUtils; @@ -233,8 +225,7 @@ private static boolean hasSodium(File gameDir) { * Initialize OpenGL and do checks to see if the GPU of the device is affected by the render * distance issue. - * Currently only checks whether the user has an Adreno GPU capable of OpenGL ES 3 - * and surfaceless rendering installed. + * Currently only checks whether the user has an Adreno GPU capable of OpenGL ES 3. * This issue is caused by a very severe limit on the amount of GL buffer names that could be allocated * by the Adreno properietary GLES driver. @@ -242,44 +233,8 @@ private static boolean hasSodium(File gameDir) { * @return whether the GPU is affected by the Large Thin Wrapper render distance issue on vanilla */ private static boolean affectedByRenderDistanceIssue() { - EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); - if(eglDisplay == EGL14.EGL_NO_DISPLAY || !EGL14.eglInitialize(eglDisplay, null, 0, null, 0)) return false; - int[] egl_attributes = new int[] { - EGL14.EGL_BLUE_SIZE, 8, - EGL14.EGL_GREEN_SIZE, 8, - EGL14.EGL_RED_SIZE, 8, - EGL14.EGL_ALPHA_SIZE, 8, - EGL14.EGL_DEPTH_SIZE, 24, - EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT, - EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, - EGL14.EGL_NONE - }; - EGLConfig[] config = new EGLConfig[1]; - int[] num_configs = new int[]{0}; - if(!EGL14.eglChooseConfig(eglDisplay, egl_attributes, 0, config, 0, 1, num_configs, 0) || num_configs[0] == 0) { - EGL14.eglTerminate(eglDisplay); - Log.e("CheckVendor", "Failed to choose an EGL config"); - return false; - } - int[] egl_context_attributes = new int[] { EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, EGL14.EGL_NONE }; - EGLContext context = EGL14.eglCreateContext(eglDisplay, config[0], EGL14.EGL_NO_CONTEXT, egl_context_attributes, 0); - if(context == EGL14.EGL_NO_CONTEXT) { - Log.e("CheckVendor", "Failed to create a context"); - EGL14.eglTerminate(eglDisplay); - return false; - } - if(!EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, context)) { - Log.e("CheckVendor", "Failed to make context current"); - EGL14.eglDestroyContext(eglDisplay, context); - EGL14.eglTerminate(eglDisplay); - } - boolean is_adreno = GLES30.glGetString(GLES30.GL_VENDOR).equals("Qualcomm") && - GLES30.glGetString(GLES30.GL_RENDERER).contains("Adreno"); - Log.e("CheckVendor", "Running Adreno graphics: "+is_adreno); - EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); - EGL14.eglDestroyContext(eglDisplay, context); - EGL14.eglTerminate(eglDisplay); - return is_adreno; + GLInfoUtils.GLInfo info = GLInfoUtils.getGlInfo(); + return info.isAdreno() && info.glesMajorVersion >= 3; } private static boolean checkRenderDistance(File gamedir) { @@ -1071,6 +1026,8 @@ public static void printLauncherInfo(String gameVersion, String javaArguments) { Logger.appendToLog("Info: API version: " + SDK_INT); Logger.appendToLog("Info: Selected Minecraft version: " + gameVersion); Logger.appendToLog("Info: Custom Java arguments: \"" + javaArguments + "\""); + GLInfoUtils.GLInfo info = GLInfoUtils.getGlInfo(); + Logger.appendToLog("Info: Graphics device: "+info.vendor+ " "+info.renderer+" (OpenGL ES "+info.glesMajorVersion+")"); } public interface DownloaderFeedback { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/mirrors/DownloadMirror.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/mirrors/DownloadMirror.java index f24159a328..2cced7b7ee 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/mirrors/DownloadMirror.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/mirrors/DownloadMirror.java @@ -87,6 +87,29 @@ public static long getContentLengthMirrored(int downloadClass, String urlInput) } } + /** + * Download a file as a string from the current mirror. If the file does not exist on the mirror + * or the mirror returns an invalid string, request the file from the original source + * @param downloadClass Class of the download. Can either be DOWNLOAD_CLASS_LIBRARIES, + * DOWNLOAD_CLASS_METADATA or DOWNLOAD_CLASS_ASSETS + * @param urlInput The original (Mojang) URL for the download + * @return the contents of the downloaded file as a String. + */ + public static String downloadStringMirrored(int downloadClass, String urlInput) throws IOException{ + String resultString = null; + try { + resultString = DownloadUtils.downloadString(getMirrorMapping(downloadClass,urlInput)); + }catch (FileNotFoundException e) { + Log.w("DownloadMirror", "Failed to download string from mirror", e); + } + if(Tools.isValidString(resultString)) { + return resultString; + }else { + Log.w("DownloadMirror", "Downloaded string is invalid, falling back to default"); + } + return DownloadUtils.downloadString(urlInput); + } + /** * Check if the current download source is a mirror and not an official source. * @return true if the source is a mirror, false otherwise diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java index 49b1f6f2f0..048458d30a 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/modloaders/modpacks/api/ModpackInstaller.java @@ -21,7 +21,14 @@ public class ModpackInstaller { public static ModLoader installModpack(ModDetail modDetail, int selectedVersion, InstallFunction installFunction) throws IOException { String versionUrl = modDetail.versionUrls[selectedVersion]; String versionHash = modDetail.versionHashes[selectedVersion]; - String modpackName = modDetail.title.toLowerCase(Locale.ROOT).trim().replace(" ", "_" ); + String modpackName = (modDetail.title.toLowerCase(Locale.ROOT) + " " + modDetail.versionNames[selectedVersion]) + .trim().replaceAll("[\\\\/:*?\"<>| \\t\\n]", "_" ); + if (versionHash != null) { + modpackName += "_" + versionHash; + } + if (modpackName.length() > 255){ + modpackName = modpackName.substring(0,255); + } // Build a new minecraft instance, folder first diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/CustomSeekBarPreference.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/CustomSeekBarPreference.java index 5bb1bd131f..9fc6242a2b 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/CustomSeekBarPreference.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/CustomSeekBarPreference.java @@ -23,6 +23,8 @@ public class CustomSeekBarPreference extends SeekBarPreference { private int mMin; /** The textview associated by default to the preference */ private TextView mTextView; + /** Seekbar increment in case the max gets set */ + private final int mIncrement; @SuppressLint("PrivateResource") @@ -31,6 +33,7 @@ public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyle try (TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SeekBarPreference, defStyleAttr, defStyleRes)) { mMin = a.getInt(R.styleable.SeekBarPreference_min, 0); + mIncrement = a.getInt(R.styleable.SeekBarPreference_seekBarIncrement, 0); } } @@ -111,7 +114,12 @@ public void setSuffix(String suffix) { */ public void setRange(int min, int max){ setMin(min); - setMax(max); + setMaxKeepIncrement(max); + } + + public void setMaxKeepIncrement(int max) { + super.setMax(max); + setSeekBarIncrement(mIncrement); } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java index e61f6c8df5..e7796c34a4 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/LauncherPreferences.java @@ -141,14 +141,14 @@ public static void loadPreferences(Context ctx) { */ private static int findBestRAMAllocation(Context ctx){ int deviceRam = Tools.getTotalDeviceMemory(ctx); - if (deviceRam < 1024) return 300; - if (deviceRam < 1536) return 450; - if (deviceRam < 2048) return 600; + if (deviceRam < 1024) return 296; + if (deviceRam < 1536) return 448; + if (deviceRam < 2048) return 656; // Limit the max for 32 bits devices more harshly - if (is32BitsDevice()) return 700; + if (is32BitsDevice()) return 696; if (deviceRam < 3064) return 936; - if (deviceRam < 4096) return 1148; + if (deviceRam < 4096) return 1144; if (deviceRam < 6144) return 1536; return 2048; //Default RAM allocation for 64 bits } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceJavaFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceJavaFragment.java index 245bf84855..975ec8e089 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceJavaFragment.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceJavaFragment.java @@ -38,7 +38,7 @@ public void onCreatePreferences(Bundle b, String str) { if(is32BitsDevice() || deviceRam < 2048) maxRAM = Math.min(1024, deviceRam); else maxRAM = deviceRam - (deviceRam < 3064 ? 800 : 1024); //To have a minimum for the device to breathe - memorySeekbar.setMax(maxRAM); + memorySeekbar.setMaxKeepIncrement(maxRAM); memorySeekbar.setValue(ramAllocation); memorySeekbar.setSuffix(" MB"); diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceMiscellaneousFragment.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceMiscellaneousFragment.java index 9cdbf9dc9f..5d100a7653 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceMiscellaneousFragment.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/prefs/screens/LauncherPreferenceMiscellaneousFragment.java @@ -1,19 +1,21 @@ package net.kdt.pojavlaunch.prefs.screens; +import android.content.pm.PackageManager; import android.os.Bundle; import androidx.preference.Preference; import net.kdt.pojavlaunch.R; import net.kdt.pojavlaunch.Tools; +import net.kdt.pojavlaunch.utils.GLInfoUtils; public class LauncherPreferenceMiscellaneousFragment extends LauncherPreferenceFragment { @Override public void onCreatePreferences(Bundle b, String str) { addPreferencesFromResource(R.xml.pref_misc); Preference driverPreference = requirePreference("zinkPreferSystemDriver"); - if(!Tools.checkVulkanSupport(driverPreference.getContext().getPackageManager())) { - driverPreference.setVisible(false); - } + PackageManager packageManager = driverPreference.getContext().getPackageManager(); + boolean supportsTurnip = Tools.checkVulkanSupport(packageManager) && GLInfoUtils.getGlInfo().isAdreno(); + driverPreference.setVisible(supportsTurnip); } } diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java index 95074cc804..6c6670384e 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/tasks/MinecraftDownloader.java @@ -395,6 +395,40 @@ private final class DownloaderTask implements Runnable, Tools.DownloaderFeedback this.mSkipIfFailed = skipIfFailed; } + private String downloadSha1() throws IOException { + String downloadedHash = DownloadMirror.downloadStringMirrored( + mDownloadClass, mTargetUrl + ".sha1" + ); + if(!Tools.isValidString(downloadedHash)) return null; + // Ensure that we don't have leading/trailing whitespaces before checking hash length + downloadedHash = downloadedHash.trim(); + // SHA1 is made up of 20 bytes, which means 40 hexadecimal digits, which means 40 chars + if(downloadedHash.length() != 40) return null; + return downloadedHash; + } + + /* + * Maven repositories usually have the hash of a library near it, like: + * .../libraryName-1.0.jar + * .../libraryName.1.0.jar.sha1 + * Since Minecraft libraries are stored in maven repositories, try to use + * this when downloading libraries without hashes in the json. + */ + private void tryGetLibrarySha1() { + String resultHash = null; + try { + resultHash = downloadSha1(); + // The hash is a 40-byte download. + mInternetUsageCounter.getAndAdd(40); + }catch (IOException e) { + Log.i("MinecraftDownloader", "Failed to download hash", e); + } + if(resultHash != null) { + Log.i("MinecraftDownloader", "Got hash: "+resultHash+ " for "+FileUtils.getFileName(mTargetUrl)); + mTargetSha1 = resultHash; + } + } + @Override public void run() { try { @@ -405,6 +439,10 @@ public void run() { } private void runCatching() throws Exception { + if(mDownloadClass == DownloadMirror.DOWNLOAD_CLASS_LIBRARIES && !Tools.isValidString(mTargetSha1)) { + // If we're downloading a library, try to get sha1 since it might be available as a file + tryGetLibrarySha1(); + } if(Tools.isValidString(mTargetSha1)) { verifyFileSha1(); }else { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/GLInfoUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/GLInfoUtils.java new file mode 100644 index 0000000000..15af997c7b --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/GLInfoUtils.java @@ -0,0 +1,167 @@ +package net.kdt.pojavlaunch.utils; + +import android.opengl.EGL14; +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.opengl.GLES20; +import android.opengl.GLES30; +import android.util.Log; + +public class GLInfoUtils { + public static String GLES_VERSION_PREFIX = "OpenGL ES "; + private static GLInfo info; + + private static int getMajorGLVersion(String versionString) { + if(versionString.startsWith(GLES_VERSION_PREFIX)) { + versionString = versionString.substring(GLES_VERSION_PREFIX.length()); + } + int firstDot = versionString.indexOf('.'); + String majorVersion = versionString.substring(0, firstDot).trim(); + return Integer.parseInt(majorVersion); + } + + private static GLInfo queryInfo(int contextGLVersion) { + String vendor = GLES20.glGetString(GLES20.GL_VENDOR); + String renderer = GLES20.glGetString(GLES20.GL_RENDERER); + String versionString = GLES20.glGetString(GLES30.GL_VERSION); + int version = 2; + try { + version = getMajorGLVersion(versionString); + }catch (NumberFormatException e) { + Log.w("GLInfoUtils","Failed to parse GL version number, falling back to 2", e); + } + // LTW depends on the ability to create a context with a major version of 3, + // and even if the string parse returns 3 while EGL can only create 2, + // it's still a noncompilant implementation + version = Math.min(version, contextGLVersion); + return new GLInfo(vendor, renderer, version); + } + + private static void initDummyInfo() { + Log.e("GLInfoUtils", "An error happened during info query. Will use dummy info. This should be investigated."); + info = new GLInfo("", "", 2); + } + + private static EGLContext tryCreateContext(EGLDisplay eglDisplay, EGLConfig config, int majorVersion) { + int[] egl_context_attributes = new int[] { EGL14.EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL14.EGL_NONE }; + EGLContext context = EGL14.eglCreateContext(eglDisplay, config, EGL14.EGL_NO_CONTEXT, egl_context_attributes, 0); + if(context == EGL14.EGL_NO_CONTEXT || context == null) { + Log.e("GLInfoUtils", "Failed to create a context with major version "+majorVersion); + return null; + } + return context; + } + + private static EGLContext tryMakeCurrent(EGLDisplay eglDisplay, EGLConfig config, EGLSurface surface, int majorVersion) { + EGLContext context = tryCreateContext(eglDisplay, config, majorVersion); + if(context == null) return null; + // Old Mali drivers are broken, and will actually let us create a context with GLES 3 + // But won't let us make it current, which will break the check anyway... + boolean makeCurrentResult = EGL14.eglMakeCurrent(eglDisplay, surface, surface, context); + if(!makeCurrentResult) { + Log.i("GLInfoUtils", "Failed to make context GL version "+majorVersion +" current"); + EGL14.eglDestroyContext(eglDisplay, context); + return null; + } + return context; + } + + private static boolean initAndQueryInfo() { + // This is here just to satisfy Android M which incorrectly null-checks it + int[] egl_version = new int[2]; + EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + if(eglDisplay == EGL14.EGL_NO_DISPLAY || !EGL14.eglInitialize(eglDisplay, egl_version, 0 , egl_version, 1)) return false; + int[] egl_attributes = new int[] { + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_ALPHA_SIZE, 8, + EGL14.EGL_DEPTH_SIZE, 24, + EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT, + EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, + EGL14.EGL_NONE + }; + EGLConfig[] config = new EGLConfig[1]; + int[] num_configs = new int[]{0}; + if(!EGL14.eglChooseConfig(eglDisplay, egl_attributes, 0, config, 0, 1, num_configs, 0) || num_configs[0] == 0) { + EGL14.eglTerminate(eglDisplay); + Log.e("GLInfoUtils", "Failed to choose an EGL config"); + return false; + } + + // Create PBuffer surface as some devices might actually not support surfaceless. + int[] pbuffer_attributes = new int[] { + EGL14.EGL_WIDTH, 16, + EGL14.EGL_HEIGHT, 16, + EGL14.EGL_NONE + }; + + EGLSurface surface = EGL14.eglCreatePbufferSurface(eglDisplay, config[0], pbuffer_attributes, 0); + if(surface == null || surface == EGL14.EGL_NO_SURFACE) { + Log.e("GLInfoUtils", "Failed to create pbuffer surface"); + EGL14.eglTerminate(eglDisplay); + return false; + } + + int contextGLVersion = 3; + EGLContext context = tryMakeCurrent(eglDisplay, config[0], surface, contextGLVersion); + if(context == null) { + contextGLVersion = 2; + context = tryMakeCurrent(eglDisplay, config[0], surface, contextGLVersion); + } + + // Creation/currenting failed in both cases + if(context == null) { + Log.e("GLInfoUtils", "Failed to create and make context current"); + EGL14.eglDestroySurface(eglDisplay, surface); + EGL14.eglTerminate(eglDisplay); + return false; + } + + info = queryInfo(contextGLVersion); + + EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); + EGL14.eglDestroyContext(eglDisplay, context); + EGL14.eglTerminate(eglDisplay); + return true; + } + + /** + * Get the information about the current OpenGL ES device, which consists of the vendor, + * the renderer and the major GLES version + * @return the info + */ + public static GLInfo getGlInfo() { + if(info != null) return info; + Log.i("GLInfoUtils", "Querying graphics device info..."); + boolean infoQueryResult = false; + try { + infoQueryResult = initAndQueryInfo(); + }catch (Throwable e) { + Log.e("GLInfoUtils", "Throwable when trying to initialize GL info", e); + } + if(!infoQueryResult) initDummyInfo(); + return info; + } + + public static class GLInfo { + public final String vendor; + public final String renderer; + public final int glesMajorVersion; + protected GLInfo(String vendor, String renderer, int glesMajorVersion) { + this.vendor = vendor; + this.renderer = renderer; + this.glesMajorVersion = glesMajorVersion; + } + + /** + * Check if this GLInfo belongs to a Qualcomm Adreno graphics adapter + * @return + */ + public boolean isAdreno() { + return renderer.contains("Adreno") && vendor.equals("Qualcomm"); + } + } +} diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java index faf2c34d6e..166ec8ac31 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java @@ -32,11 +32,6 @@ import net.kdt.pojavlaunch.prefs.*; import org.lwjgl.glfw.*; -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; - public class JREUtils { private JREUtils() {} @@ -109,7 +104,8 @@ public static void redirectAndPrintJRELog() { public void run() { try { if (logcatPb == null) { - logcatPb = new ProcessBuilder().command("logcat", /* "-G", "1mb", */ "-v", "brief", "-s", "jrelog:I", "LIBGL:I", "NativeInput").redirectErrorStream(true); + // No filtering by tag anymore as that relied on incorrect log levels set in log.h + logcatPb = new ProcessBuilder().command("logcat", /* "-G", "1mb", */ "-v", "brief", "-s", "jrelog", "LIBGL", "NativeInput").redirectErrorStream(true); } Log.i("jrelog-logcat","Clearing logcat"); @@ -192,8 +188,6 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws if(PREF_DUMP_SHADERS) envMap.put("LIBGL_VGPU_DUMP", "1"); - if(PREF_ZINK_PREFER_SYSTEM_DRIVER) - envMap.put("POJAV_ZINK_PREFER_SYSTEM_DRIVER", "1"); if(PREF_VSYNC_IN_ZINK) envMap.put("POJAV_VSYNC_IN_ZINK", "1"); if(Tools.deviceHasHangingLinker()) @@ -240,8 +234,10 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws } reader.close(); } + + GLInfoUtils.GLInfo info = GLInfoUtils.getGlInfo(); if(!envMap.containsKey("LIBGL_ES") && LOCAL_RENDERER != null) { - int glesMajor = getDetectedVersion(); + int glesMajor = info.glesMajorVersion; Log.i("glesDetect","GLES version detected: "+glesMajor); if (glesMajor < 3) { @@ -255,6 +251,11 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws envMap.put("LIBGL_ES", "3"); } } + + if(info.isAdreno() && !PREF_ZINK_PREFER_SYSTEM_DRIVER) { + envMap.put("POJAV_LOAD_TURNIP", "1"); + } + for (Map.Entry env : envMap.entrySet()) { Logger.appendToLog("Added custom env: " + env.getKey() + "=" + env.getValue()); try { @@ -316,7 +317,7 @@ public static void launchJavaVM(final AppCompatActivity activity, final Runtime initJavaRuntime(runtimeHome); JREUtils.setupExitMethod(activity.getApplication()); - JREUtils.initializeGameExitHook(); + JREUtils.initializeHooks(); chdir(gameDirectory == null ? Tools.DIR_GAME_NEW : gameDirectory.getAbsolutePath()); userArgs.add(0,"java"); //argv[0] is the program name according to C standard. @@ -512,68 +513,14 @@ private static boolean hasExtension(String extensions, String name) { } public static int getDetectedVersion() { - /* - * Get all the device configurations and check the EGL_RENDERABLE_TYPE attribute - * to determine the highest ES version supported by any config. The - * EGL_KHR_create_context extension is required to check for ES3 support; if the - * extension is not present this test will fail to detect ES3 support. This - * effectively makes the extension mandatory for ES3-capable devices. - */ - EGL10 egl = (EGL10) EGLContext.getEGL(); - EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - int[] numConfigs = new int[1]; - if (egl.eglInitialize(display, null)) { - try { - boolean checkES3 = hasExtension(egl.eglQueryString(display, EGL10.EGL_EXTENSIONS), - "EGL_KHR_create_context"); - if (egl.eglGetConfigs(display, null, 0, numConfigs)) { - EGLConfig[] configs = new EGLConfig[numConfigs[0]]; - if (egl.eglGetConfigs(display, configs, numConfigs[0], numConfigs)) { - int highestEsVersion = 0; - int[] value = new int[1]; - for (int i = 0; i < numConfigs[0]; i++) { - if (egl.eglGetConfigAttrib(display, configs[i], - EGL10.EGL_RENDERABLE_TYPE, value)) { - if (checkES3 && ((value[0] & EGL_OPENGL_ES3_BIT_KHR) == - EGL_OPENGL_ES3_BIT_KHR)) { - if (highestEsVersion < 3) highestEsVersion = 3; - } else if ((value[0] & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT) { - if (highestEsVersion < 2) highestEsVersion = 2; - } else if ((value[0] & EGL_OPENGL_ES_BIT) == EGL_OPENGL_ES_BIT) { - if (highestEsVersion < 1) highestEsVersion = 1; - } - } else { - Log.w("glesDetect", "Getting config attribute with " - + "EGL10#eglGetConfigAttrib failed " - + "(" + i + "/" + numConfigs[0] + "): " - + egl.eglGetError()); - } - } - return highestEsVersion; - } else { - Log.e("glesDetect", "Getting configs with EGL10#eglGetConfigs failed: " - + egl.eglGetError()); - return -1; - } - } else { - Log.e("glesDetect", "Getting number of configs with EGL10#eglGetConfigs failed: " - + egl.eglGetError()); - return -2; - } - } finally { - egl.eglTerminate(display); - } - } else { - Log.e("glesDetect", "Couldn't initialize EGL."); - return -3; - } + return GLInfoUtils.getGlInfo().glesMajorVersion; } public static native int chdir(String path); public static native boolean dlopen(String libPath); public static native void setLdLibraryPath(String ldLibraryPath); public static native void setupBridgeWindow(Object surface); public static native void releaseBridgeWindow(); - public static native void initializeGameExitHook(); + public static native void initializeHooks(); public static native void setupExitMethod(Context context); // Obtain AWT screen pixels to render on Android SurfaceView public static native int[] renderAWTScreenFrame(/* Object canvas, int width, int height */); diff --git a/app_pojavlauncher/src/main/jni/Android.mk b/app_pojavlauncher/src/main/jni/Android.mk index 6619cd41ea..0763db163b 100644 --- a/app_pojavlauncher/src/main/jni/Android.mk +++ b/app_pojavlauncher/src/main/jni/Android.mk @@ -28,17 +28,17 @@ LOCAL_SRC_FILES := \ ctxbridges/osmesa_loader.c \ ctxbridges/swap_interval_no_egl.c \ environ/environ.c \ + jvm_hooks/emui_iterator_fix_hook.c \ + jvm_hooks/java_exec_hooks.c \ + jvm_hooks/lwjgl_dlopen_hook.c \ input_bridge_v3.c \ jre_launcher.c \ utils.c \ stdio_is.c \ - java_exec_hooks.c \ - lwjgl_dlopen_hook.c \ driver_helper/nsbypass.c ifeq ($(TARGET_ARCH_ABI),arm64-v8a) LOCAL_CFLAGS += -DADRENO_POSSIBLE -LOCAL_LDLIBS += -lEGL -lGLESv2 endif include $(BUILD_SHARED_LIBRARY) @@ -46,7 +46,9 @@ include $(CLEAR_VARS) LOCAL_MODULE := exithook LOCAL_LDLIBS := -ldl -llog LOCAL_SHARED_LIBRARIES := bytehook pojavexec -LOCAL_SRC_FILES := exit_hook.c +LOCAL_SRC_FILES := \ + native_hooks/exit_hook.c \ + native_hooks/chmod_hook.c include $(BUILD_SHARED_LIBRARY) #ifeq ($(TARGET_ARCH_ABI),arm64-v8a) diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c index 8f66139735..0b9ad99a42 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c +++ b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -11,11 +10,13 @@ #include "gl_bridge.h" #include "egl_loader.h" +#define TAG __FILE_NAME__ +#include + // // Created by maks on 17.09.2022. // -static const char* g_LogTag = "GLBridge"; static __thread gl_render_window_t* currentBundle; static EGLDisplay g_EglDisplay; @@ -23,13 +24,11 @@ bool gl_init() { if(!dlsym_EGL()) return false; g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY); if (g_EglDisplay == EGL_NO_DISPLAY) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", - "eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY"); + LOGE("%s", "eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY"); return false; } if (eglInitialize_p(g_EglDisplay, 0, 0) != EGL_TRUE) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglInitialize_p() failed: %04x", - eglGetError_p()); + LOGE("eglInitialize_p() failed: %04x", eglGetError_p()); return false; } return true; @@ -62,14 +61,12 @@ gl_render_window_t* gl_init_context(gl_render_window_t *share) { EGLint num_configs = 0; if (eglChooseConfig_p(g_EglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglChooseConfig_p() failed: %04x", - eglGetError_p()); + LOGE("eglChooseConfig_p() failed: %04x", eglGetError_p()); free(bundle); return NULL; } if (num_configs == 0) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s", - "eglChooseConfig_p() found no matching config"); + LOGE("%s", "eglChooseConfig_p() found no matching config"); free(bundle); return NULL; } @@ -96,8 +93,7 @@ gl_render_window_t* gl_init_context(gl_render_window_t *share) { bundle->context = eglCreateContext_p(g_EglDisplay, bundle->config, share == NULL ? EGL_NO_CONTEXT : share->context, egl_context_attributes); if (bundle->context == EGL_NO_CONTEXT) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglCreateContext_p() finished with error: %04x", - eglGetError_p()); + LOGE("eglCreateContext_p() finished with error: %04x", eglGetError_p()); free(bundle); return NULL; } @@ -110,14 +106,14 @@ void gl_swap_surface(gl_render_window_t* bundle) { } if(bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface); if(bundle->newNativeSurface != NULL) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "Switching to new native surface"); + LOGI("Switching to new native surface"); bundle->nativeSurface = bundle->newNativeSurface; bundle->newNativeSurface = NULL; ANativeWindow_acquire(bundle->nativeSurface); ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, bundle->format); bundle->surface = eglCreateWindowSurface_p(g_EglDisplay, bundle->config, bundle->nativeSurface, NULL); }else{ - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "No new native surface, switching to 1x1 pbuffer"); + LOGI("No new native surface, switching to 1x1 pbuffer"); bundle->nativeSurface = NULL; const EGLint pbuffer_attrs[] = {EGL_WIDTH, 1 , EGL_HEIGHT, 1, EGL_NONE}; bundle->surface = eglCreatePbufferSurface_p(g_EglDisplay, bundle->config, pbuffer_attrs); @@ -136,11 +132,11 @@ void gl_make_current(gl_render_window_t* bundle) { bool hasSetMainWindow = false; if(pojav_environ->mainWindowBundle == NULL) { pojav_environ->mainWindowBundle = (basic_render_window_t*)bundle; - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", pojav_environ->mainWindowBundle); + LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle); pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow; hasSetMainWindow = true; } - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface); + LOGI("Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface); if(bundle->surface == NULL) { //it likely will be on the first run gl_swap_surface(bundle); } @@ -152,7 +148,7 @@ void gl_make_current(gl_render_window_t* bundle) { gl_swap_surface((gl_render_window_t*)pojav_environ->mainWindowBundle); pojav_environ->mainWindowBundle = NULL; } - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglMakeCurrent returned with error: %04x", eglGetError_p()); + LOGE("eglMakeCurrent returned with error: %04x", eglGetError_p()); } } @@ -170,14 +166,14 @@ void gl_swap_buffers() { currentBundle->newNativeSurface = NULL; gl_swap_surface(currentBundle); eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context); - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "The window has died, awaiting window change"); + LOGI("The window has died, awaiting window change"); } } void gl_setup_window() { if(pojav_environ->mainWindowBundle != NULL) { - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is not NULL, changing state"); + LOGI("Main window bundle is not NULL, changing state"); pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW; pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow; } @@ -192,14 +188,14 @@ void gl_swap_interval(int swapInterval) { JNIEXPORT void JNICALL Java_org_lwjgl_opengl_PojavRendererInit_nativeInitGl4esInternals(JNIEnv *env, jclass clazz, jobject function_provider) { - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "GL4ES internals initializing..."); + LOGI("GL4ES internals initializing..."); jclass funcProviderClass = (*env)->GetObjectClass(env, function_provider); jmethodID method_getFunctionAddress = (*env)->GetMethodID(env, funcProviderClass, "getFunctionAddress", "(Ljava/lang/CharSequence;)J"); #define GETSYM(N) ((*env)->CallLongMethod(env, function_provider, method_getFunctionAddress, (*env)->NewStringUTF(env, N))); void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height)) = (void*)GETSYM("set_getmainfbsize"); if(set_getmainfbsize != NULL) { - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "GL4ES internals initialized dimension callback"); + LOGI("GL4ES internals initialized dimension callback"); set_getmainfbsize(gl4esi_get_display_dimensions); } diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/osm_bridge.c b/app_pojavlauncher/src/main/jni/ctxbridges/osm_bridge.c index 814f2e86db..8df959138d 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/osm_bridge.c +++ b/app_pojavlauncher/src/main/jni/ctxbridges/osm_bridge.c @@ -4,10 +4,10 @@ #include #include #include -#include #include "osm_bridge.h" +#define TAG __FILE_NAME__ +#include -static const char* g_LogTag = "GLBridge"; static __thread osm_render_window_t* currentBundle; // a tiny buffer for rendering when there's nowhere t render static char no_render_buffer[4]; @@ -49,13 +49,13 @@ void osm_set_no_render_buffer(ANativeWindow_Buffer* buffer) { void osm_swap_surfaces(osm_render_window_t* bundle) { if(bundle->nativeSurface != NULL && bundle->newNativeSurface != bundle->nativeSurface) { if(!bundle->disable_rendering) { - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Unlocking for cleanup..."); + LOGI("Unlocking for cleanup..."); ANativeWindow_unlockAndPost(bundle->nativeSurface); } ANativeWindow_release(bundle->nativeSurface); } if(bundle->newNativeSurface != NULL) { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, "Switching to new native surface"); + LOGI("Switching to new native surface"); bundle->nativeSurface = bundle->newNativeSurface; bundle->newNativeSurface = NULL; ANativeWindow_acquire(bundle->nativeSurface); @@ -63,8 +63,7 @@ void osm_swap_surfaces(osm_render_window_t* bundle) { bundle->disable_rendering = false; return; }else { - __android_log_print(ANDROID_LOG_ERROR, g_LogTag, - "No new native surface, switching to dummy framebuffer"); + LOGI("No new native surface, switching to dummy framebuffer"); bundle->nativeSurface = NULL; osm_set_no_render_buffer(&bundle->buffer); bundle->disable_rendering = true; @@ -96,7 +95,7 @@ void osm_make_current(osm_render_window_t* bundle) { currentBundle = bundle; if(pojav_environ->mainWindowBundle == NULL) { pojav_environ->mainWindowBundle = (basic_render_window_t*) bundle; - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", pojav_environ->mainWindowBundle); + LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle); pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow; hasSetMainWindow = true; } @@ -130,7 +129,7 @@ void osm_swap_buffers() { void osm_setup_window() { if(pojav_environ->mainWindowBundle != NULL) { - __android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is not NULL, changing state"); + LOGI("Main window bundle is not NULL, changing state"); pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW; pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow; } diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/swap_interval_no_egl.c b/app_pojavlauncher/src/main/jni/ctxbridges/swap_interval_no_egl.c index 580aa9e3ee..159d5a94cc 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/swap_interval_no_egl.c +++ b/app_pojavlauncher/src/main/jni/ctxbridges/swap_interval_no_egl.c @@ -5,9 +5,11 @@ #include #include #include -#include #include +#define TAG __FILE_NAME__ +#include + // Taken from https://android.googlesource.com/platform/frameworks/native/+/41abd67/include/ui/egl/android_natives.h // Might be outdated, if you can find a more recent version please add it there // region android_native_base_t definition @@ -227,17 +229,17 @@ void setNativeWindowSwapInterval(struct ANativeWindow* nativeWindow, int swapInt } struct ANativeWindow_real* nativeWindowReal = (struct ANativeWindow_real*) nativeWindow; if(nativeWindowReal->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) { - __android_log_print(ANDROID_LOG_WARN, "SwapIntervalNoEGL", "ANativeWindow magic does not match. Expected %i, got %i", + LOGW("ANativeWindow magic does not match. Expected %i, got %i", ANDROID_NATIVE_WINDOW_MAGIC, nativeWindowReal->common.magic); return; } if(nativeWindowReal->common.version != sizeof(struct ANativeWindow_real)) { - __android_log_print(ANDROID_LOG_WARN, "SwapIntervalNoEGL", "ANativeWindow version does not match. Expected %i, got %i", + LOGW("ANativeWindow version does not match. Expected %i, got %i", sizeof(struct ANativeWindow_real), nativeWindowReal->common.version); return; } int error; if((error = nativeWindowReal->setSwapInterval(nativeWindow, swapInterval)) != 0) { - __android_log_print(ANDROID_LOG_WARN, "SwapIntervalNoEGL", "Failed to set swap interval: %s", strerror(-error)); + LOGW("Failed to set swap interval: %s", strerror(-error)); } } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c b/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c index 9d854ae25e..16fbe68068 100644 --- a/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c +++ b/app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c @@ -82,7 +82,6 @@ bool linker_ns_load(const char* lib_search_path) { // load the two functions we need android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace"); ld_android_link_namespaces_t android_link_namespaces = dlsym(ld_android_handle, "__loader_android_link_namespaces"); - __android_log_print(ANDROID_LOG_INFO, "nsbypass", "found functions at %p %p", android_create_namespace, android_link_namespaces); if(android_create_namespace == NULL || android_link_namespaces == NULL) { dlclose(ld_android_handle); return false; diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 8b133a30b2..b1d56b8f06 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -99,41 +99,8 @@ EXTERNAL_API void* pojavGetCurrentContext() { //#define ADRENO_POSSIBLE #ifdef ADRENO_POSSIBLE -//Checks if your graphics are Adreno. Returns true if your graphics are Adreno, false otherwise or if there was an error -bool checkAdrenoGraphics() { - EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if(eglDisplay == EGL_NO_DISPLAY || eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE) return false; - EGLint egl_attributes[] = { EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; - EGLint num_configs = 0; - if(eglChooseConfig(eglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE || num_configs == 0) { - eglTerminate(eglDisplay); - return false; - } - EGLConfig eglConfig; - eglChooseConfig(eglDisplay, egl_attributes, &eglConfig, 1, &num_configs); - const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; - EGLContext context = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, egl_context_attributes); - if(context == EGL_NO_CONTEXT) { - eglTerminate(eglDisplay); - return false; - } - if(eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context) != EGL_TRUE) { - eglDestroyContext(eglDisplay, context); - eglTerminate(eglDisplay); - } - const char* vendor = glGetString(GL_VENDOR); - const char* renderer = glGetString(GL_RENDERER); - bool is_adreno = false; - if(strcmp(vendor, "Qualcomm") == 0 && strstr(renderer, "Adreno") != NULL) { - is_adreno = true; // TODO: check for Turnip support - } - eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroyContext(eglDisplay, context); - eglTerminate(eglDisplay); - return is_adreno; -} void* load_turnip_vulkan() { - if(!checkAdrenoGraphics()) return NULL; + if(getenv("POJAV_LOAD_TURNIP") == NULL) return NULL; const char* native_dir = getenv("POJAV_NATIVEDIR"); const char* cache_dir = getenv("TMPDIR"); if(!linker_ns_load(native_dir)) return NULL; @@ -172,8 +139,7 @@ static void set_vulkan_ptr(void* ptr) { } void load_vulkan() { - if(getenv("POJAV_ZINK_PREFER_SYSTEM_DRIVER") == NULL && - android_get_device_api_level() >= 28) { // the loader does not support below that + if(android_get_device_api_level() >= 28) { // the loader does not support below that #ifdef ADRENO_POSSIBLE void* result = load_turnip_vulkan(); if(result != NULL) { @@ -215,6 +181,11 @@ int pojavInitOpenGL() { extern void updateMonitorSize(int width, int height); EXTERNAL_API int pojavInit() { + pojav_environ->glfwThreadVmEnv = get_attached_env(pojav_environ->runtimeJavaVMPtr); + if(pojav_environ->glfwThreadVmEnv == NULL) { + printf("Failed to attach Java-side JNIEnv to GLFW thread\n"); + return 0; + } ANativeWindow_acquire(pojav_environ->pojavWindow); pojav_environ->savedWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow); pojav_environ->savedHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow); diff --git a/app_pojavlauncher/src/main/jni/environ/environ.c b/app_pojavlauncher/src/main/jni/environ/environ.c index 72633d78fa..f75c2eaa9d 100644 --- a/app_pojavlauncher/src/main/jni/environ/environ.c +++ b/app_pojavlauncher/src/main/jni/environ/environ.c @@ -7,11 +7,14 @@ #include #include #include "environ.h" +#define TAG __FILE_NAME__ +#include + struct pojav_environ_s *pojav_environ; __attribute__((constructor)) void env_init() { char* strptr_env = getenv("POJAV_ENVIRON"); if(strptr_env == NULL) { - __android_log_print(ANDROID_LOG_INFO, "Environ", "No environ found, creating..."); + LOGI("No environ found, creating..."); pojav_environ = malloc(sizeof(struct pojav_environ_s)); assert(pojav_environ); memset(pojav_environ, 0 , sizeof(struct pojav_environ_s)); @@ -19,8 +22,8 @@ __attribute__((constructor)) void env_init() { setenv("POJAV_ENVIRON", strptr_env, 1); free(strptr_env); }else{ - __android_log_print(ANDROID_LOG_INFO, "Environ", "Found existing environ: %s", strptr_env); + LOGI("Found existing environ: %s", strptr_env); pojav_environ = (void*) strtoul(strptr_env, NULL, 0x10); } - __android_log_print(ANDROID_LOG_INFO, "Environ", "%p", pojav_environ); + LOGI("%p", pojav_environ); } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/environ/environ.h b/app_pojavlauncher/src/main/jni/environ/environ.h index fbfdb1b095..25dd3d3ab0 100644 --- a/app_pojavlauncher/src/main/jni/environ/environ.h +++ b/app_pojavlauncher/src/main/jni/environ/environ.h @@ -51,9 +51,8 @@ struct pojav_environ_s { jbyte* keyDownBuffer; jbyte* mouseDownBuffer; JavaVM* runtimeJavaVMPtr; - JNIEnv* runtimeJNIEnvPtr_JRE; + JNIEnv* glfwThreadVmEnv; JavaVM* dalvikJavaVMPtr; - JNIEnv* dalvikJNIEnvPtr_ANDROID; long showingWindow; bool isInputReady, isCursorEntered, isUseStackQueueCall, shouldUpdateMouse; bool shouldUpdateMonitorSize, monitorSizeConsumed; diff --git a/app_pojavlauncher/src/main/jni/exit_hook.c b/app_pojavlauncher/src/main/jni/exit_hook.c deleted file mode 100644 index 294fa5c68a..0000000000 --- a/app_pojavlauncher/src/main/jni/exit_hook.c +++ /dev/null @@ -1,82 +0,0 @@ -// -// Created by maks on 15.01.2025. -// - -#include -#include -#include -#include -#include -#include -#include -#include "stdio_is.h" - -static _Atomic bool exit_tripped = false; - -typedef void (*exit_func)(int); - -static void custom_exit(int code) { - // If the exit was already done (meaning it is recursive or from a different thread), pass the call through - if(exit_tripped) { - BYTEHOOK_CALL_PREV(custom_exit, exit_func, code); - BYTEHOOK_POP_STACK(); - return; - } - exit_tripped = true; - // Perform a nominal exit, as we expect. - nominal_exit(code, false); - BYTEHOOK_POP_STACK(); -} - -static void custom_atexit() { - // Same as custom_exit, but without the code or the exit passthrough. - if(exit_tripped) { - return; - } - exit_tripped = true; - nominal_exit(0, false); -} - -static bool init_exit_hook() { - void* bytehook_handle = dlopen("libbytehook.so", RTLD_NOW); - if(bytehook_handle == NULL) { - goto dlerror; - } - - bytehook_stub_t (*bytehook_hook_all_p)(const char *callee_path_name, const char *sym_name, void *new_func, - bytehook_hooked_t hooked, void *hooked_arg); - int (*bytehook_init_p)(int mode, bool debug); - - bytehook_hook_all_p = dlsym(bytehook_handle, "bytehook_hook_all"); - bytehook_init_p = dlsym(bytehook_handle, "bytehook_init"); - - if(bytehook_hook_all_p == NULL || bytehook_init_p == NULL) { - goto dlerror; - } - int bhook_status = bytehook_init_p(BYTEHOOK_MODE_AUTOMATIC, false); - if(bhook_status == BYTEHOOK_STATUS_CODE_OK) { - bytehook_stub_t stub = bytehook_hook_all_p(NULL, "exit", &custom_exit, NULL, NULL); - __android_log_print(ANDROID_LOG_INFO, "exit_hook", "Successfully initialized exit hook, stub=%p", stub); - return true; - } else { - __android_log_print(ANDROID_LOG_INFO, "exit_hook", "bytehook_init failed (%i)", bhook_status); - dlclose(bytehook_handle); - return false; - } - - dlerror: - if(bytehook_handle != NULL) dlclose(bytehook_handle); - __android_log_print(ANDROID_LOG_ERROR, "exit_hook", "Failed to load hook library: %s", dlerror()); - return false; -} - -JNIEXPORT void JNICALL -Java_net_kdt_pojavlaunch_utils_JREUtils_initializeGameExitHook(JNIEnv *env, jclass clazz) { - bool hookReady = init_exit_hook(); - if(!hookReady){ - // If we can't hook, register atexit(). This won't report a proper error code, - // but it will prevent a SIGSEGV or a SIGABRT from the depths of Dalvik that happens - // on exit(). - atexit(custom_atexit); - } -} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 93c1b9041b..d661d0e113 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -19,9 +19,11 @@ #include #include +#define TAG __FILE_NAME__ #include "log.h" #include "utils.h" #include "environ/environ.h" +#include "jvm_hooks/jvm_hooks.h" #define EVENT_TYPE_CHAR 1000 #define EVENT_TYPE_CHAR_MODS 1001 @@ -34,31 +36,33 @@ static void registerFunctions(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { if (pojav_environ->dalvikJavaVMPtr == NULL) { - __android_log_print(ANDROID_LOG_INFO, "Native", "Saving DVM environ..."); + LOGI("Saving DVM environ..."); //Save dalvik global JavaVM pointer pojav_environ->dalvikJavaVMPtr = vm; - (*vm)->GetEnv(vm, (void**) &pojav_environ->dalvikJNIEnvPtr_ANDROID, JNI_VERSION_1_4); - pojav_environ->bridgeClazz = (*pojav_environ->dalvikJNIEnvPtr_ANDROID)->NewGlobalRef(pojav_environ->dalvikJNIEnvPtr_ANDROID,(*pojav_environ->dalvikJNIEnvPtr_ANDROID) ->FindClass(pojav_environ->dalvikJNIEnvPtr_ANDROID,"org/lwjgl/glfw/CallbackBridge")); - pojav_environ->method_accessAndroidClipboard = (*pojav_environ->dalvikJNIEnvPtr_ANDROID)->GetStaticMethodID(pojav_environ->dalvikJNIEnvPtr_ANDROID, pojav_environ->bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); - pojav_environ->method_onGrabStateChanged = (*pojav_environ->dalvikJNIEnvPtr_ANDROID)->GetStaticMethodID(pojav_environ->dalvikJNIEnvPtr_ANDROID, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V"); + JNIEnv *dvEnv; + (*vm)->GetEnv(vm, (void**) &dvEnv, JNI_VERSION_1_4); + pojav_environ->bridgeClazz = (*dvEnv)->NewGlobalRef(dvEnv,(*dvEnv) ->FindClass(dvEnv,"org/lwjgl/glfw/CallbackBridge")); + pojav_environ->method_accessAndroidClipboard = (*dvEnv)->GetStaticMethodID(dvEnv, pojav_environ->bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); + pojav_environ->method_onGrabStateChanged = (*dvEnv)->GetStaticMethodID(dvEnv, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V"); pojav_environ->isUseStackQueueCall = JNI_FALSE; } else if (pojav_environ->dalvikJavaVMPtr != vm) { - __android_log_print(ANDROID_LOG_INFO, "Native", "Saving JVM environ..."); + LOGI("Saving JVM environ..."); pojav_environ->runtimeJavaVMPtr = vm; - (*vm)->GetEnv(vm, (void**) &pojav_environ->runtimeJNIEnvPtr_JRE, JNI_VERSION_1_4); - pojav_environ->vmGlfwClass = (*pojav_environ->runtimeJNIEnvPtr_JRE)->NewGlobalRef(pojav_environ->runtimeJNIEnvPtr_JRE, (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "org/lwjgl/glfw/GLFW")); - pojav_environ->method_glftSetWindowAttrib = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticMethodID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "glfwSetWindowAttrib", "(JII)V"); - pojav_environ->method_internalWindowSizeChanged = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticMethodID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "internalWindowSizeChanged", "(J)V"); - pojav_environ->method_internalChangeMonitorSize = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticMethodID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "internalChangeMonitorSize", "(II)V"); - jfieldID field_keyDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticFieldID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "keyDownBuffer", "Ljava/nio/ByteBuffer;"); - jobject keyDownBufferJ = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticObjectField(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, field_keyDownBuffer); - pojav_environ->keyDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(pojav_environ->runtimeJNIEnvPtr_JRE, keyDownBufferJ); - jfieldID field_mouseDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticFieldID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "mouseDownBuffer", "Ljava/nio/ByteBuffer;"); - jobject mouseDownBufferJ = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticObjectField(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, field_mouseDownBuffer); - pojav_environ->mouseDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(pojav_environ->runtimeJNIEnvPtr_JRE, mouseDownBufferJ); - hookExec(); - installLwjglDlopenHook(); - installEMUIIteratorMititgation(); + 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); + hookExec(vmEnv); + installLwjglDlopenHook(vmEnv); + installEMUIIteratorMititgation(vmEnv); } if(pojav_environ->dalvikJavaVMPtr == vm) { @@ -90,10 +94,10 @@ ADD_CALLBACK_WWIN(Scroll) #undef ADD_CALLBACK_WWIN void updateMonitorSize(int width, int height) { - (*pojav_environ->runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, pojav_environ->method_internalChangeMonitorSize, width, height); + (*pojav_environ->glfwThreadVmEnv)->CallStaticVoidMethod(pojav_environ->glfwThreadVmEnv, pojav_environ->vmGlfwClass, pojav_environ->method_internalChangeMonitorSize, width, height); } void updateWindowSize(void* window) { - (*pojav_environ->runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, pojav_environ->method_internalWindowSizeChanged, (jlong)window); + (*pojav_environ->glfwThreadVmEnv)->CallStaticVoidMethod(pojav_environ->glfwThreadVmEnv, pojav_environ->vmGlfwClass, pojav_environ->method_internalWindowSizeChanged, (jlong)window); } void pojavPumpEvents(void* window) { @@ -228,43 +232,6 @@ void sendData(int type, int i1, int i2, int i3, int i4) { atomic_fetch_add_explicit(&pojav_environ->eventCounter, 1, memory_order_acquire); } -/** - * This function is meant as a substitute for SharedLibraryUtil.getLibraryPath() that just returns 0 - * (thus making the parent Java function return null). This is done to avoid using the LWJGL's default function, - * which will hang the crappy EMUI linker by dlopen()ing inside of dl_iterate_phdr(). - * @return 0, to make the parent Java function return null immediately. - * For reference: https://github.com/PojavLauncherTeam/lwjgl3/blob/fix_huawei_hang/modules/lwjgl/core/src/main/java/org/lwjgl/system/SharedLibraryUtil.java - */ -jint getLibraryPath_fix(__attribute__((unused)) JNIEnv *env, - __attribute__((unused)) jclass class, - __attribute__((unused)) jlong pLibAddress, - __attribute__((unused)) jlong sOutAddress, - __attribute__((unused)) jint bufSize){ - return 0; -} - -/** - * Install the linker hang mitigation that is meant to prevent linker hangs on old EMUI firmware. - */ -void installEMUIIteratorMititgation() { - if(getenv("POJAV_EMUI_ITERATOR_MITIGATE") == NULL) return; - __android_log_print(ANDROID_LOG_INFO, "EMUIIteratorFix", "Installing..."); - JNIEnv* env = pojav_environ->runtimeJNIEnvPtr_JRE; - jclass sharedLibraryUtil = (*env)->FindClass(env, "org/lwjgl/system/SharedLibraryUtil"); - if(sharedLibraryUtil == NULL) { - __android_log_print(ANDROID_LOG_ERROR, "EMUIIteratorFix", "Failed to find the target class"); - (*env)->ExceptionClear(env); - return; - } - JNINativeMethod getLibraryPathMethod[] = { - {"getLibraryPath", "(JJI)I", &getLibraryPath_fix} - }; - if((*env)->RegisterNatives(env, sharedLibraryUtil, getLibraryPathMethod, 1) != 0) { - __android_log_print(ANDROID_LOG_ERROR, "EMUIIteratorFix", "Failed to register the mitigation method"); - (*env)->ExceptionClear(env); - } -} - void critical_set_stackqueue(jboolean use_input_stack_queue) { pojav_environ->isUseStackQueueCall = (int) use_input_stack_queue; } @@ -306,7 +273,7 @@ JNIEXPORT jboolean JNICALL JavaCritical_org_lwjgl_glfw_CallbackBridge_nativeSetI #ifdef DEBUG LOGD("Debug: Changing input state, isReady=%d, pojav_environ->isUseStackQueueCall=%d\n", inputReady, pojav_environ->isUseStackQueueCall); #endif - __android_log_print(ANDROID_LOG_INFO, "NativeInput", "Input ready: %i", inputReady); + LOGI("Input ready: %i", inputReady); pojav_environ->isInputReady = inputReady; return pojav_environ->isUseStackQueueCall; } @@ -482,16 +449,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib( // in environ for the Android UI thread but this is the only place that uses it // (very rarely, only in lifecycle callbacks) so i dont care - JavaVM* jvm = pojav_environ->runtimeJavaVMPtr; - JNIEnv *jvm_env = NULL; - jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4); - if(env_result == JNI_EDETACHED) { - env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL); - } - if(env_result != JNI_OK) { - printf("input_bridge nativeSetWindowAttrib() JNI call failed: %i\n", env_result); - return; - } + JNIEnv *jvm_env = get_attached_env(pojav_environ->runtimeJavaVMPtr); (*jvm_env)->CallStaticVoidMethod( jvm_env, pojav_environ->vmGlfwClass, @@ -557,9 +515,9 @@ static void registerFunctions(JNIEnv *env) { bool use_critical_cc = tryCriticalNative(env); jclass bridge_class = (*env)->FindClass(env, "org/lwjgl/glfw/CallbackBridge"); if(use_critical_cc) { - __android_log_print(ANDROID_LOG_INFO, "pojavexec", "CriticalNative is available. Enjoy the 4.6x times faster input!"); + LOGI("CriticalNative is available. Enjoy the 4.6x times faster input!"); }else{ - __android_log_print(ANDROID_LOG_INFO, "pojavexec", "CriticalNative is not available. Upgrade, maybe?"); + LOGI("CriticalNative is not available. Upgrade, maybe?"); } (*env)->RegisterNatives(env, bridge_class, diff --git a/app_pojavlauncher/src/main/jni/jre_launcher.c b/app_pojavlauncher/src/main/jni/jre_launcher.c index 7ae251f923..6ecfd95d58 100644 --- a/app_pojavlauncher/src/main/jni/jre_launcher.c +++ b/app_pojavlauncher/src/main/jni/jre_launcher.c @@ -185,9 +185,6 @@ JNIEXPORT jint JNICALL Java_com_oracle_dalvik_VMLauncher_launchJVM(JNIEnv *env, jint res = 0; - // Save dalvik JNIEnv pointer for JVM launch thread - pojav_environ->dalvikJNIEnvPtr_ANDROID = env; - if (argsArray == NULL) { LOGE("Args array null, returning"); //handle error diff --git a/app_pojavlauncher/src/main/jni/jvm_hooks/emui_iterator_fix_hook.c b/app_pojavlauncher/src/main/jni/jvm_hooks/emui_iterator_fix_hook.c new file mode 100644 index 0000000000..cb2825d6da --- /dev/null +++ b/app_pojavlauncher/src/main/jni/jvm_hooks/emui_iterator_fix_hook.c @@ -0,0 +1,45 @@ +// +// Created by maks on 23.01.2025. +// + +#include "jvm_hooks.h" +#include + +#define TAG __FILE_NAME__ +#include + +/** + * This function is meant as a substitute for SharedLibraryUtil.getLibraryPath() that just returns 0 + * (thus making the parent Java function return null). This is done to avoid using the LWJGL's default function, + * which will hang the crappy EMUI linker by dlopen()ing inside of dl_iterate_phdr(). + * @return 0, to make the parent Java function return null immediately. + * For reference: https://github.com/PojavLauncherTeam/lwjgl3/blob/fix_huawei_hang/modules/lwjgl/core/src/main/java/org/lwjgl/system/SharedLibraryUtil.java + */ +jint getLibraryPath_fix(__attribute__((unused)) JNIEnv *env, + __attribute__((unused)) jclass class, + __attribute__((unused)) jlong pLibAddress, + __attribute__((unused)) jlong sOutAddress, + __attribute__((unused)) jint bufSize){ + return 0; +} + +/** + * Install the linker hang mitigation that is meant to prevent linker hangs on old EMUI firmware. + */ +void installEMUIIteratorMititgation(JNIEnv *env) { + if(getenv("POJAV_EMUI_ITERATOR_MITIGATE") == NULL) return; + LOGI("Installing..."); + jclass sharedLibraryUtil = (*env)->FindClass(env, "org/lwjgl/system/SharedLibraryUtil"); + if(sharedLibraryUtil == NULL) { + LOGE("Failed to find target class"); + (*env)->ExceptionClear(env); + return; + } + JNINativeMethod getLibraryPathMethod[] = { + {"getLibraryPath", "(JJI)I", &getLibraryPath_fix} + }; + if((*env)->RegisterNatives(env, sharedLibraryUtil, getLibraryPathMethod, 1) != 0) { + LOGE("Failed to register the mitigation method"); + (*env)->ExceptionClear(env); + } +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/java_exec_hooks.c b/app_pojavlauncher/src/main/jni/jvm_hooks/java_exec_hooks.c similarity index 89% rename from app_pojavlauncher/src/main/jni/java_exec_hooks.c rename to app_pojavlauncher/src/main/jni/jvm_hooks/java_exec_hooks.c index 4469ba117d..cc523a4b86 100644 --- a/app_pojavlauncher/src/main/jni/java_exec_hooks.c +++ b/app_pojavlauncher/src/main/jni/jvm_hooks/java_exec_hooks.c @@ -2,15 +2,14 @@ // Created by maks on 05.01.2025. // -#include +#include "jvm_hooks.h" #include #include #include #include -#include -#include -#include +#include "environ/environ.h" +#include "utils.h" static jint (*orig_ProcessImpl_forkAndExec)(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream); @@ -72,18 +71,18 @@ static jint hooked_ProcessImpl_forkAndExec(JNIEnv *env, jobject process, jint mo } // Hook the forkAndExec method in the Java runtime for custom executable overriding. -void hookExec() { - jclass cls; +void hookExec(JNIEnv *env) { + jclass hookClass; orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_UNIXProcess_forkAndExec"); if (!orig_ProcessImpl_forkAndExec) { orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_ProcessImpl_forkAndExec"); - cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/ProcessImpl"); + hookClass = (*env)->FindClass(env, "java/lang/ProcessImpl"); } else { - cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/UNIXProcess"); + hookClass = (*env)->FindClass(env, "java/lang/UNIXProcess"); } JNINativeMethod methods[] = { {"forkAndExec", "(I[B[B[BI[BI[B[IZ)I", (void *)&hooked_ProcessImpl_forkAndExec} }; - (*pojav_environ->runtimeJNIEnvPtr_JRE)->RegisterNatives(pojav_environ->runtimeJNIEnvPtr_JRE, cls, methods, 1); + (*env)->RegisterNatives(env, hookClass, methods, 1); printf("Registered forkAndExec\n"); } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/jvm_hooks/jvm_hooks.h b/app_pojavlauncher/src/main/jni/jvm_hooks/jvm_hooks.h new file mode 100644 index 0000000000..6fd4471b15 --- /dev/null +++ b/app_pojavlauncher/src/main/jni/jvm_hooks/jvm_hooks.h @@ -0,0 +1,14 @@ +// +// Created by maks on 23.01.2025. +// + +#ifndef POJAVLAUNCHER_JVM_HOOKS_H +#define POJAVLAUNCHER_JVM_HOOKS_H + +#include + +void installEMUIIteratorMititgation(JNIEnv *env); +void installLwjglDlopenHook(JNIEnv *env); +void hookExec(JNIEnv *env); + +#endif //POJAVLAUNCHER_JVM_HOOKS_H diff --git a/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c b/app_pojavlauncher/src/main/jni/jvm_hooks/lwjgl_dlopen_hook.c similarity index 82% rename from app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c rename to app_pojavlauncher/src/main/jni/jvm_hooks/lwjgl_dlopen_hook.c index 8694613d14..c9af60513b 100644 --- a/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c +++ b/app_pojavlauncher/src/main/jni/jvm_hooks/lwjgl_dlopen_hook.c @@ -2,16 +2,19 @@ // Created by maks on 06.01.2025. // +#include "jvm_hooks.h" + #include -#include -#include -#include +#include "environ/environ.h" #include #include #include +#define TAG __FILE_NAME__ +#include + extern void* maybe_load_vulkan(); /** @@ -45,12 +48,11 @@ static jlong ndlopen_bugfix(__attribute__((unused)) JNIEnv *env, /** * Install the LWJGL dlopen hook. This allows us to mitigate linker bugs and add custom library overrides. */ -void installLwjglDlopenHook() { - __android_log_print(ANDROID_LOG_INFO, "LwjglLinkerHook", "Installing LWJGL dlopen() hook"); - JNIEnv* env = pojav_environ->runtimeJNIEnvPtr_JRE; +void installLwjglDlopenHook(JNIEnv *env) { + LOGI("Installing LWJGL dlopen() hook"); jclass dynamicLinkLoader = (*env)->FindClass(env, "org/lwjgl/system/linux/DynamicLinkLoader"); if(dynamicLinkLoader == NULL) { - __android_log_print(ANDROID_LOG_ERROR, "LwjglLinkerHook", "Failed to find the target class"); + LOGE("Failed to find the target class"); (*env)->ExceptionClear(env); return; } @@ -58,7 +60,7 @@ void installLwjglDlopenHook() { {"ndlopen", "(JI)J", &ndlopen_bugfix} }; if((*env)->RegisterNatives(env, dynamicLinkLoader, ndlopenMethod, 1) != 0) { - __android_log_print(ANDROID_LOG_ERROR, "LwjglLinkerHook", "Failed to register the hooked method"); + LOGE("Failed to register the hooked method"); (*env)->ExceptionClear(env); } } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/log.h b/app_pojavlauncher/src/main/jni/log.h index f5d2d16f0e..0064486260 100644 --- a/app_pojavlauncher/src/main/jni/log.h +++ b/app_pojavlauncher/src/main/jni/log.h @@ -1,6 +1,9 @@ -#ifdef __ANDROID__ +#ifndef POJAVLAUNCHER_LOG_H +#define POJAVLAUNCHER_LOG_H + #include +#ifndef TAG #define TAG "jrelog" #endif @@ -8,12 +11,14 @@ extern "C" { #endif -#define LOGE(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) -#define LOGW(...) __android_log_print(ANDROID_LOG_SILENT, TAG, __VA_ARGS__) -#define LOGI(...) __android_log_print(ANDROID_LOG_SILENT, TAG, __VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #ifdef __cplusplus } #endif +#endif + diff --git a/app_pojavlauncher/src/main/jni/native_hooks/chmod_hook.c b/app_pojavlauncher/src/main/jni/native_hooks/chmod_hook.c new file mode 100644 index 0000000000..9f798202bc --- /dev/null +++ b/app_pojavlauncher/src/main/jni/native_hooks/chmod_hook.c @@ -0,0 +1,33 @@ +// +// Created by maks on 23.01.2025. +// + +#include "native_hooks.h" +#include +#include + +#define TAG __FILE_NAME__ +#include + +// Hooks for chmod and fchmod that always return success. +// This allows older Android versions to work with Java NIO zipfs inside of the Pojav folder. +typedef int (*chmod_func)(const char*, mode_t); +typedef int (*fchmod_func)(int, mode_t); + +#define TEMPLATE_HOOK(X, Y, Z, W) static int X(Y, mode_t mode) { \ + int result = BYTEHOOK_CALL_PREV(X, Z, W, mode); \ + if(result != 0) errno = 0; \ + BYTEHOOK_POP_STACK(); \ + return 0; \ +} \ + +TEMPLATE_HOOK(custom_chmod, const char* filename, chmod_func, filename) +TEMPLATE_HOOK(custom_fchmod, int fd, fchmod_func, fd) + +#undef TEMPLATE_HOOK + +void create_chmod_hooks(bytehook_hook_all_t bytehook_hook_all_p) { + bytehook_stub_t stub_chmod = bytehook_hook_all_p(NULL, "chmod", &custom_chmod, NULL, NULL); + bytehook_stub_t stub_fchmod = bytehook_hook_all_p(NULL, "fchmod", &custom_fchmod, NULL, NULL); + LOGI("Successfully initialized chmod hooks, stubs: %p %p", stub_chmod, stub_fchmod); +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/native_hooks/exit_hook.c b/app_pojavlauncher/src/main/jni/native_hooks/exit_hook.c new file mode 100644 index 0000000000..3fbe726f42 --- /dev/null +++ b/app_pojavlauncher/src/main/jni/native_hooks/exit_hook.c @@ -0,0 +1,86 @@ +// +// Created by maks on 15.01.2025. +// +#include "native_hooks.h" + +#include +#include +#include +#include +#include +#include "stdio_is.h" + +#define TAG __FILE_NAME__ +#include + +static _Atomic bool exit_tripped = false; + +static int exit_code = 0; + +typedef void (*exit_func)(int); +// Use the exit hook *only* to store the exit code. +static void custom_exit(int code) { + exit_code = code; + BYTEHOOK_CALL_PREV(custom_exit, exit_func, code); + BYTEHOOK_POP_STACK(); +} + +static void custom_atexit() { + if(exit_tripped) { + return; + } + exit_tripped = true; + nominal_exit(exit_code, false); +} + +static void create_hooks(bytehook_hook_all_t bytehook_hook_all_p) { + bytehook_stub_t stub_exit = bytehook_hook_all_p(NULL, "exit", &custom_exit, NULL, NULL); + LOGI("Successfully initialized exit hook, stub: %p", stub_exit); + // Only apply chmod hooks on devices where the game directory is in games/PojavLauncher + // which is below API 29 + if(android_get_device_api_level() < 29) { + create_chmod_hooks(bytehook_hook_all_p); + } +} + +static bool init_hooks() { + void* bytehook_handle = dlopen("libbytehook.so", RTLD_NOW); + if(bytehook_handle == NULL) { + goto dlerror; + } + + bytehook_hook_all_t bytehook_hook_all_p; + int (*bytehook_init_p)(int mode, bool debug); + + bytehook_hook_all_p = dlsym(bytehook_handle, "bytehook_hook_all"); + bytehook_init_p = dlsym(bytehook_handle, "bytehook_init"); + + if(bytehook_hook_all_p == NULL || bytehook_init_p == NULL) { + goto dlerror; + } + int bhook_status = bytehook_init_p(BYTEHOOK_MODE_AUTOMATIC, false); + if(bhook_status == BYTEHOOK_STATUS_CODE_OK) { + create_hooks(bytehook_hook_all_p); + return true; + } else { + LOGE("bytehook_init failed (%i)", bhook_status); + dlclose(bytehook_handle); + return false; + } + + dlerror: + if(bytehook_handle != NULL) dlclose(bytehook_handle); + LOGE("Failed to load hook library: %s", dlerror()); + return false; +} + +JNIEXPORT void JNICALL +Java_net_kdt_pojavlaunch_utils_JREUtils_initializeHooks(JNIEnv *env, jclass clazz) { + bool hooks_ready = init_hooks(); + if(!hooks_ready) { + LOGE("Failed to initialize native hooks!"); + } + // Always register atexit, because that's what we will call our exit from. + // We only use the hook to capture the exit code. + atexit(custom_atexit); +} \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/native_hooks/native_hooks.h b/app_pojavlauncher/src/main/jni/native_hooks/native_hooks.h new file mode 100644 index 0000000000..a99a8182ca --- /dev/null +++ b/app_pojavlauncher/src/main/jni/native_hooks/native_hooks.h @@ -0,0 +1,15 @@ +// +// Created by maks on 23.01.2025. +// + +#ifndef POJAVLAUNCHER_NATIVE_HOOKS_H +#define POJAVLAUNCHER_NATIVE_HOOKS_H + +#include + +typedef bytehook_stub_t (*bytehook_hook_all_t)(const char *callee_path_name, const char *sym_name, void *new_func, + bytehook_hooked_t hooked, void *hooked_arg); + +void create_chmod_hooks(bytehook_hook_all_t bytehook_hook_all_p); + +#endif //POJAVLAUNCHER_NATIVE_HOOKS_H diff --git a/app_pojavlauncher/src/main/jni/utils.c b/app_pojavlauncher/src/main/jni/utils.c index 571bc72545..e703629c55 100644 --- a/app_pojavlauncher/src/main/jni/utils.c +++ b/app_pojavlauncher/src/main/jni/utils.c @@ -157,6 +157,19 @@ JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_executeBinary(JNI return result; } +JNIEnv* get_attached_env(JavaVM* jvm) { + JNIEnv *jvm_env = NULL; + jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4); + if(env_result == JNI_EDETACHED) { + env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL); + } + if(env_result != JNI_OK) { + printf("get_attached_env failed: %i", env_result); + return NULL; + } + return jvm_env; +} + // METHOD 2 /* JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_executeForkedBinary(JNIEnv *env, jclass clazz, jobjectArray cmdArgs) { diff --git a/app_pojavlauncher/src/main/jni/utils.h b/app_pojavlauncher/src/main/jni/utils.h index 69583c44eb..7ebd1dedd8 100644 --- a/app_pojavlauncher/src/main/jni/utils.h +++ b/app_pojavlauncher/src/main/jni/utils.h @@ -11,8 +11,6 @@ jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray); jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr); -void hookExec(); -void installLwjglDlopenHook(); -void installEMUIIteratorMititgation(); +JNIEnv* get_attached_env(JavaVM* jvm); JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc); diff --git a/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml b/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml index b53b968127..6d6c265a2f 100644 --- a/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml +++ b/app_pojavlauncher/src/main/res/layout/fragment_profile_editor.xml @@ -179,6 +179,8 @@ android:layout_marginEnd="@dimen/padding_medium" android:background="@drawable/background_line" android:ems="10" + android:maxLines="2" + android:ellipsize="end" android:hint=".minecraft" android:paddingHorizontal="@dimen/padding_heavy" diff --git a/app_pojavlauncher/src/main/res/values-ar/strings.xml b/app_pojavlauncher/src/main/res/values-ar/strings.xml index a032eae85d..fc7a49bc94 100644 --- a/app_pojavlauncher/src/main/res/values-ar/strings.xml +++ b/app_pojavlauncher/src/main/res/values-ar/strings.xml @@ -9,10 +9,11 @@ اسم المستخدم تسجيل الدخول + "أضغط على أيقونة الإعدادات في أعلى منتصف الشاشة لفتح قائمة التعديلات ⚙\nأضغط على زر للتخصيص: تغيير, تعديل الحجم، حذف، أو تعديل أزرار التحكم." سيتم إزالة هذا الحساب! - حدد مشغل مودات للتثبيت + حدد مشغل مودات لتثبيته لقد توقف PojavLauncher بشكل غير متوقع لا يوجد إصدار! @@ -36,7 +37,7 @@ تخصيص التحكم استخدام عرض الأسطح البديل قد يساعد الأداء في سيناريوهات المعتمدة على GPU. - تجاهل النوتش (الجزء المفقود من أعلى الشاشة مع الكاميرا الأمامية) + تجاهل النوتش (الجزء المفقود من أعلى الشاشة قرب الكاميرا الأمامية) تجاهل النوتش وتوسيع الشاشة أسفلها.\nيعطيك تجرِبة أكثر انغماساً. مقياس الدقة يسمح لك بتخفيض دقة اللعبة. 100% هي الدقة الكاملة. @@ -51,6 +52,7 @@ عارض الرسوميات Holy GL4ES - (جميع الإصدارات، سريع) Zink (Vulkan) - (جميع الإصدارات، متوسط) + LTW (OpenGL ES 3) - 1.17+ فقط إصدار نهائي اللمحات \"سنابشوت\" نسخ ألفا قديمة @@ -75,6 +77,7 @@ الافتراضي تم الخروج من التطبيق/اللعبة بخلل %d، تحقق من latestlog.txt لمزيد من التفاصيل. + تم الخروج من التطبيق/اللعبة بخلل %d، انظر في latestlog.txt لمزيد من التفاصيل. هل أنت متأكد من أنك تريد فرض الإغلاق؟ عارض الرسوميات Zink (Vulkan) غير مدعوم على هذا الجهاز! @@ -145,6 +148,7 @@ قفل إلى الأمام تتبع الأصابع بشكل مطلق الكَمَيَّة الحالية من ذاكرة الوصول العشوائي المتاحة للاستخدام (%d) أقل من ذاكرة الوصول العشوائي المحددة (%d)، مما قد يؤدي إلى حدوث أعطال. غير الذاكرة المخصصة إذا توقفت اللعبة. + الكَمَيَّة الحالية من ذاكرة الوصول العشوائي المتاحة للاستخدام (%d) أقل من ذاكرة الوصول العشوائي المحددة (%d)، مما قد يؤدي إلى حدوث أعطال. غير الذاكرة المخصصة إذا توقفت اللعبة. الذاكرة المخصصة للاستخدام يتحكم في كَمَيَّة الذاكرة المعطاة لـ Minecraft. بيئة تشغيل Java تالفة @@ -157,6 +161,7 @@ تعيين كافتراضي الافتراضي يجب أن يكون لديك على الأقل بيئة تشغيل جافا واحدة مثبتة. + لم يتم العثور على أي بيئة تشغيل Java متوافقة، هذا الإصدار يتطلب Java %d أو أحدث. لا يمكن العثور على Java 8. لاستخدام هذا الخِيار، تحتاج إلى تثبيت Java 8. حذف بيئة التشغيل مكان تخزين اللعبة @@ -238,6 +243,7 @@ تمكين افراغ الشادر سجل الShaders المحولة داخل ملف السجل. %d%% + %d جزء من الثانية مغادرة؟ هل أنت متأكد من أنك تريد الخروج؟ مغادرة المحرر @@ -319,15 +325,57 @@ السماح بالإشعارات . السماح بتفعيل V-Sync مع Zink - يسمح للمشغل باستخدام APIs النظام الداخلي لتمكين V-Sync للزنك. قم بإيقاف تشغيل هذا إذا تعطل المشغل فجأة مع الزنك بعد تحديث النظام. + يسمع للمشغل فشل تثبيت JRE 17 قراءة بيانات تعريف اللعبة… تحميل بيانات تعريف اللعبة (%s) + جاري تحميل اللعبة… (%d/%d, %.2f MB/s) + جاري تحميل اللعبة… (%.2f/%.2f MB، %.2f MB/s) + اختيار منطقة الصورة + تأمين المحور العمودي + تأمين المحور الأفقي + إعادة الضبط + تم إلغاء الاختيار + إيقاف التمرير التلقائي\n + إيقاف التمرير التلقائي\n + المخرجات\nمتوقفة + المخرجات\nمفعلة + سِجل الإخراج: + فشل في قراءة ملف .jar + تنفيذ وظيفة .jar غير متوافق مع Java %d A B X Y Start اختر + الزناد الأيسر + الزناد الأيمن + الكتف الأيسر + الكتف الأيمن + العصا للأعلى + العصا للأسفل + العصا لليسار + العصا لليمين + انقر فوق عصا الأصبع الأيسر + انقر فوق عصا الأصبع الأيمن + D-Pad للأعلى + D-Pad للأسفل + D-Pad لليسار + D-Pad لليمين + اثبت + للخروج + الوضع الحالي الظهور + داخل اللعبة + في القوائم + قم بالتوسعة لتغيير رمز الزر + تغيير إعدادات مفاتيح التحكم + يسمح لك بتعديل المفتاح المخصص لكل زر في وحدة التحكم + سيرفر الديسكورد + وحدة معالجة الرسوميات الخاصة بك غير قادرة على معالجة أكثر من 7 رندر ديستانس دون مود Sodium أو غيرها من المودات المشابهة. سيتم تخفيض الرندر ديستانس تلقائيًا عند النقر على \"موافق\". + فتح ملفات اللعبة + اسم المستخدم غير مناسب + يجب أن يكون اسم المستخدم بين 3–16 حرفاً، ويجب أن يحتوي فقط على أحرف لاتينية وأرقام 0-9 وتسطيرات سفلية. + قائمة الإعدادات السريعة diff --git a/app_pojavlauncher/src/main/res/values-cs/strings.xml b/app_pojavlauncher/src/main/res/values-cs/strings.xml index 5b2db93aa9..7f20a250eb 100644 --- a/app_pojavlauncher/src/main/res/values-cs/strings.xml +++ b/app_pojavlauncher/src/main/res/values-cs/strings.xml @@ -9,6 +9,7 @@ Uživatelské jméno Přihlásit se + "Klikněte na ikonu ozubeného kolečka nahoře uprostřed pro otevření menu ⚙\nKlikněte na tlačítko pro přizpůsobení: editaci, škálu, odstranění či změnu kláves." Tento účet bude odstraněn! @@ -20,7 +21,7 @@ Zobrazit méně Je vyžadováno oprávnění pro čtení/zápis do úložiště! - Instalace byla úspěšná + Instalace proběhla úspěšně @@ -28,29 +29,30 @@ Wiki - Čištění souborů mezipaměti + Čištění mezipaměti Stahování %s "Stahování %s (%.2f MB / %.2f MB)" Příprava ke stažení prostředků Možnosti Vlastní ovládací prvky Použít jiné vykreslování povrchu - Může zvýšit výkon v situacích, kdy je zatížená GPU. + Může zvýšit výkon v situacích, kdy je více zatížené GPU. Ignorovat výřez - Ignoruje výřez a rozšíří obrazovku pod ním.\nDá více celo-obrazný pohlcující zážitek. + Ignoruje výřez a rozšíří obrazovku pod ním.\nDodá více pohlcující zážitek. Škála rozlišení Umožňuje snížit rozlišení hry. 100% je plné rozlišení. - Zpoždění dlouhého stisku + Zpoždění přidržení Změní délku stisku ke zničení bloků a vyhazování itemů. Škálování kontrolních tlačítek - Zvětšte je, jsou-li tlačítka příliš malá. - Škálování myši - Změnit velikost virtuální myši. + Zvětšete pokud jsou tlačítka příliš malá. + Velikost myši + Změní velikost virtuální myši. JVM spouštěcí argumenty Buďte opatrní, toto může způsobit pád hry, je-li upraveno bez znalostí. Vykreslovač - Holy GL4ES - (všechny verze, rychlá) + Holy GL4ES - (všechny verze, rychlý) Zink (Vulkan) - (všechny verze, střední) + LTW (OpenGL ES 3) - jen 1.17+ Vydání Snapshot Stará alfa @@ -75,6 +77,7 @@ Výchozí Aplikace/Hra spadla s kódem %d, zkontroluj latestlog.txt pro více informací. + Aplikace/Hra skončila s fatálním signálem %d, zkontroluj latestlog.txt pro detaily. Opravdu chcete vynutit ukončení? Vykreslovač Zink (Vulkan) není v tomto zařízení podporován! @@ -145,6 +148,7 @@ Uzamknout chození vpřed Absolutní následování prstu Aktuální množství volné paměti RAM (%d) je nižší než přidělená paměť RAM (%d), což může vést k pádu. Spadne-li hra, snižte přidělení paměti. + Aktuální množství volné přístupné paměti RAM (%d) je nižší než přidělená paměť RAM (%d), což povede k pádu. Spadne-li hra, sniž přidělení paměti. Přidělení paměti Určuje množství paměti přidělené Minecraftu. Poškozená Java Runtime @@ -157,6 +161,7 @@ Nastavit výchozí Výchozí Musíte mít nainstalovanou alespoň jednu verzi Javy. + Nelze najít žádnou podporovanou Java Runtime. Tato verze vyžaduje Javu %d nebo novější. Nelze najít Javu 8. Chcete-li používat tuto možnost, musíte mít nainstalovanou Javu 8. Smazat runtime Složka hry @@ -238,6 +243,7 @@ Povolit vyhazování shaderů Zaznamenat převedené shadery do souboru záznamu. %d%% + %d ms Odcházíte? Určitě chcete odejít? Opustit editor @@ -326,11 +332,53 @@ Instalace JRE 17 selhala Čtení metadat hry… Stahování metadat hry (%s) + Stahování hry… (%d/%d, %.2f MB) + Stahování hry… (%.2f/%.2f MB, %.2f MB/s) + Vyberte oblast oříznutí + Zamknout svisle + Zamknout Vodorovně + Resetovat + Výběr zrušen + Samoskrolování\nVypnuto + Samoskrolování\nZapnuto + Výstup\nVypnuto + Výstup\nZapnuto + Výstup záznamu: + Selhalo čtení souboru .jar + Funkce spouštění .jar souboru není kompatibilní s Javou %d A B X Y Start Vybrat + Levá spoušť + Pravá spoušť + Levé tlačítko + Pravé tlačítko + Páčka nahoru + Páčka dolů + Páčka doleva + Páčka doprava + Kliknutí levé páčky + Kliknutí pravé páčky + D-Pad nahoru + D-Pad dolů + D-Pad doleva + D-Pad doprava + Drž + pro ukončení + Aktuální mód Viditelnost + Ve hře + V menech + Rozbal pro změny kódů kláves + Změnit nastavení kláves ovladače + Umožňuje změnit jaké klávesy každé tlačítko ovladače produkuje + Discord + Tvá GPU není schopna vykreslovat víc než 7 chunků dohledu bez Sodium či podobnách módů. Vykreslovací vzdálenost bude snížena kliknete-li \"OK\". + Otevřít složku hry + Špatné uživatelské jméno + Uživatelské jméno musí být mezi 3 až 16 znaky, musí být pouze v latince s čísly a podtržítkem. + Rychlá nastavení diff --git a/app_pojavlauncher/src/main/res/values-de/strings.xml b/app_pojavlauncher/src/main/res/values-de/strings.xml index 1fe4c59c44..0bc27404ad 100644 --- a/app_pojavlauncher/src/main/res/values-de/strings.xml +++ b/app_pojavlauncher/src/main/res/values-de/strings.xml @@ -9,6 +9,7 @@ Benutzername Anmelden + "Tippe auf das Zahnradsymbol oben in der Mitte, um das Kontextmenü zu öffnen ⚙.\nTippe auf eine Schaltfläche, um sie anzupassen: Bearbeiten, Größe ändern, Löschen oder die Tastenzuordnung ändern." Dieses Konto wird entfernt! @@ -51,6 +52,7 @@ Renderer Holy GL4ES - (alle Versionen, schnell) Zink (Vulkan) - (alle Versionen, mittel) + LTW (OpenGL ES 3) - nur 1.17+ Vollversionen Entwicklungsversionen Alte Alpha @@ -75,6 +77,7 @@ Standard Anwendung/Spiel wurde mit dem Code %d beendet. Für weitere Details, siehe latestlog.txt. + Anwendung/Spiel wurde mit dem Fehlercode %d beendet. Für weitere Details, siehe latestlog.txt. Beenden wirklich erzwingen? Der Zink-Renderer (Vulkan) wird auf diesem Gerät nicht unterstützt! @@ -145,6 +148,7 @@ Weiterleitungssperre Absolutes Finger-Tracking Die aktuelle Menge an freiem RAM (%d) ist niedriger als zugewiesener RAM (%d), was zu Abstürzen führen kann. Ändere die Zuordnung, wenn das Spiel abstürzt. + Der aktuelle freie adressierbare RAM-Speicherplatz (%d) ist niedriger als der zugewiesene RAM (%d), was zu Abstürzen führen wird. Sollte das Spiel abstürzen, ändere die Zuweisung. Zugewiesener RAM Legt fest, wie viel Arbeitsspeicher Minecraft zugewiesen wird. Beschädigte Java-Runtime @@ -157,6 +161,7 @@ Als Standard festlegen Standard Es muss mindestens eine Java-Laufzeit installiert sein. + Es wurde keine kompatible Java Runtime gefunden. Diese Version benötigt Java %d oder neuer. Java 8 kann nicht gefunden werden. Um diese Option nutzen zu können, musst du Java 8 installieren. Laufzeit löschen Spielverzeichnis @@ -238,6 +243,7 @@ Shader-Dumping aktivieren Konvertierte Shader mit in die Protokolldatei schreiben. %d%% + %d ms Gehst Du? Wollen Sie das Spiel wirklich beenden? Editor beenden @@ -326,11 +332,53 @@ Um die offizielle Download-Quelle zu verwenden, drücke \"Auf offizielle Seite u Konnte JRE 17 nicht installieren Lese Spiel-Metadaten… Lade Spiel-Metadaten herunter (%s) + Lade das Spiel herunter… (%d/%d, %.2f MB) + Lade das Spiel herunter… (%.2f/%.2f MB, %.2f MB/s) + Bildbereich auswählen + Vertikaler Lock + Horizontaler Lock + Zurücksetzen + Auswahl abgebrochen + Autoscrollen\nAUS + Autoscrollen\nAN + Ausgabe\nAUS + Ausgabe\nAN + Protokoll-Ausgabe: + Fehler beim Lesen der .jar-Datei + Die Ausführung der .jar-Funktion ist nicht kompatibel mit Java %d A B X Y Start Auswählen + Linker Trigger + Rechter Trigger + Linke Schultertaste + Rechte Schultertaste + Stick (hoch) + Stick (runter) + Stick (links) + Stick (rechts) + Linker Thumbstick (Klick) + Rechter Thumbstick (Klick) + Steuerkreuz hoch + Steuerkreuz unten + Steuerkreuz links + Steuerkreuz rechts + Halte + gedrückt zum Beenden + Aktueller Modus Sichtbarkeit + Ingame + In den Menüs + Zeige mehr an, um die Keycodes zu ändern + Controller-Tastenbelegung ändern + Ermöglicht es dir, die Tastaturtaste zu ändern, die jeder Controller-Taste zugeordnet ist + Discord + Deine GPU ist ohne Sodium oder ähnliche Mods nicht in der Lage, eine Renderdistanz von über 7 Chunks zu rendern. Solltest du auf OK tippen, wird die Renderdistanz automatisch reduziert. + Spielverzeichnis öffnen + Ungeeigneter Benutzername + Der Benutzername muss zwischen 3–16 Zeichen lang sein und darf nur lateinische Buchstaben, Ziffern 0–9 und Unterstriche enthalten. + Schnelleinstellungen diff --git a/app_pojavlauncher/src/main/res/values-es/strings.xml b/app_pojavlauncher/src/main/res/values-es/strings.xml index a86d733e1b..d9324861bd 100644 --- a/app_pojavlauncher/src/main/res/values-es/strings.xml +++ b/app_pojavlauncher/src/main/res/values-es/strings.xml @@ -51,6 +51,7 @@ Renderizador Holy GL4ES - (Todas las versiones, rápido) Zink (Vulkan) - (todas las versiones, medio) + LTW (OpenGL ES 3) - solo 1.17+ Lanzamientos Snapshots Alphas @@ -75,6 +76,7 @@ Predeterminado La aplicación/juego ha finalizado con el código %d, mira el archivo latestlog.txt para más detalles. + La aplicación/juego ha finalizado con código %d, revise latestlog.txt para más detalles. ¿Estás seguro de que quieres forzar el cierre? ¡El renderizador Zink (Vulkan) no es compatible con este dispositivo! @@ -145,6 +147,7 @@ Bloqueo hacia adelante Seguimiento absoluto del dedo La cantidad actual de memoria RAM libre (%d) es menor que la memoria RAM asignada (%d), lo que puede provocar cierres forzados. Cambia la asignación si el juego se cierra. + La cantidad actual de RAM libre (%d) es menor que la RAM asignada (%d), lo cual puede causar cierres forzados. Cambie la cantidad asignada si el juego se cierra. Asignación de memoria Controla cuánta memoria se le da a Minecraft. Java Runtime Corrupto @@ -157,6 +160,7 @@ Establecer como predeterminado Predeterminado Debes tener al menos un Runtime de Java instalado. + No se encontró ningún Java Runtime compatible. Esta versión requiere de Java %d o superior. No se puede encontrar Java 8. Para utilizar esta opción, necesita instalar Java 8. Eliminar runtime Directorio del juego @@ -238,6 +242,7 @@ Activar dumpeo de shaders Registra shaders compilados (sic). %d%% + %d ms ¿Vas a salir? ¿Estás seguro de que quieres salir? Salir del editor @@ -246,7 +251,7 @@ No La configuración del control fue borrada. Ajustes del control - Restablecer mapeo del mando + Restablecer mapeo del control Te permite cambiar los botones del control. Escala de la zona muerta del Joystick Auméntalo si el joystick tiene drift. @@ -326,11 +331,36 @@ Error al instalar JRE 17 Leyendo metadatos… Descargando metadatos del juego (%s) + Descargando el juego...(%d/%d,%.2f MB/s) + Descargando el juego...(%.2f/%.2f MB, %.2f MB/s) + Seleccione la región de la imagen + Reiniciar + Selección cancelada + Desplazamiento automático\nApagado + Desplazamiento automático\nEncendido + Salida\nApagado + Salida\nEncendido + Salida del registro: + Falló al leer el archivo .jar + La característica para ejecutar .jar no es compatible con Java %d A B X Y Start Seleccionar + Activador izquierdo + Activador derecho + Mantenga + para salir + Modo actual Visibilidad + Cambiar configuración de teclas del controlador + Te permite modificar las teclas del teclado asignadas a cada botón del controlador + Discord + Su GPU no es capaz de renderizar más de 7 de distancia sin usar Sodium o mods similares. La distancia de renderizado será reducido automáticamente cuando haga click en \"OK\". + Abrir directorio del juego + Nombre de usuario inadecuado + El nombre de usuario debe de ser entre 3 a 16 caracteres, y solo contener letras latinas, números de 0 a 9 y guiones bajos. + Configuraciones rápidas diff --git a/app_pojavlauncher/src/main/res/values-fil/strings.xml b/app_pojavlauncher/src/main/res/values-fil/strings.xml index 08addc381c..3dafd18c24 100644 --- a/app_pojavlauncher/src/main/res/values-fil/strings.xml +++ b/app_pojavlauncher/src/main/res/values-fil/strings.xml @@ -35,6 +35,7 @@ Mga pilian Pasadyang mga kontrol Gumamit ng alternatibong surface rendering + Maaaring makatulong sa performance sa GPU bound scenario. Huwag pansinin ang notch Resolution Scaler Pagkontrol sa pag-scale ng mga pindutan diff --git a/app_pojavlauncher/src/main/res/values-fr/strings.xml b/app_pojavlauncher/src/main/res/values-fr/strings.xml index e8b355a65f..4f7277149a 100644 --- a/app_pojavlauncher/src/main/res/values-fr/strings.xml +++ b/app_pojavlauncher/src/main/res/values-fr/strings.xml @@ -9,6 +9,7 @@ Nom d’utilisateur Se connecter + "Appuyez sur l'icône d'engrenage \"⚙\" pour ouvrir le menu contextuel\nAppuyez sur un bouton pour le personnaliser : modifier, redimensionner, supprimer ou changer son raccourci clavier." Ce compte sera retiré ! @@ -51,6 +52,7 @@ Moteur de rendu Holy GL4ES - (toutes les versions, rapide) Zink (Vulkan) - (toutes les versions, mid) + LTW (OpenGL ES 3) - 1.17+ uniquement Version officielle Snapshot Alpha @@ -75,6 +77,7 @@ Par défaut L\'Application/Jeu a quitté avec le code %d, vérifiez le fichier latestlog.txt pour plus de détails. + L\'application/Le jeu s\'est fermé(e) avec le code %d, vérifiez le fichier latestlog.txt pour plus de détails. Voulez-vous vraiment forcer la fermeture ? Le moteur de rendu Zink (Vulkan) n\'est pas pris en charge sur votre appareil ! @@ -145,6 +148,7 @@ Verrouillage vers l\'avant Suivi absolu du doigt La quantité actuelle de RAM libre (%d) est inférieure à la RAM allouée (%d), ce qui peut entraîner des plantages. Changez l\'allocation si le jeu plante. + La quantité actuelle d\'espace RAM allouable libre (%d) est inférieure à la RAM allouée (%d), ce qui entraînera des crashs. Modifiez l\'allocation de la RAM si le jeu crash. Allocation de mémoire Contrôle la quantité de mémoire donnée à Minecraft. Java Runtime corrompu @@ -157,6 +161,7 @@ Définir par défaut Par défaut Vous devez avoir au moins un Runtime Java installé. + Aucune version compatible de Java n\'a été trouvée. Cette version nécessite Java %d ou plus récente. Java 8 est introuvable. Pour utiliser cette option, vous devez installer Java 8. Supprimer le runtime Répertoire du jeu @@ -238,6 +243,7 @@ Activer le dumping du shader Enregistre les shaders convertis dans le fichier journal. %d%% + %d ms Partir? Êtes-vous sûr·e de vouloir quitter? Quitter l\'éditeur @@ -326,11 +332,43 @@ L\'installation de JRE 17 a échoué Lecture des métadonnées du jeu … Téléchargement des métadonnées du jeu (%s) + Téléchargement du jeu en cours… (%d/%d, %.2f MB/s) + Téléchargement du jeu en cours… (%.2f/%.2f MB, %.2f MB/s) + Sélectionnez une version de Forge + Verrouillage vertical + Verrouillage horizontal + Réinitialiser + Sélection annulée + Défilement automatique\nDésactivé + Défilement automatique\nActivé + Sortie\nDésactivée + Sortie\nDésactivée + Sortie des logs : + Impossible de lire le fichier .jar + La fonction \"Exécuter le fichier .jar\" n\'est pas compatible avec Java%d A B X Y Start Sélectionner + Gâchette gauche + Gâchette droite + Stick (haut) + Stick (bas) + Stick (gauche) + Stick (droite) + Stick gauche (appuyé) + Stick droit (appuyé) + D-Pad (haut) + D-Pad (bas) + D-Pad (gauche) + D-Pad (droite) + Maintenir + pour quitter + Mode actuel Visibilité + En jeu + Dans les menus + Développer pour changer les codes de touches diff --git a/app_pojavlauncher/src/main/res/values-in/strings.xml b/app_pojavlauncher/src/main/res/values-in/strings.xml index fe8e8b9a12..664d1ae3ac 100644 --- a/app_pojavlauncher/src/main/res/values-in/strings.xml +++ b/app_pojavlauncher/src/main/res/values-in/strings.xml @@ -9,6 +9,7 @@ Username Login + "Sentuh roda gigi diatas tengah untuk membuka menu konteks ⚙️\nSentuh sebuah tombol untuk menyesuaikan: edit, ubah ukuran, atau ubah tombol pintasannya." Akun ini akan dihapus! @@ -51,6 +52,7 @@ Renderer Holy GL4ES - (semua versi, cepat) Zink (Vulkan) - (semua versi, menengah) + LTW (OpenGL ES 3) - hanya untuk 1.17+ Rilis Snapshot Alpha-lama @@ -75,6 +77,7 @@ Default Aplikasi/permainan keluar dengan kode %d, cek latestlog.txt untuk detail lebih lanjut. + Aplikasi/Game keluar dengan sinyal fatal %d, cek latestlog.txt untuk detail lebih lanjut. Apa anda yakin mau tutup secara paksa? Renderer Zink (Vulkan) tidak didukung di perangkat ini! @@ -145,6 +148,7 @@ Kunci ke depan Pelacakan jari absolut Jumlah RAM kosong saat ini (%d) lebih rendah dari RAM yang dialokasikan (%d), yang dapat menyebabkan crash. Ubah alokasi jika game crash. + Jumlah RAM kosong saat ini (%d) lebih rendah dari RAM yang dialokasikan (%d), yang dapat menyebabkan crash. Ubah alokasi jika game crash. Alokasi Memori Kontrol seberapa banyak memori yang diberikan untuk Minecraft. Java Runtime Rusak @@ -157,6 +161,7 @@ Set default Default Kamu harus punya setidaknya satu Runtime Java yang terpasang. + Tidak dapat mencari Java Runtime yang kompatibel. Versi ini membutuhkan Java %d atau lebih baru. Tidak dapat menemukan Java 8. Untuk menggunakan opsi ini, kamu perlu menginstal Java 8. Hapus runtime Direktori game @@ -174,10 +179,10 @@ Barang Eksperimental Gunakan hal-hal di sana dengan pertimbangan, tidak ada dukungan Aktifkan mode kinerja berkelanjutan - Limit thermal throttling dengan me-limit performa. + Batasi thermal throttling dengan cara membatasi performa maksimal. Paksa aktifkan VSync - Limit thermal throttling dengan me-limit performa. - Paksa bahasa saat ini ke bahasa Inggris + Batasi thermal throttling dengan cara membatasi performa maksimal. + Paksa bahasa ke bahasa Inggris Memperbolehkan anda untuk melihat string asli, seperti kehendak pengembang. Membutuhkan muat ulang. Ubah kontrol kustom Atur skema kontrol untuk menyesuaikan kebutuhan Anda. @@ -224,10 +229,10 @@ Sepertinya akun ini tidak mempunyai profil Minecraft. Jika kamu memiliki Xbox Game Pass, tolong login ke https://minecraft.net/ dan mengaturnya. Xbox Live tidak tersedia dinegaramu Hidupkan kontrol giroskop - Pppp. + Mengaktifkan ini dapat memperbolehkan anda untuk berputar dengan cara memutar ponsel anda. Giroskop mengontrol sensitivitas Atur sensitivitas kontrol giroskop. - ! + Nyalakan kontrol giro sebelum menggunakan ini! Tingkat pengambilan sampel giroskop Jika anda memiliki masalah perfoma dengan kontrol giroskop, tingkatkan ini. Terlalu banyak permintaan, coba lagi nanti. @@ -238,6 +243,7 @@ Aktifkan shader dumping Simpan catatan shader ke sebuah berkas. %d%% + %d ms Meninggalkan? Anda yakin ingin keluar? Tinggalkan editor @@ -320,17 +326,59 @@ Pojav launcher memperlukan izin untuk post notifikasi untuk mencegah download game/modpack berhenti ketika keluar dari aplikasi. Tanpa izin ini, android mungkin membatalkan unduhan ketita menempatkan PojavLaunher dalam mode latar belakang. kamu selalu dapat berubah pikiran nanti dengan masuk ke Pengaturan Izinkan notifikasi - Pencet untuk request kembali izin notifikasi, dibutuhkan untuk pengunduhan latar belakang permainan/modpack untuk berjalan dengan benar. + Tekan untuk meminta kembali izin notifikasi, dibutuhkan untuk pengunduhan latar belakang permainan/modpack untuk berjalan dengan benar. Membolehkan V-sync dengan Zink Perbolehkan peluncur untuk menggunakan API sistem internal untuk menyalakan V-Sync untuk Zink. Matikan ini jika peluncur anda tiba-tiba keluar sendiri setelah pembaruan sistem. Gagal memasang JRE 17 Membaca metadata game… Mendownload metadata game (%s) + Mendownload game... (%d/%d, %.2f MB/s) + Mendownload game... (%.2f/%.2f MB, %.2f MB/s) + Pilih region gambar + V. kunci + H. kunci + Atur Ulang + seleksi dibatalkan + Scroll otomatis\nMATI + Scroll otomatis\nHIDUP + Keluaran\nMATI + Keluaran\nHIDUP + Keluaran log: + Gagal membaca dokumen .jar + Fitur eksekusi .jar tidak kompatibel dengan Java %d A B X Y Mulai Pilih + Pemicu Kiri + Pemicu Kanan + Bahu Kiri + Bahu Kanan + Stik Atas + Stik Bawah + Stik Kiri + Stik Kanan + Stik Jempol kiri (klik) + Stik Jempol kanan (klik) + D-Pad Atas + D-Pad Bawah + D-Pad Kiri + D-Pad Kanan + Tahan + untuk keluar + Mode saat ini Visibilitas + Dalam permainan + Dalam menu + Besarkan untuk mengganti kode kunci + Ganti pengikatan kunci kontroller + Memperbolehkan anda untuk memodifikasikan kunci yang terikat ke setiap tombol kontroller + Discord + GPU anda tidak mampu untuk merender diatas 7 jarak render tanpa menginstall Sodium atau modifikasi serupa. Jarak render akan di kurangi secara otomatis setelah anda mengklik \"OK\". + Buka direktori permainan + Username tidak cocok + Panjang username harus diantara 3–16 karakter, dan harus hanya berisi huruf latin, nomor 0–9 dan mengaris bawahi. + Pengaturan cepat diff --git a/app_pojavlauncher/src/main/res/values-it/strings.xml b/app_pojavlauncher/src/main/res/values-it/strings.xml index c328b62089..3d414054d0 100644 --- a/app_pojavlauncher/src/main/res/values-it/strings.xml +++ b/app_pojavlauncher/src/main/res/values-it/strings.xml @@ -9,6 +9,7 @@ Nome utente Accedi + "Toccare la rotella dentata in alto al centro per aprire il menu contestuale ⚙ Toccare un pulsante per personalizzarlo: modificarlo, ridimensionarlo, rimuoverlo o cambiarne i tasti." L\'account sarà cancellato! @@ -51,6 +52,7 @@ Renderer Holy GL4ES - (Tutte le versioni, veloce) Zink (Vulkan) - (tutte le persone, med) + LTW (OpenGL ES 3) - solo 1.17+ Finale Snapshot Vecchie-alpha @@ -75,6 +77,7 @@ Predefinito L\'applicazione/gioco si è chiuso con il codice %d, controlla il lastlog.txt per più dettagli. + Applicazione/gioco interrotto dal segnale fatale %d, controllare latestlog.txt per maggiori dettagli. Sei sicuro di voler eseguire una chiusura forzata? Il renderer Zink (Vulkan) non è supportato su questo dispositivo! @@ -145,6 +148,7 @@ Forward lock Tracciamento assoluto delle dita L\'attuale quantità di RAM libera (%d) è minore di quella allocata (%d), la quale potrebbe portare a crash inaspettati. Modifica la quantità di RAM allocata in caso di crash. + L\'attuale quantità di spazio libero indirizzabile nella RAM (%d) è inferiore alla RAM allocata (%d), il che provoca un crash. Modificare l\'allocazione se il gioco si blocca. Memoria allocata Controlla quanta memoria dedicare a Minecraft. Runtime Java corrotta @@ -157,6 +161,7 @@ Imposta predefinito Predefinito Devi avere almeno un Runtime Java installato. + Impossibile trovare un Runtime Java compatibile. Questa versione richiede Java %d o più recente. Impossibile trovare Java 8. Per usare questa opzione, è necessario installare Java 8. Cancella runtime Cartella gioco @@ -239,6 +244,7 @@ Accedi almeno una volta su https://minecraft.net/ e riprova. Abilità shader dumping Registra gli shader convertiti nel file di log. %d%% + %d ms Uscire? Sei sicuro di voler uscire? Esci dall\'editor @@ -327,5 +333,17 @@ se vuoi scaricare dalla sorgente ufficiale premi \"Passa al sito ufficiale"\ e r Installazione fallita di JRE 17 Lettura metadati del gioco… Download dei metadati di gioco (%s) + Download del gioco... (%d/%d, %.2f MB/s) + Download del gioco... (%.2f/%.2f MB, %.2f MB/s) + Selezionare la regione dell\'immagine + Selezione annullata + Impossibile leggere il file .jar + La funzione Esegui .jar non è compatibile con Java %d Seleziona + Consente di modificare i tasti della tastiera legati a ciascun pulsante del controller + La GPU non è in grado di eseguire il rendering a una distanza superiore a 7 senza Sodium o altre modifiche simili. La distanza di rendering verrà automaticamente ridotta quando si fa clic su \"OK\". + Aprire la directory del gioco + Nome utente non adatto + Il nome utente deve avere una lunghezza compresa tra 3 e 16 caratteri e deve contenere solo lettere latine, numeri 0-9 e trattini bassi. + Impostazioni rapide diff --git a/app_pojavlauncher/src/main/res/values-ko/strings.xml b/app_pojavlauncher/src/main/res/values-ko/strings.xml index e1074116fe..d434bd2d49 100644 --- a/app_pojavlauncher/src/main/res/values-ko/strings.xml +++ b/app_pojavlauncher/src/main/res/values-ko/strings.xml @@ -9,6 +9,7 @@ 사용자명 로그인 + "상단 중앙 톱니바퀴 아이콘을 탭하여 상황에 맞는 메뉴를 엽니다. ⚙\n버튼을 탭하여 키바인드를 편집, 크기 조정, 삭제, 사용자 지정합니다" 이 계정이 제거될 거예요! diff --git a/app_pojavlauncher/src/main/res/values-pl/strings.xml b/app_pojavlauncher/src/main/res/values-pl/strings.xml index b8d2601e53..f1aeb74003 100644 --- a/app_pojavlauncher/src/main/res/values-pl/strings.xml +++ b/app_pojavlauncher/src/main/res/values-pl/strings.xml @@ -9,6 +9,7 @@ Nazwa użytkownika Zaloguj się + "Dotknij ikony zębatki, aby otworzyć menu kontekstowe ⚙\nNaciśnij przycisk, aby dostosować: edytuj, zmień rozmiar, usuń lub zmień przypisanie klawiszy." To konto zostanie usunięte! @@ -51,6 +52,7 @@ Silnik renderujący Holy GL4ES - (wszystkie wersje, szybki) Zink (Vulkan) - (wszystkie wersje, średni) + LTW (OpenGL ES 3) - tylko 1.17+ Oficjalne wydanie Wersja deweloperska Dawna Alpha @@ -75,6 +77,7 @@ Domyślny Aplikacja/gra zakończyła się błędem o kodzie %d, sprawdź latestlog.txt, aby uzyskać więcej informacji. + Aplikacja/gra zakończyła się błędem o kodzie %d, sprawdź plik latestlog.txt, aby uzyskać więcej informacji. Czy na pewno chcesz wymusić zamknięcie? Renderer Zink (Vulkan) nie jest wspierany na tym urządzeniu! @@ -145,6 +148,7 @@ Zablokowanie w przód Bezwzględne śledzenie palców Bieżąca ilość wolnej pamięci RAM (%d) jest mniejsza od przydzielonej pamięci RAM (%d), co może prowadzić do awarii. Zmień ilość, jeśli gra ulegnie awarii. + Bieżąca ilość wolnej pamięci RAM (%d) jest niższa od przydzielonej pamięci, (%d), co może prowadzić do awarii. Zmień przydzielenie, jeśli gra ulegnie awarii. Przydział pamięci Dostosuj ilość pamięci przydzieloną do Minecrafta. Uszkodzone środowisko wykonawcze Java @@ -157,6 +161,7 @@ Ustaw jako domyślny Domyślny Należy mieć zainstalowane co najmniej jedno środowisko wykonawcze Java. + Nie udało się znaleźć kompatybilnych środowisk uruchomieniowych Java. Ta wersja wymaga Java %d lub nowszej. Nie można znaleźć Java 8. Aby korzystać z tej opcji, należy zainstalować Java 8. Usuń środowisko wykonawcze Katalog gry @@ -238,6 +243,7 @@ Włącz dumping shaderów Rejestrowanie przekonwertowanych shaderów w pliku dziennika. %d%% + %d ms Wychodzisz? Czy na pewno chcesz wyjść? Opuść edytor @@ -326,11 +332,53 @@ Nie udało się zainstalować JRE 17 Czytanie metadanych gry… Pobieranie metadanych gry (%s) + Pobieranie gry... (%d/%d, %.2f MB/s) + Pobieranie gry... (%.2f/%.2f MB, %.2f MB/s) + Wybierz region obrazu + Blokada wertykalna + Blokada horyzontalna + Reset + Zaznaczenie anulowane + Auto przewijanie\nOFF + Auto przewijanie\nON + Wyjście\nOFF + Wyjście\nON + Wyjście logów: + Nie udało się odczytać pliku .jar + Funkcja wykonywania .jar jest niekompatybilna z Java %d A B X Y Start Wybierz + Lewy spust + Prawy spust + Lewy ramię + Prawe ramię + Analog w górę + Analog w dół + Analog w lewo + Analog w prawo + Lewy analog (kliknij) + Prawy analog (kliknij) + Krzyżak w górę + Krzyżak w dół + Krzyżak w lewo + Krzyżak w prawo + Przytrzymaj + Aby opuścić + Obecny tryb Widzialność + W grze + W menu + Rozwiń, aby zmienić przypisania przycisków + Zmień przypisania przycisków kontrolera + Pozwala na modyfikację przycisków klawiatury przypisanych do każdego przycisku kontrolera + Discord + Twoje GPU nie jest kompatybilne z zasięgiem renderowania powyżej 7 bez Sodium lub innych podobnych modów. Zasięg renderowanie zostanie automatycznie zmniejszony, jeśli klikniesz \"OK\". + Otwórz lokalizację plików gry + Nieodpowiednia nazwa użytkownika + Nazwa użytkownika musi posiadać od 3 do 16 znaków, i musi zawierać tylko latyńskie litery, numery od 0 do 9 oraz podkreślenia. + Szybkie ustawienia diff --git a/app_pojavlauncher/src/main/res/values-pt-rBR/strings.xml b/app_pojavlauncher/src/main/res/values-pt-rBR/strings.xml index a810883dd5..577c584013 100644 --- a/app_pojavlauncher/src/main/res/values-pt-rBR/strings.xml +++ b/app_pojavlauncher/src/main/res/values-pt-rBR/strings.xml @@ -9,6 +9,7 @@ Nome de Usuário Iniciar sessão + "Toque na engrenagem no topo da tela para abrir as configurações ⚙️\nToque em algum botão para customizar: editar, redimensionar, deletar, ou alterar o mapeamento." Esta conta será removida! @@ -51,6 +52,7 @@ Renderizador Holy GL4ES - (todas as versões, rápido) Zink (Vulkan) - (todas as versões, mediano) + LTW (OpenGL ES 3) - apenas 1.17+ Versões finais Snapshot Alpha antiga @@ -75,6 +77,7 @@ Padrão Aplicativo/jogo fechou com o código %d, verifique latestlog.txt para mais detalhes. + Aplicativo/jogo fechou com o código %d, verifique latestlog.txt para mais detalhes. Tem certeza que deseja forçar o encerramento? O renderizador Zink (Vulkan) não é compatível com este dispositivo! @@ -145,6 +148,7 @@ Trava para correr Movimento absoluto A quantidade atual de RAM livre (%d) é menor que a RAM alocada (%d), no qual pode causar falhas. Altere a quantidade se o jogo apresentar alguma falha. + A quantidade atual de RAM livre (%d) é menor que a RAM alocada (%d), no qual pode causar falhas. Altere a quantidade se o jogo apresentar alguma falha. Alocação de memória Controla o quanto de RAM será disponibilizado para o Minecraft. Java Runtime corrompido @@ -157,6 +161,7 @@ Definir como padrão Padrão Você precisa ter pelo menos um Java Runtime instalado. + Nenhum Java Runtime compatível encontrado. Essa versão requer o Java %d ou mais recente. Não foi possível encontrar o Java 8. Para usar esta opção, você precisa instalar o Java 8. Excluir runtime Diretório do jogo @@ -238,6 +243,7 @@ Habilitar despejo de shader Registrar shaders convertidos no arquivo de registro. %d%% + %d ms Saindo? Tem certeza que deseja sair? Sair do editor @@ -326,11 +332,48 @@ Falha ao instalar o JRE 17 Lendo metadados do jogo… Baixando metadados do jogo (%s) + Baixando o jogo… (%d/%d, %.2f MB/s) + Baixando o jogo… (%.2f/%.2f MB, %.2f MB/s) + Selecionar região da imagem + Bloqueio V. + Bloqueio H. + Redefinir + Seleção cancelada + Rolagem automática\nDESLIGADA + Rolagem automática\nLIGADA + Saída\nDESLIGADA + SAÍDA\nLIGADA + Registro de saída: + Falha na leitura do arquivo .jar + O recurso Executar .jar não é compatível com Java %d A B X Y Começar Selecionar + Botão esquerdo + Botão direito + Botão superior esquerdo + Botão superior direito + Analógico para cima + Analógico para baixo + Analógico para a esquerda + Analógico para a direita + Clique do analógico esquerdo + Analógico direito (clique) + Segurar + para sair + Modo atual Visibilidade + No jogo + Nos menus + Alterar mapeamento dos botões + Permite que você modifique as teclas do teclado vinculadas à cada botão do controle + Discord + A sua GPU não possui capacidade para renderizar a distância acima de 7 sem o Sodium ou outros mods semelhantes. A renderização de distância será reduzida automaticamente ao clicar em \"OK\". + Abrir diretório do jogo + Nome de usuário inadequado + O nome de usuário deve ter entre 3 a 16 caracteres, deve conter somente letras latinas, número de 0 a 9 e sublinhados. + Configurações rápidas diff --git a/app_pojavlauncher/src/main/res/values-ru/strings.xml b/app_pojavlauncher/src/main/res/values-ru/strings.xml index 56d2ac8ce1..512bf3a857 100644 --- a/app_pojavlauncher/src/main/res/values-ru/strings.xml +++ b/app_pojavlauncher/src/main/res/values-ru/strings.xml @@ -9,6 +9,7 @@ Имя пользователя Войти + "Нажмите на центральную шестерёнку ⚙, чтобы открыть меню действий.\n Выберите кнопку, чтобы удалить её или скопировать;\nизменить её свойства, размер или привязанные клавиши." Эта учётная запись будет удалена! @@ -51,6 +52,7 @@ Визуализатор Holy GL4ES (все версии, быстрый) Zink (Vulkan; все версии, средний) + LTW (OpenGL ES 3; 1.17 и выше) Релизы Снапшоты Старые альфа @@ -75,6 +77,7 @@ По умолчанию Произошёл собой приложения/игры с кодом %d. Проверьте latestlog.txt, чтобы получить больше информации. + Произошло аварийное завершение игры с сигналом %d. Проверьте latestlog.txt, чтобы получить больше информации. Вы уверены, что хотите принудительно завершить игру? Визуализатор Zink (Vulkan) не поддерживается на вашем устройстве. @@ -145,6 +148,7 @@ Фиксатор движения Динамический центр Текущий объем свободной оперативной памяти (%d) меньше, чем выделенная (%d), что может привести к сбоям. Измените количество выделенной памяти при сбое игры. + Текущий объём линейно адресуемой оперативной памяти (%d) меньше, чем выделенная (%d), что может привести к сбою. В случае сбоя игры измените количество выделенной памяти. Выделение памяти Управление объёмом выделяемой игре памяти. Среда выполнения Java повреждена @@ -157,6 +161,7 @@ Выбрать По умолчанию Должна быть установлена хотя бы одна среда выполнения Java. + Не удаётся найти совместимую среду выполнения Java. Эта версия требует Java %d или новее. Не удалось найти Java 8. Чтобы использовать эту опцию, необходимо установить Java 8. Удалить Папка игры @@ -238,6 +243,7 @@ Сохранять дамп шейдеров Записывать в файл журнала данные о конвертации шейдеров. %d %% + %d мс Выйти? Вы действительно хотите выйти? Покинуть редактор @@ -326,11 +332,53 @@ Не удалось установить JRE 17 Чтение метаданных игры… Загрузка метаданных игры (%s) + Загрузка файлов игры… (%d/%d, %.2f МБ/с) + Загрузка файлов игры… (%.2f/%.2f МБ, %.2f МБ/с) + Выбрать часть изображения + + + Сброс + Выбор отменён + Автопрокрутка\nВЫКЛ + Автопрокрутка\nВКЛ + Вывод\nВЫКЛ + Вывод\nВКЛ + Журнал: + Ошибка чтения .jar файла + Функция запуска .jar файлов несовместима с Java %d A B X Y Старт Выбрать + Левый курок + Правый курок + Левая плечевая кнопка + Правая плечевая кнопка + Джойстик вверх + Джойстик вниз + Джойстик влево + Джойстик вправо + Левый джойстик (нажатие) + Правый джойстик (нажатие) + Крестовина вверх + Крестовина вниз + Крестовина влево + Крестовина вправо + Удерживайте + , чтобы выйти + Текущий режим Отображение + В игре + В меню + Нажмите для изменения кодов клавиш + Изменить назначения клавиш контроллера + Позволяет настраивать привязку клавиш клавиатуры к кнопкам контроллера + Discord + Ваше видеоядро не поддерживает прорисовку более 7 чанков без использования Sodium или его аналогов. Нажмите «ОК», чтобы автоматически снизить прорисовку. + Открыть папку игры + Неподходящее имя пользователя + Имя пользователя должно быть от 3 до 16 символов в длину и содержать только латинские символы, цифры 0–9 или нижние подчёркивания. + Быстрые настройки diff --git a/app_pojavlauncher/src/main/res/values-vi/strings.xml b/app_pojavlauncher/src/main/res/values-vi/strings.xml index f78c1f8e61..c4a23d6ced 100644 --- a/app_pojavlauncher/src/main/res/values-vi/strings.xml +++ b/app_pojavlauncher/src/main/res/values-vi/strings.xml @@ -1,7 +1,7 @@ - PojavLauncher + PojavLauncher (Minecraft: Java Edition cho Android) PojavLauncher @@ -9,6 +9,7 @@ Tên người dùng Đăng nhập + "Chạm phím bánh răng ở giữa cạnh trên màn hình để mở menu ⚙\nChạm vào các phím để tùy chỉnh chúng: chỉnh sửa, thay đổi kích thước, xoá, hoặc thay đổi liên kết phím." Tài khoản này sẽ bị xoá! @@ -41,6 +42,7 @@ Độ phân giải Cho phép bạn giảm độ phân giải của trò chơi. 100% là độ phân giải tối đa. Kích hoạt độ trễ cao + Thay đổi khoảng thời gian chạm giữ để phá khối và ném đồ vật. Độ rộng nút điều khiển Tăng độ rộng nếu nút quá nhỏ. Độ lớn của chuột @@ -50,10 +52,13 @@ Trình kết xuất Holy GL4ES - (tất cả phiên bản, nhanh) Zink (Vulkan) - (tất cả phiên bản, Hiệu suất cho: trung bình) + LTW (OpenGL ES 3) - 1.17 trở lên Bản phát hành Snapshot Bản Alpha cũ Bản Beta cũ + Thực thi tệp .jar trong hộp cát + Điều khiển tính khả dụng của trình quản lý bảo mật hộp cát khi thực thi tệp .jar. Nhân bản Chỉnh sửa @@ -72,6 +77,7 @@ Mặc định Ứng dụng/Trò chơi đã thoát với mã %d, kiểm tra nhật kí trình khởi chạy (latestlog.txt) để biết thêm chi tiết. + Ứng dụng/Trò chơi đã thoát với mã %d, kiểm tra nhật kí trình khởi chạy (latestlog.txt) để biết thêm chi tiết. Bạn có chắc muốn bắt buộc thoát chương trình? Trình kết xuất Zink (Vulkan) không được hỗ trợ trên thiết bị này! @@ -127,17 +133,22 @@ Chơi Bộ nhớ được đặt thành %d MB Kiểm tra các thư viện sau khi tải + Tùy chọn này buộc trình khởi động kiểm tra hàm băm thư viện nếu có sẵn, ngăn chặn việc tải xuống lỗi. Thư viện %s bị hỏng và sẽ được tải lại Thư viện %s không thể kiểm tra, cho rằng nó tốt Library %s tốt và có thể sử dụng được Tắt cử chỉ Tắt cử chỉ, ví dụ như giữ để phá khối, và chạm để đặt khối. Tắt nhấn đúp để đổi tay + Tắt việc nhấn đúp vào vật phẩm trên thanh công cụ để đổi nó vào tay phụ. Tốc độ chuột + Thay đổi tốc độ của chuột ảo. Di chuyển chuột Có thể vuốt Khoá di chuyển lên + Theo dõi chuyển động tuyệt đối của ngón tay Số lượng RAM trống hiện tại (%d) thấp hơn số lượng RAM được phân bổ (%d), có thể dẫn đến sự cố. Thay đổi số lượng phân bổ nếu trò chơi bị sập. + Bộ nhớ trống hiện có (%d) thấp hơn bộ nhớ được phân bổ (%d), điều này có thể gây ra sự cố. Thay đổi lượng bộ nhớ được phân bổ nếu trò chơi bị văng. Phân bổ bộ nhớ Điều khiển lượng bộ nhớ tạm được đưa vào Minecraft. Java đã gặp xung đột @@ -150,6 +161,7 @@ Đặt làm mặc định Mặc định Bạn phải có ít nhất một hệ thống thời gian chạy Java đã được cài đặt. + Không thể tìm thấy Java Runtime tương thích. Phiên bản này yêu cầu Java %d trở lên. Không thể tìm thấy Java 8. Để sử dụng tùy chọn này, bạn cần cài đặt Java 8. Xóa runtime Đường dẫn thư mục của trò chơi @@ -161,20 +173,26 @@ Tuỳ chỉnh bộ điều khiển Cử chỉ, nút bấm và kích cỡ Điều chỉnh Java + Các Java Runtime, chỉ số JVM, lượng RAM phân bổ và hộp cát Các cài đặt khác Kiểm tra danh sách phiên bản và thư viện Những cài đặt thử nghiệm Cân nhắc sử dụng các tuỳ chọn này, không hỗ trợ Bật chế độ duy trì hiệu suất + Hạn chế giảm hiệu suất vì quá nhiệt bằng cách giảm hiệu suất tối đa. Bắt buộc kích hoạt VSync + Hạn chế giảm hiệu suất vì quá nhiệt bằng cách giảm hiệu suất tối đa. Buộc ngôn ngữ Tiếng Anh Cho phép hiển thị các dòng chữ ban đầu, như theo ý của nhà phát triển. Yêu cầu khởi động lại. Tùy chỉnh điều khiển + + Điều khiển con quay hồi chuyển Chuột ảo Đảo ngược trục X Đảo ngược trục Y Đảo ngược trục hoành. Đảo ngược trục tung. + Bật làm mịn con quay hồi chuyển Reduce jitter in exchange of latency. Quay về màn hình trước đó Chưa đặt tên @@ -223,18 +241,23 @@ Tắt đi nếu bạn muốn sử dụng chữ cái thường trong mục điều khiển. Tạo cấu hình mới Kích hoạt đổ bóng + Ghi các trình đổ bóng đã chuyển đổi vào tệp nhật ký. %d%% + %d ms Rời đi? Bạn có chắc bạn muốn thoát ra không? Rời khỏi trình chỉnh sửa Lưu và thoát Đồng ý Không + Cấu hình điều khiển đã bị xóa. Cài đặt điều khiển Thiết đặt lại cấu hình điều khiển Cho phép bạn thay đổi các cấu hình tay cầm. Độ rộng vùng chết cần điều khiển Tăng nếu cần điểu khiển bị lệch. + Buộc trình kết xuất chạy trên lõi lớn + Buộc luồng kết xuất của Minecraft chạy trên lõi có tần số cao nhất. Chọn phiên bản Đang tải xuống %s Đang tìm số phiên bản của Forge @@ -279,11 +302,25 @@ Đã xảy ra lỗi Nhấn để xem chi tiết Chỉ hiện phiên bản ổn dịnh + Cảnh báo xác minh tập tin + + +Điều này không an toàn. Nếu bạn tiếp tục, thông tin cá nhân của bạn có thể gặp nguy hiểm!
+ +Nếu bạn vẫn muốn sử dụng nguồn bản sao này, nhấn vào "Tắt kiểm tra danh sách phiên bản game" để bắt đầu tải xuống lại.
+ +Nếu bạn muốn sử dụng nguồn tải xuống chính thức, nhấn vào "Chuyển sang nguồn chính thức" để bắt đầu tải xuống lại.
]]>
+ Tắt kiểm tra danh sách phiên bản + Chuyển sang nguồn chính thức Nguồn tải trò chơi + Chọn nguồn bản sao để tải xuống thay vì sử dụng máy chủ tải xuống chính thức + Kiểm tra danh sách phiên bản trò chơi + Khi bật, trình khởi chạy sẽ kiểm tra danh sách phiên bản trò chơi và thư viện. Trò chơi đã sẵn sàng để chạy Nhấn vào đây để bắt đầu! Những cử chỉ Phím + Những cài đặt thử nghiệm Điều chỉnh Java Danh mục Các cài đặt khác @@ -292,13 +329,59 @@ PojavLauncher yêu cầu quyền để gửi thông báo để ngăn chặn trò chơi/modpacks tải xuống mà không dừng lại khi bạn rời khỏi ứng dụng. Nếu không cấp quyền, Android có thể ngắt quá trình tải khi bạn để PojavLauncher ở chế độ nền. Bạn luôn có thể thay đổi ý định của mình bằng cách vào Cài đặt Cho phép Gửi thông báo + Nhấp để yêu cầu lại quyền thông báo, điều này là cần thiết để trò chơi/gói tích hợp tải xuống bình thường ở chế độ nền. Cho phép V-Sync với trình kết xuất Zink + Cho phép trình khởi chạy sử dụng API hệ thống nội bộ để kích hoạt đồng bộ dọc cho trình kết xuất Zink. Tắt cài đặt này nếu trình khởi chạy bất ngờ bị văng với Zink sau một bản cập nhật hệ thống. Cài Đặt thất bại JRE 17 + Đang đọc siêu dữ liệu trò chơi… Đang tải xuống siêu dữ liệu trò chơi (%s) + Đang tải xuống trò chơi… (%d/%d, %.2f MB) + Đang tải xuống trò chơi… (%.2f/%.2f MB, %.2f MB) + Chọn vùng hình ảnh + Khóa trục dọc + Khóa trục ngang + Đặt lại + Lựa chọn đã bị hủy + Tự động cuộn\nTắt + Tự động cuộn\nBật + In ra MH\nTắt + In ra MH\nBật + Đầu ra nhật ký: + Không thể đọc tệp .jar + Chức năng thực thi .jar không tương thích với Java %d A B X Y Bắt đầu Chọn + Nút nhấn trái + Nút nhấn phải + Nút vai trái + Nút vai phải + Cần điều khiển lên + Cần điều khiển xuống + Cần điều khiển trái + Cần điều khiển phải + Cần điều khiển trái (nhấn) + Cần điều khiển phải (nhấn) + Phím lên + Phím xuống + Phím trái + Phím phải + Giữ + để thoát ra + Chế độ hiện tại + Có thể nhìn thấy + Trong trò chơi + Trong menu + Mở rộng để thay đổi mã phím + Thay đổi liên kết nút tay cầm + Cho phép bạn sửa đổi các phím bàn phím được gán cho mỗi nút điều khiển + Discord + GPU của bạn không thể kết xuất với khoảng cách trên 7 chunks nếu không có Sodium hoặc các mod tương tự khác. Khoảng cách kết xuất sẽ được tự điều chỉnh lại khi nhấn OK. + Mở thư mục trò chơi + Tên người dùng không phù hợp + Tên người dùng phải có từ 3 đến 16 kí tự, và chỉ có chữ cái Latinh, chữ số và dấu gạch chân. + Cài đặt nhanh
diff --git a/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml b/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml index 45509a2762..9c8faeabbb 100644 --- a/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml +++ b/app_pojavlauncher/src/main/res/values-zh-rCN/strings.xml @@ -9,6 +9,7 @@ 用户名 登录 + "点按顶部中央齿轮以打开上下文菜单⚙\n点击按钮进行自定义:编辑、调整大小、删除或更改其按键绑定。" 此账户将被移除! @@ -51,6 +52,7 @@ 渲染器 Holy GL4ES -(全版本可用,速度较快) Zink(Vulkan)-(全版本可用,速度中等) + LTW (OpenGL ES 3) - 仅限 1.17+ 正式版 快照版 远古 alpha 版 @@ -75,6 +77,7 @@ 默认 应用程序/游戏以代码 %d退出,请查看 latestlog.txt 了解详情;如果你不知道发生了什么,请点击 “分享日志文件” 将日志文件发送给他人分析,而不是在此页面截屏。 + 应用程序/游戏以致命信号 %d 中止,请查看 latestlog.txt 以了解更多详情。 您确定要强制关闭? 此设备不支持 Zink(Vulkan)渲染器! @@ -145,6 +148,7 @@ 允许锁定前进 绝对手指跟踪 当前可用内存(%d)低于所分配的内存(%d),这可能会导致崩溃!如果游戏崩溃请更改内存分配设置。 + 当前可用可寻址内存空间量 (%d) 低于已分配内存量 (%d),这将导致游戏崩溃。如果游戏崩溃,请调整分配。 内存分配 控制给应用程序/游戏分配多少内存 Java 运行环境损坏 @@ -157,6 +161,7 @@ 设为默认 默认 您必须至少安装一个 Java 运行环境。 + 找不到任何兼容的 Java 运行时。此版本需要 Java %d 或更新版本。 无法找到 Java 8,如要使用此选项,您需要安装 Java 8。 删除运行环境 游戏目录 @@ -238,6 +243,7 @@ 启用着色器输出 记录切换的着色器到日志文件中。 %d%% + %d 毫秒 您确定要离开? 您确定要退出? 退出编辑器 @@ -326,11 +332,53 @@ JRE 17 安装失败! 正在读取游戏元数据… 正在下载游戏元数据(%s) + 正在下载游戏… (%d/%d, %.2f MB/秒) + 正在下载游戏… (%.2f/%.2f MB, %.2f MB/秒) + 选择图像区域 + 纵向锁定 + 横向锁定 + 重置 + 选择已取消 + 自动滚动\n关 + 自动滚动\n开 + 输出\n关 + 输出\n开 + 日志输出: + 无法读取 .jar 文件 + 执行 .jar 功能与 Java %d 不兼容 A B X Y 开始 选择 + 左扳机 + 右扳机 + 左肩键 + 右肩键 + 摇杆上 + 摇杆下 + 摇杆左 + 摇杆右 + 左摇杆(按下) + 右摇杆(按下) + 方向键上 + 方向键下 + 方向键左 + 方向键右 + 长按 + 以退出 + 当前模式 可见性 + 游戏内 + 菜单内 + 展开以更改键码 + 更改手柄按键绑定 + 允许你修改绑定到每个手柄按钮的键盘按键 + Discord + 如果没有 Sodium 或其他类似模组,你的 GPU 将无法渲染 7 以上的渲染距离。点击“确定”后,渲染距离将自动缩短。 + 打开游戏目录 + 用户名不合适 + 用户名长度必须在 3–16 个字符之间,并且只能包含拉丁字母、数字 0–9 和下划线。 + 快速设置 diff --git a/app_pojavlauncher/src/main/res/values-zh-rTW/strings.xml b/app_pojavlauncher/src/main/res/values-zh-rTW/strings.xml index 7657df190f..80eb421a3c 100644 --- a/app_pojavlauncher/src/main/res/values-zh-rTW/strings.xml +++ b/app_pojavlauncher/src/main/res/values-zh-rTW/strings.xml @@ -9,6 +9,7 @@ 使用者名稱 登入 + "請輕觸頂部中央的齒輪圖示 ⚙ 開啟選單。\n輕觸按鈕來進行自訂:編輯、調整大小、移除或變更其按鍵綁定。" 這個帳號將被移除! @@ -47,10 +48,11 @@ 滑鼠縮放 變更虛擬滑鼠的大小。 JVM 啟動參數 - 注意:若您不具備相關知識,修改這項設定可能會導致遊戲崩潰。 + 注意:若你不具備相關知識,修改這項設定可能會導致遊戲崩潰。 渲染器 Holy GL4ES -(全版本可用,速度快) Zink (Vulkan) -(全版本支援,速度中等) + LTW(OpenGL ES 3)- 僅限 1.17+ 正式版 快照版 舊版 Alpha @@ -74,8 +76,9 @@ 重試 預設 - 應用程式/遊戲以代碼 %d 退出,請查看 latestlog.txt 以取得更多詳細資訊。 - 確定要強制關閉嗎? + 應用程式/遊戲以代碼 %d 結束,請查看 latestlog.txt 以取得更多詳細資訊。 + 應用程式/遊戲發生嚴重錯誤(%d)並已中止,請檢查 latestlog.txt 以取得更多資訊。 + 您確定要強制關閉嗎? 這部裝置不支援 Zink 渲染器! 聊天欄 @@ -144,11 +147,12 @@ 可滑動 疾走鎖定 絕對手指追蹤 - 目前可用的剩餘記憶體 (%d) 比已配置的記憶體 (%d) 還低,這可能會導致程式崩潰。如果遊戲崩潰,請調整配置。 + 目前可用記憶體 (%d) 低於已配置記憶體 (%d),這可能會導致遊戲崩潰。如果遊戲崩潰,請變更記憶體配置設定。 + 目前可用的可定址記憶體空間 (%d) 低於已配置的記憶體 (%d) ,這將導致遊戲崩潰。如果遊戲崩潰,請變更記憶體配置設定。 記憶體配置 - 控制配置給 Minecraft 的記憶體用量。 + 控制配置給 Minecraft 的記憶體容量。 Java 執行環境毀損 - %s 與您的硬體架構不相容 + 不相容的架構:%s Java 執行環境 新增 執行庫管理器 @@ -156,7 +160,8 @@ 正在快取…… 設為預設 預設 - 您必須至少一個安裝 Java 執行庫。 + 你必須至少安裝一個 Java 執行環境。 + 找不到任何相容的 Java 執行環境。這個版本需要 Java %d 或以上版本。 找不到已安裝的 Java 8。請安裝 Java 8 以使用此功能。 刪除 Java 執行環境 遊戲目錄 @@ -178,9 +183,9 @@ 強制啟用垂直同步 透過限制峰值效能來限制過熱降頻。 強制使用英文 - 允許您按開發人員的原意看到原始字串,此操作需要重新啟動。 + 允許你查看開發人員預期的原始字串。需要重新啟動。 自訂控制鍵 - 調整控制方案以適應您的需求。 + 調整控制配置以符合你的需求。 陀螺儀控制 虛擬滑鼠 反轉 X 軸 @@ -218,26 +223,27 @@ 無已儲存帳號 Minecraft 下載失敗!可能導致失敗的原因有:不穩定的網路連線、位置不正確的檔案等 未知的 Xbox Live API 錯誤 %d - 您似乎沒有 Xbox Live 帳號。請先登入 https://minecraft.net/ 後再試一次。 - 您的帳號需要被家長驗證 - 因為您的 Xbox 帳號未成年,若要登入,請將此帳號加入 Microsoft 家庭 - 看起來這個帳號沒有 Minecraft 個人檔案。如果您有 Xbox Game Pass,請前往 https://minecraft.net/ 並設定它。 - Xbox Live 在您的國家/地區無法使用 + 你似乎沒有 Xbox Live 帳號。請先登入 https://minecraft.net/ 後再試一次。 + 需要成年人驗證你的帳號。 + 因為你的 Xbox 帳號未成年,若要登入,請將此帳號加入 Microsoft 家庭 + 看起來這個帳號沒有 Minecraft 個人檔案。如果你有 Xbox Game Pass,請前往 https://minecraft.net/ 並設定它。 + Xbox Live 在你的國家/地區無法使用 啟用陀螺儀控制 - 啟用此功能將允許您透過轉動手機來在遊戲中轉動視角。 + 啟用此功能將允許你透過轉動手機來在遊戲中轉動視角。 陀螺儀控制靈敏度 調整陀螺儀控制的靈敏度 需要先啟用陀螺儀控制才能使用 陀螺儀取樣率 - 如果您在陀螺儀控制上遇到效能問題,請增加此值。 - 您的操作過於頻繁,請稍後再試! + 如果你在陀螺儀控制上遇到效能問題,請增加此值。 + 你的操作過於頻繁,請稍後再試! PojavLauncher 需要連接外部儲存空間,請重新連接並重新啟動應用程式。 在按鈕標籤中僅使用大寫字母 - 如果您想在控制鍵中使用並顯示小寫字母,請關閉此設定。 + 如果你想在控制鍵中使用並顯示小寫字母,請關閉此設定。 新增設定檔 啟用著色器傾印 將轉換後的著色器記錄到記錄檔中。 %d%% + %d 毫秒 是否離開? 您確定要離開嗎? 離開編輯器 @@ -247,7 +253,7 @@ 控制器設定已清除。 控制器設定 重設控制器映射 - 允許您重新映射控制器按鍵。 + 允許你重新映射控制器按鍵。 搖桿死區比例 如果搖桿飄移,請增加此值。 強制渲染器在大核心上執行 @@ -298,9 +304,9 @@ 僅顯示穩定版本 檔案驗證警告 - 這並不安全。如果您繼續操作,您的個人資訊可能會處於風險之中。
- 如果您仍想使用鏡像站,請按一下「關閉清單檢查」,然後重新開始下載。
- 如果您想使用官方下載來源,請按一下「切換至官方網站」,然後重新開始下載。
]]>
+ 這並不安全。如果你繼續操作,你的個人資訊可能會處於風險之中。
+ 如果你仍想使用鏡像站,請按一下「關閉清單檢查」,然後重新開始下載。
+ 如果你想使用官方下載來源,請按一下「切換至官方網站」,然後重新開始下載。
]]> 關閉版本資訊清單檢查 切換到官方網站 遊戲下載來源 @@ -317,20 +323,62 @@ 其他設定 顯示設定 權限要求 - PojavLauncher 需要通知權限,以防止您離開應用程式時,遊戲/模組包的下載停止。如果沒有這個權限,當您將 PojavLauncher 置於背景模式時,Android 可能會停止您的下載內容。 - 您隨時可以進入設定變更您的決定。 + PojavLauncher 需要通知權限,以防止你離開應用程式時,遊戲/模組包的下載停止。如果沒有這個權限,當你將 PojavLauncher 置於背景模式時,Android 可能會停止你的下載內容。 + 你隨時可以進入設定變更你的決定。 允許通知 按一下重新請求通知權限,這是遊戲/模組包背景下載正常運作所必需的。 允許在使用 Zink 時啟用垂直同步 - 允許啟動器使用內部系統 API 來啟用 Zink 的垂直同步。如果您的啟動器在系統更新後突然在使用 Zink 時崩潰,請關閉此功能。 + 允許啟動器使用內部系統 API 來啟用 Zink 的垂直同步。如果你的啟動器在系統更新後突然在使用 Zink 時崩潰,請關閉此功能。 無法安裝 JRE 17 正在讀取遊戲中繼資料…… 正在下載遊戲中繼資料 (%s) + 正在下載遊戲……(%d/%d, %.2f MB/秒) + 正在下載遊戲……(%.2f/%.2f MB, %.2f MB/秒) + 選擇圖片區域 + 垂直鎖定 + 水平鎖定 + 重設 + 已取消選擇 + 自動捲動\n關閉 + 自動捲動\n開啟 + 輸出\n關閉 + 輸出\n開啟 + 記錄輸出: + 讀取 .jar 檔案失敗 + 執行 .jar 功能與 Java %d 不相容 A B X Y 開始 選擇 + 左扳機 + 右扳機 + 左肩鍵 + 右肩鍵 + 搖桿上 + 搖桿下 + 搖桿左 + 搖桿右 + 左搖桿(按下) + 右搖桿(按下) + 方向鍵上 + 方向鍵下 + 方向鍵左 + 方向鍵右 + 按住 + 以離開 + 目前模式 可見度 + 遊戲中 + 選單中 + 展開以變更按鍵碼 + 變更控制器按鍵綁定 + 允許你修改綁定至每個控制器按鈕的鍵盤按鍵 + Discord + 你的 GPU 無法在不使用 Sodium 或其他類似模組的情況下,繪製超過 7 的顯示距離。當你輕觸「確定」時,顯示距離將會自動降低。 + 開啟遊戲目錄 + 不適當的使用者名稱 + 使用者名稱長度必須介於 3 到 16 個字元之間,且僅能包含拉丁字母、數字 0 到 9 以及底線。 + 快速設定 diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index ccc63e1a87..a83ff8fec5 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -13,7 +13,7 @@ Login - "Touch the top center cogwheel to open the context menu ⚙\nTap a button to customize: edit, resize, remove, or change its keybind." + "Touch the top center cogwheel to open the context menu ⚙\nTap a button to customize: edit, resize, remove, or change its keybinds." This account will be removed! @@ -422,6 +422,6 @@ Open game directory https://discord.com/invite/aenk3EUvER Unsuitable username - The username must be between 3–16 characters long, and must only contain latin letters, arabic numerals and underscores. + The username must be between 3–16 characters long, and must only contain latin letters, numbers 0–9 and underscores. Quick settings diff --git a/jre_lwjgl3glfw/libs/lwjgl-lwjglx.jar b/jre_lwjgl3glfw/libs/lwjgl-lwjglx.jar index 45530a23f4..f2589d7369 100644 Binary files a/jre_lwjgl3glfw/libs/lwjgl-lwjglx.jar and b/jre_lwjgl3glfw/libs/lwjgl-lwjglx.jar differ