mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-18 17:15:40 -04:00
Add mod installer (not implemented)
This commit is contained in:
parent
bf49d40eb7
commit
958e22f0a3
@ -41,6 +41,11 @@
|
||||
android:name=".MCLauncherActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"/>
|
||||
|
||||
<activity
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:name=".InstallModActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"/>
|
||||
|
||||
<activity
|
||||
android:screenOrientation="sensorLandscape"
|
||||
android:name=".CustomControlsActivity"
|
||||
|
@ -28,12 +28,32 @@ public class BinaryExecutor
|
||||
|
||||
// return fd;
|
||||
}
|
||||
|
||||
|
||||
public static void setJavaEnvironment() {
|
||||
setEnvironment("JAVA_HOME", Tools.homeJreDir);
|
||||
setEnvironment("HOME", Tools.MAIN_PATH);
|
||||
setEnvironment("TMPDIR", getCacheDir().getAbsolutePath());
|
||||
// setEnvironment("LIBGL_MIPMAP", "3");
|
||||
setEnvironment("MESA_GLSL_CACHE_DIR", getCacheDir().getAbsolutePath());
|
||||
setEnvironment("LD_LIBRARY_PATH", ldLibraryPath);
|
||||
setEnvironment("PATH", Tools.homeJreDir + "/bin:" + Os.getenv("PATH"));
|
||||
}
|
||||
|
||||
private static void setEnvironment(String name, String value) throws ErrnoException, IOException {
|
||||
if (MainActivity.LAUNCH_TYPE == MainActivity.LTYPE_PROCESS) {
|
||||
mLaunchShell.writeToProcess("export " + name + "=" + value);
|
||||
} else {
|
||||
Os.setenv(name, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
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 setupBridgeEGL();
|
||||
|
||||
public static native void setupBridgeSurfaceAWT(Object surface);
|
||||
|
||||
// BEFORE Load and execute PIE binary using dlopen and dlsym("main")
|
||||
// AFTER: Execute a binary in forked process
|
||||
public static native int executeBinary(String[] args);
|
||||
|
@ -0,0 +1,98 @@
|
||||
package net.kdt.pojavlaunch;
|
||||
|
||||
import android.graphics.*;
|
||||
import android.os.*;
|
||||
import android.support.v7.app.*;
|
||||
import android.view.*;
|
||||
import com.oracle.dalvik.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class InstallModActivity extends AppCompatActivity
|
||||
{
|
||||
private TextureView mTextureView;
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.install_mod);
|
||||
|
||||
final File modFile = (File) getIntent().getExtras().getSerializable("modFile");
|
||||
|
||||
mTextureView = findViewById(R.id.installmod_surfaceview);
|
||||
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener(){
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture tex, int w, int h) {
|
||||
BinaryExecutor.setupBridgeSurfaceAWT(new Surface(tex));
|
||||
new Thread(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
launchJavaRuntime(modFile);
|
||||
finish();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture tex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture tex, int w, int h) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture tex) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void forceClose(View v) {
|
||||
MainActivity.dialogForceClose(this);
|
||||
}
|
||||
|
||||
private void launchJavaRuntime(File modFile) {
|
||||
try {
|
||||
List<String> javaArgList = new ArrayList<String>();
|
||||
|
||||
javaArgList.add(Tools.homeJreDir + "/bin/java");
|
||||
|
||||
// javaArgList.add("-Xms512m");
|
||||
javaArgList.add("-Xmx512m");
|
||||
|
||||
javaArgList.add("-Djava.home=" + Tools.homeJreDir);
|
||||
javaArgList.add("-Dos.name=Linux");
|
||||
javaArgList.add("-Djava.library.path=");
|
||||
javaArgList.add("-jar");
|
||||
javaArgList.add(modFile.getAbsolutePath());
|
||||
|
||||
String libName = System.getProperty("os.arch").contains("64") ? "lib64" : "lib";
|
||||
String ldLibraryPath = (
|
||||
// To make libjli.so ignore re-execute
|
||||
Tools.homeJreDir + "/lib/server:" +
|
||||
|
||||
"/system/" + libName + ":" +
|
||||
"/vendor/" + libName + ":" +
|
||||
"/vendor/" + libName + "/hw:" +
|
||||
|
||||
getApplicationInfo().nativeLibraryDir + ":" +
|
||||
|
||||
Tools.homeJreDir + "/lib/jli:" +
|
||||
Tools.homeJreDir + "/lib"
|
||||
);
|
||||
|
||||
BinaryExecutor.setJavaEnvironment();
|
||||
BinaryExecutor.redirectStdio();
|
||||
BinaryExecutor.setLdLibraryPath(ldLibraryPath);
|
||||
BinaryExecutor.initJavaRuntime();
|
||||
BinaryExecutor.chdir(Tools.MAIN_PATH);
|
||||
|
||||
VMLauncher.launchJVM(javaArgList.toArray(new String[0]));
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(this, th, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -773,21 +773,18 @@ public class MCLauncherActivity extends AppCompatActivity
|
||||
@Override
|
||||
public void onClick(DialogInterface p1, int p2)
|
||||
{
|
||||
switch(p2){
|
||||
case 0:{ // Mods manager
|
||||
modManager();
|
||||
} break;
|
||||
case 1:{ // OptiFine installer
|
||||
installOptiFine();
|
||||
} break;
|
||||
case 2:{ // Custom controls
|
||||
if (Tools.enableDevFeatures) {
|
||||
startActivity(new Intent(MCLauncherActivity.this, CustomControlsActivity.class));
|
||||
}
|
||||
} break;
|
||||
case 3:{ // Settings
|
||||
startActivity(new Intent(MCLauncherActivity.this, LauncherPreferenceActivity.class));
|
||||
} break;
|
||||
switch (p2) {
|
||||
case 1: // Mod installer
|
||||
installMod();
|
||||
break;
|
||||
case 2: // Custom controls
|
||||
if (Tools.enableDevFeatures) {
|
||||
startActivity(new Intent(MCLauncherActivity.this, CustomControlsActivity.class));
|
||||
}
|
||||
break;
|
||||
case 3: // Settings
|
||||
startActivity(new Intent(MCLauncherActivity.this, LauncherPreferenceActivity.class));
|
||||
break;
|
||||
case 4:{ // About
|
||||
final AlertDialog.Builder aboutB = new AlertDialog.Builder(MCLauncherActivity.this);
|
||||
aboutB.setTitle(R.string.mcl_option_about);
|
||||
@ -810,70 +807,11 @@ public class MCLauncherActivity extends AppCompatActivity
|
||||
builder.show();
|
||||
}
|
||||
|
||||
public void modManager()
|
||||
{
|
||||
/*
|
||||
File file1 = new File(Tools.mpModEnable);
|
||||
File file2 = new File(Tools.mpModDisable);
|
||||
File file3 = new File(Tools.mpModAddNewMo);
|
||||
file1.mkdirs();
|
||||
file2.mkdir();
|
||||
try
|
||||
{
|
||||
file3.createNewFile();
|
||||
}
|
||||
catch (IOException e){}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle("Mods manager (Forge)");
|
||||
builder.setPositiveButton(android.R.string.cancel, null);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
MFileListView flv = new MFileListView(this, dialog);
|
||||
flv.listFileAt(Tools.datapath + "/ModsManager");
|
||||
flv.setFileSelectedListener(new MFileSelectedListener(){
|
||||
|
||||
@Override
|
||||
public void onFileLongClick(File file, String path, String nane, String extension)
|
||||
{
|
||||
// TODO: Implement this method
|
||||
}
|
||||
@Override
|
||||
public void onFileSelected(File file, String path, String nane, String extension)
|
||||
{
|
||||
// TODO: Implement this method
|
||||
if(extension.equals(".jar")) {
|
||||
|
||||
} else {
|
||||
openSelectMod();
|
||||
}
|
||||
}
|
||||
});
|
||||
dialog.setView(flv);
|
||||
dialog.show();
|
||||
*/
|
||||
|
||||
Tools.dialogOnUiThread(this, "Mods manager", "This feature is not yet supported!");
|
||||
}
|
||||
|
||||
public void openSelectMod()
|
||||
{
|
||||
private void installMod() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.alerttitle_installmod);
|
||||
builder.setPositiveButton(android.R.string.cancel, null);
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
FileListView flv = new FileListView(this);
|
||||
|
||||
dialog.setView(flv);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void installOptiFine() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.alerttitle_installoptifine);
|
||||
builder.setPositiveButton(android.R.string.cancel, null);
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
FileListView flv = new FileListView(this);
|
||||
flv.setFileSelectedListener(new FileSelectedListener(){
|
||||
@ -881,7 +819,9 @@ public class MCLauncherActivity extends AppCompatActivity
|
||||
@Override
|
||||
public void onFileSelected(File file, String path, String name) {
|
||||
if (name.endsWith(".jar")) {
|
||||
doInstallOptiFine(file);
|
||||
Intent intent = new Intent(MCLauncherActivity.this, InstallModActivity.class);
|
||||
intent.putExtra("modFile", file);
|
||||
startActivity(intent);
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
@ -890,143 +830,6 @@ public class MCLauncherActivity extends AppCompatActivity
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void doInstallOptiFine(File optifineFile) {
|
||||
new OptiFineInstaller().execute(optifineFile);
|
||||
}
|
||||
|
||||
private class OptiFineInstaller extends AsyncTask<File, String, Throwable>
|
||||
{
|
||||
private ProgressDialog dialog;
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
dialog = new ProgressDialog(MCLauncherActivity.this);
|
||||
dialog.setTitle("Installing OptiFine");
|
||||
dialog.setMessage("Preparing");
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
dialog.setMax(5);
|
||||
dialog.setCancelable(false);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Throwable doInBackground(File[] file) {
|
||||
final StringBuilder currentLog = new StringBuilder();
|
||||
LoggerJava.LoggerOutputStream logOut = new LoggerJava.LoggerOutputStream(System.out, new LoggerJava.OnStringPrintListener(){
|
||||
@Override
|
||||
public void onCharPrint(char c)
|
||||
{
|
||||
currentLog.append(c);
|
||||
}
|
||||
});
|
||||
LoggerJava.LoggerOutputStream logErr = new LoggerJava.LoggerOutputStream(System.err, new LoggerJava.OnStringPrintListener(){
|
||||
@Override
|
||||
public void onCharPrint(char c)
|
||||
{
|
||||
currentLog.append(c);
|
||||
}
|
||||
});
|
||||
Throwable throwable = null;
|
||||
File convertedFile = null;
|
||||
try {
|
||||
publishProgress("Preparing", "5");
|
||||
|
||||
String origMd5 = OptiFinePatcher.calculateMD5(file[0]);
|
||||
convertedFile = new File(Tools.optifineDir, origMd5 + ".jar");
|
||||
if (!convertedFile.exists()) {
|
||||
publishProgress("Patching OptiFine Installer", null, "1", "true");
|
||||
|
||||
Tools.extractAssetFolder(MCLauncherActivity.this, "optifine_patch", Tools.optifineDir, true);
|
||||
|
||||
new File(Tools.optifineDir + "/optifine_patch/AndroidOptiFineUtilities.class.patch").delete();
|
||||
|
||||
String[] output = Tools.patchOptifineInstaller(MCLauncherActivity.this, file[0]);
|
||||
File patchedFile = new File(output[1]);
|
||||
|
||||
publishProgress("Converting OptiFine", null, null, "false");
|
||||
|
||||
System.setOut(new PrintStream(logOut));
|
||||
System.setErr(new PrintStream(logErr));
|
||||
|
||||
if (!convertedFile.exists()) {
|
||||
RuntimeException dxError = new RuntimeException(getResources().getString(R.string.error_convert_lib, "OptiFine") + "\n" + currentLog.toString());
|
||||
dxError.setStackTrace(new StackTraceElement[0]);
|
||||
throw dxError;
|
||||
}
|
||||
|
||||
patchedFile.delete();
|
||||
}
|
||||
|
||||
publishProgress("Launching OptiFine installer", null, null, "true");
|
||||
|
||||
File optDir = getDir("dalvik-cache", 0);
|
||||
optDir.mkdir();
|
||||
|
||||
DexClassLoader loader = new DexClassLoader(convertedFile.getAbsolutePath(), optDir.getAbsolutePath(), getApplicationInfo().nativeLibraryDir, getClass().getClassLoader());
|
||||
// AndroidOptiFineUtilities.originalOptifineJar = convertedFile.getAbsolutePath();
|
||||
|
||||
Class installerClass = loader.loadClass("optifine.AndroidInstaller");
|
||||
Method installerMethod = installerClass.getDeclaredMethod("doInstall", File.class);
|
||||
installerMethod.invoke(null, new File(Tools.MAIN_PATH));
|
||||
|
||||
publishProgress("(4/5) Patching OptiFine Tweaker", null, null);
|
||||
File optifineLibFile = new File("unimpl");
|
||||
if (!optifineLibFile.exists()) {
|
||||
throw new FileNotFoundException(optifineLibFile.getAbsolutePath() + "\n\n--- OptiFine installer log ---\n" + currentLog.toString());
|
||||
}
|
||||
new OptiFinePatcher(optifineLibFile).saveTweaker();
|
||||
convertedFile.delete();
|
||||
|
||||
publishProgress("(5/5) Done!", null, null);
|
||||
Thread.sleep(500);
|
||||
} catch (Throwable th) {
|
||||
throwable = th;
|
||||
} finally {
|
||||
System.setOut(logOut.getRootStream());
|
||||
System.setErr(logErr.getRootStream());
|
||||
/*
|
||||
if (throwable != null && convertedFile != null) {
|
||||
convertedFile.delete();
|
||||
}
|
||||
*/
|
||||
return throwable;
|
||||
}
|
||||
}
|
||||
/*
|
||||
private Object fromConfig(DexClassLoader loader, String name) throws ReflectiveOperationException {
|
||||
Field f = loader.loadClass("Config").getDeclaredField(name);
|
||||
f.setAccessible(true);
|
||||
return f.get(null);
|
||||
}
|
||||
*/
|
||||
@Override
|
||||
protected void onProgressUpdate(String[] text) {
|
||||
super.onProgressUpdate(text);
|
||||
dialog.setMessage(text[0]);
|
||||
if (text.length > 1 && text[1] != null) {
|
||||
dialog.setMax(Integer.valueOf(text[1]));
|
||||
} if (text.length > 2) {
|
||||
dialog.setProgress(dialog.getProgress() + 1);
|
||||
} if (text.length > 3 && text[3] != null) {
|
||||
dialog.setIndeterminate(Boolean.getBoolean(text[3]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Throwable th) {
|
||||
super.onPostExecute(th);
|
||||
dialog.dismiss();
|
||||
|
||||
new RefreshVersionListTask().execute();
|
||||
|
||||
if (th == null) {
|
||||
Toast.makeText(MCLauncherActivity.this, R.string.toast_optifine_success, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Tools.showError(MCLauncherActivity.this, th);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
List<Fragment> fragmentList = new ArrayList<>();
|
||||
|
@ -123,10 +123,10 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
private boolean isLogAllow = false;
|
||||
// private int navBarHeight = 40;
|
||||
|
||||
private static final int LTYPE_PROCESS = 0;
|
||||
private static final int LTYPE_INVOCATION = 1;
|
||||
private static final int LTYPE_CREATEJAVAVM = 2;
|
||||
private static final int LAUNCH_TYPE;
|
||||
public static final int LTYPE_PROCESS = 0;
|
||||
public static final int LTYPE_INVOCATION = 1;
|
||||
public static final int LTYPE_CREATEJAVAVM = 2;
|
||||
public static final int LAUNCH_TYPE;
|
||||
|
||||
static {
|
||||
int launchTypeFinal = LTYPE_INVOCATION;
|
||||
@ -214,7 +214,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.nav_forceclose: dialogForceClose();
|
||||
case R.id.nav_forceclose: dialogForceClose(MainActivity.this);
|
||||
break;
|
||||
case R.id.nav_viewlog: openLogOutput();
|
||||
break;
|
||||
@ -949,13 +949,6 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
}
|
||||
|
||||
private ShellProcessOperation mLaunchShell;
|
||||
private void setEnvironment(String name, String value) throws ErrnoException, IOException {
|
||||
if (LAUNCH_TYPE == LTYPE_PROCESS) {
|
||||
mLaunchShell.writeToProcess("export " + name + "=" + value);
|
||||
} else {
|
||||
Os.setenv(name, value, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startStrace(int pid) throws Exception {
|
||||
String[] straceArgs = new String[] {"/system/bin/strace",
|
||||
@ -1054,13 +1047,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
// "$JAVA_HOME/lib:$JAVA_HOME/lib/jli:$JAVA_HOME/lib/server"
|
||||
);
|
||||
|
||||
setEnvironment("JAVA_HOME", Tools.homeJreDir);
|
||||
setEnvironment("HOME", Tools.MAIN_PATH);
|
||||
setEnvironment("TMPDIR", getCacheDir().getAbsolutePath());
|
||||
// setEnvironment("LIBGL_MIPMAP", "3");
|
||||
setEnvironment("MESA_GLSL_CACHE_DIR", getCacheDir().getAbsolutePath());
|
||||
setEnvironment("LD_LIBRARY_PATH", ldLibraryPath);
|
||||
setEnvironment("PATH", Tools.homeJreDir + "/bin:" + Os.getenv("PATH"));
|
||||
BinaryExecutor.setJavaEnvironment();
|
||||
|
||||
// can fix java?
|
||||
// setEnvironment("ORIGIN", Tools.homeJreDir + "/lib");
|
||||
@ -1082,6 +1069,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
|
||||
BinaryExecutor.redirectStdio();
|
||||
// DEPRECATED constructor (String) api 29
|
||||
/*
|
||||
FileObserver fobs = new FileObserver(logFile.getAbsolutePath(), FileObserver.MODIFY){
|
||||
@Override
|
||||
public void onEvent(int event, String str) {
|
||||
@ -1089,6 +1077,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
}
|
||||
};
|
||||
fobs.startWatching();
|
||||
*/
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -1271,9 +1260,8 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
((Button) view).setText(isVis ? R.string.control_mouseoff: R.string.control_mouseon);
|
||||
}
|
||||
|
||||
public void dialogForceClose()
|
||||
{
|
||||
new AlertDialog.Builder(this)
|
||||
public static void dialogForceClose(Context ctx) {
|
||||
new AlertDialog.Builder(ctx)
|
||||
.setMessage(R.string.mcn_exit_confirm)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
|
||||
@ -1307,6 +1295,7 @@ public class MainActivity extends AppCompatActivity implements OnTouchListener,
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Prevent back
|
||||
// Catch back as Esc keycode at another place
|
||||
}
|
||||
|
||||
public void hideKeyboard() {
|
||||
|
21
app/src/main/res/layout/install_mod.xml
Normal file
21
app/src/main/res/layout/install_mod.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<TextureView
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/installmod_surfaceview"/>
|
||||
|
||||
<Button
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:background="@drawable/mcbutton"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/control_forceclose"
|
||||
android:onClick="forceClose"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
@ -48,7 +48,7 @@
|
||||
|
||||
<!-- AlertDialog title -->
|
||||
<string name="alerttitle_selectkeymap">Pilih sebuah keymap json</string>
|
||||
<string name="alerttitle_installmod">Pilih sebuah mod untuk di tambah</string>
|
||||
<string name="alerttitle_installmod">Pilih sebuah mod untuk dipasang</string>
|
||||
<string name="alerttitle_installoptifine">Pilih jar-nya OptiFine</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
|
@ -1,9 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="mcl_options">
|
||||
<item>@string/mcl_option_modmgr</item>
|
||||
<!-- <item>@string/mcl_option_forgeinstall</item> -->
|
||||
<item>@string/mcl_option_optifineinstall</item>
|
||||
<item>@string/mcl_option_modinstall</item>
|
||||
<item>@string/mcl_option_customcontrol</item>
|
||||
<item>@string/mcl_option_settings</item>
|
||||
<item>@string/mcl_option_about</item>
|
||||
|
@ -48,8 +48,7 @@
|
||||
|
||||
<!-- AlertDialog title -->
|
||||
<string name="alerttitle_selectkeymap">Select a keymap json</string>
|
||||
<string name="alerttitle_installmod">Select a mod to add</string>
|
||||
<string name="alerttitle_installoptifine">Select OptiFine jar file</string>
|
||||
<string name="alerttitle_installmod">Select a mod to install</string>
|
||||
|
||||
<!-- Error messages -->
|
||||
<string name="error_fatal">PojavLauncher has unexpectedly crashed</string>
|
||||
@ -87,7 +86,7 @@
|
||||
|
||||
<string name="mcl_options">Options</string>
|
||||
<string name="mcl_option_modmgr">Mod manager (no function)</string>
|
||||
<string name="mcl_option_optifineinstall">Install OptiFine</string>
|
||||
<string name="mcl_option_modinstall">Install mod (Forge, LabyMod, Fabric,...)</string>
|
||||
<string name="mcl_option_checkupdate">Check for update</string>
|
||||
<string name="mcl_option_customcontrol">Custom controls</string>
|
||||
<string name="mcl_option_settings">Settings</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user