- [Custom controls] Removed control size limit, prepare custom controls
screen.
- [Jailed] Use  directory as home instead of

- [Preference] Added "button scale"
- [Preferences] Moved into launcher_preferences.plist
This commit is contained in:
Duy Tran Khanh committed 2021-07-17 07:18:03 +07:00
1 parent 12f6fcf1b6
commit 8f5059e741
24 files changed
+275 -933

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
[submodule "Natives/external/DBNumberedSlider"]
path = Natives/external/DBNumberedSlider
url = https://github.com/immago/DBNumberedSlider
@@ -1,52 +0,0 @@
package net.kdt.pojavlaunch;
import android.os.*;
public class InstallerTask extends AsyncTask<String, Void, String>
{
@Override
protected String doInBackground(String[] p1)
{
try
{
downloadLibraries(p1[0]);
dexMinecraftLibs();
downloadMinecraft(p1[0]);
dexMinecraftClient(p1[0]);
downloadAssets(p1[0]);
}
catch (Exception e)
{
return e.getMessage();
}
return null;
}
@Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
if(result == null){
//No errors
}
}
private void downloadLibraries(String versionName) throws Exception
{
}
private void dexMinecraftLibs() throws Exception
{
}
private void downloadMinecraft(String versionName) throws Exception
{
}
private void dexMinecraftClient(String version) throws Exception
{
}
private void downloadAssets(String versionName) throws Exception
{
}
}
@@ -6,7 +6,6 @@ import java.util.concurrent.*;
import org.lwjgl.glfw.CallbackBridge;
import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.uikit.*;
import net.kdt.pojavlaunch.utils.*;
import net.kdt.pojavlaunch.value.*;
@@ -23,14 +22,10 @@ public class PLaunchApp {
File mcDir = new File(Tools.DIR_GAME_NEW);
mcDir.mkdirs();
new File(Tools.DIR_ACCOUNT_NEW).mkdirs();
if (!new File(Tools.DIR_APP_DATA, "config_ver.txt").exists()) {
Tools.write(Tools.DIR_APP_DATA + "/config_ver.txt", "1.16.5");
if (!new File(mcDir.getAbsolutePath() + "/launcher_profiles.json").exists()) {
Tools.write(mcDir.getAbsolutePath() + "/launcher_profiles.json",
Tools.read(Tools.DIR_DATA + "/launcher_profiles.json"));
}
LauncherPreferences.loadPreferences();
} catch (IOException e) {
e.printStackTrace();
}
@@ -62,9 +57,13 @@ public class PLaunchApp {
String mcver = "1.16.5";
try {
mcver = Tools.read(Tools.DIR_APP_DATA + "/config_ver.txt");
String plistContent = Tools.read(Tools.DIR_APP_DATA + "/launcher_preferences.plist");
plistContent = plistContent.substring(plistContent.indexOf("<key>selected_version</key>") + 26);
plistContent = plistContent.replace("<string>", "")
.substring(0, plistContent.indexOf("</string>")).trim();
} catch (IOException e) {
UIKit.updateProgressSafe(0, "config_ver.txt not found, defaulting to Minecraft 1.16.5");
e.printStackTrace();
UIKit.updateProgressSafe(0, "Could not parse plist, defaulting to Minecraft 1.16.5");
}
AccountJNI.CURRENT_ACCOUNT.selectedVersion = mcver;
@@ -31,7 +31,6 @@ import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.uikit.UIKit;
import net.kdt.pojavlaunch.utils.DownloadUtils;
import net.kdt.pojavlaunch.utils.JSONUtils;
@@ -59,7 +58,7 @@ public final class Tools
public static final String DIR_GAME_HOME = System.getenv("HOME") + "/Documents";
public static final String DIR_GAME_NEW = DIR_GAME_HOME + "/minecraft";
public static final String DIR_APP_DATA = DIR_GAME_HOME + "/.pojavlauncher";
public static final String DIR_APP_DATA = System.getenv("POJAV_HOME");
public static final String DIR_ACCOUNT_NEW = DIR_APP_DATA + "/accounts";
// New since 3.0.0
@@ -295,89 +294,7 @@ public final class Tools
return libStr.toString();
}
/*
public static DisplayMetrics getDisplayMetrics(Activity ctx) {
DisplayMetrics displayMetrics = new DisplayMetrics();
ctx.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics;
}
public static void setFullscreen(Activity act) {
final View decorView = act.getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
}
});
}
public static DisplayMetrics currentDisplayMetrics;
public static void updateWindowSize(Activity ctx) {
currentDisplayMetrics = getDisplayMetrics(ctx);
CallbackBridge.windowWidth = currentDisplayMetrics.widthPixels;
CallbackBridge.windowHeight = currentDisplayMetrics.heightPixels;
if (CallbackBridge.windowWidth < CallbackBridge.windowHeight) {
CallbackBridge.windowWidth = currentDisplayMetrics.heightPixels;
CallbackBridge.windowHeight = currentDisplayMetrics.widthPixels;
}
}
public static float dpToPx(float dp) {
// 921600 = 1280 * 720, default scale
// TODO better way to scaling
float scaledDp = dp; // / DisplayMetrics.DENSITY_XHIGH * currentDisplayMetrics.densityDpi;
return (scaledDp * currentDisplayMetrics.density);
}
public static void copyAssetFile(Context ctx, String fileName, String output, boolean overwrite) throws IOException {
copyAssetFile(ctx, fileName, output, new File(fileName).getName(), overwrite);
}
public static void copyAssetFile(Context ctx, String fileName, String output, String outputName, boolean overwrite) throws IOException
{
File file = new File(output);
if(!file.exists()) {
file.mkdirs();
}
File file2 = new File(output, outputName);
if(!file2.exists() || overwrite){
write(file2.getAbsolutePath(), loadFromAssetToByte(ctx, fileName));
}
}
public static void extractAssetFolder(Activity ctx, String path, String output) throws Exception {
extractAssetFolder(ctx, path, output, false);
}
public static void extractAssetFolder(Activity ctx, String path, String output, boolean overwrite) throws Exception {
AssetManager assetManager = ctx.getAssets();
String assets[] = null;
try {
assets = assetManager.list(path);
if (assets.length == 0) {
Tools.copyAssetFile(ctx, path, output, overwrite);
} else {
File dir = new File(output, path);
if (!dir.exists())
dir.mkdirs();
for (String sub : assets) {
extractAssetFolder(ctx, path + "/" + sub, output, overwrite);
}
}
} catch (Exception e) {
showError(ctx, e);
}
}
*/
public static void showError(Throwable e) {
showError(e, false);
}
@@ -1,85 +0,0 @@
package net.kdt.pojavlaunch.prefs;
import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.*;
public class LauncherPreferences
{
// public static SharedPreferences DEFAULT_PREF;
public static boolean PREF_VERTYPE_RELEASE = true;
public static boolean PREF_VERTYPE_SNAPSHOT = false;
public static boolean PREF_VERTYPE_OLDALPHA = false;
public static boolean PREF_VERTYPE_OLDBETA = false;
public static boolean PREF_FREEFORM = false;
public static float PREF_BUTTONSIZE = 100f;
public static float PREF_MOUSESCALE = 100f;
public static int PREF_LONGPRESS_TRIGGER = 500;
public static String PREF_DEFAULTCTRL_PATH = Tools.CTRLDEF_FILE;
public static String PREF_CUSTOM_JAVA_ARGS;
public static String PREF_CUSTOM_OPENGL_LIBNAME = "libgl4es_114.dylib";
public static String PREF_LANGUAGE = "default";
public static void loadPreferences() {
/*
PREF_BUTTONSIZE = DEFAULT_PREF.getInt("buttonscale", 100);
PREF_MOUSESCALE = DEFAULT_PREF.getInt("mousescale", 100);
PREF_FREEFORM = DEFAULT_PREF.getBoolean("freeform", false);
PREF_VERTYPE_RELEASE = DEFAULT_PREF.getBoolean("vertype_release", true);
PREF_VERTYPE_SNAPSHOT = DEFAULT_PREF.getBoolean("vertype_snapshot", false);
PREF_VERTYPE_OLDALPHA = DEFAULT_PREF.getBoolean("vertype_oldalpha", false);
PREF_VERTYPE_OLDBETA = DEFAULT_PREF.getBoolean("vertype_oldbeta", false);
PREF_LONGPRESS_TRIGGER = DEFAULT_PREF.getInt("timeLongPressTrigger", 500);
PREF_DEFAULTCTRL_PATH = DEFAULT_PREF.getString("defaultCtrl", Tools.CTRLDEF_FILE);
PREF_LANGUAGE = DEFAULT_PREF.getString("language", "default");
// Get double of max Android heap to set default heap size
int androidHeap = (int) (Runtime.getRuntime().maxMemory() / 1024l / 512l);
int doubleAndroidHeap = androidHeap * 2;
// PREF_CUSTOM_JAVA_ARGS = DEFAULT_PREF.getString("javaArgs", "");
if (PREF_CUSTOM_JAVA_ARGS.isEmpty()) {
String DEFAULT_JAVA_ARGS =
"-Xms" + (androidHeap > 800 ? 800 : androidHeap) + "m " +
// (32bit) More than 800mb may make JVM not allocateable and crash
"-Xmx" + (doubleAndroidHeap > 800 ? 800 : doubleAndroidHeap) + "m " +
"-XX:+UseG1GC " +
"-XX:+ParallelRefProcEnabled " +
"-XX:MaxGCPauseMillis=200 " +
"-XX:+UnlockExperimentalVMOptions " +
"-XX:+AlwaysPreTouch " +
"-XX:G1NewSizePercent=30 " +
"-XX:G1MaxNewSizePercent=40 " +
"-XX:G1HeapRegionSize=8M " +
"-XX:G1ReservePercent=20 " +
"-XX:G1HeapWastePercent=5 " +
"-XX:G1MixedGCCountTarget=4 " +
"-XX:InitiatingHeapOccupancyPercent=15 " +
"-XX:G1MixedGCLiveThresholdPercent=90 " +
"-XX:G1RSetUpdatingPauseTimePercent=5 " +
"-XX:SurvivorRatio=32 " +
"-XX:+PerfDisableSharedMem " +
"-XX:MaxTenuringThreshold=1";
PREF_CUSTOM_JAVA_ARGS = DEFAULT_JAVA_ARGS;
DEFAULT_PREF.edit().putString("javaArgs", DEFAULT_JAVA_ARGS).commit();
}
String argLwjglLibname = "-Dorg.lwjgl.opengl.libname=";
for (String arg : PREF_CUSTOM_JAVA_ARGS.split(" ")) {
if (arg.startsWith(argLwjglLibname)) {
PREF_CUSTOM_OPENGL_LIBNAME = arg.substring(argLwjglLibname.length());
}
}
*/
File argsFile = new File(Tools.DIR_APP_DATA, "overrideargs.txt");
try {
if (!argsFile.exists()) {
argsFile.createNewFile();
}
PREF_CUSTOM_JAVA_ARGS = Tools.read(argsFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@@ -1,337 +0,0 @@
package net.kdt.pojavlaunch.tasks;
import android.app.*;
import android.content.*;
import android.graphics.*;
import android.os.*;
import android.util.*;
import com.google.gson.*;
import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.*;
import net.kdt.pojavlaunch.value.*;
import org.apache.commons.io.*;
public class MinecraftDownloaderTask extends AsyncTask<String, String, Throwable>
{
private BaseLauncherActivity mActivity;
private boolean launchWithError = false;
MinecraftDownloaderTask thiz = this;
public MinecraftDownloaderTask(BaseLauncherActivity activity) {
mActivity = activity;
}
@Override
protected void onPreExecute() {
mActivity.mLaunchProgress.setMax(1);
mActivity.statusIsLaunching(true);
}
private JMinecraftVersionList.Version verInfo;
@Override
protected Throwable doInBackground(final String[] p1) {
Throwable throwable = null;
try {
final String downVName = "/" + p1[0] + "/" + p1[0];
//Downloading libraries
String minecraftMainJar = Tools.DIR_HOME_VERSION + downVName + ".jar";
JAssets assets = null;
try {
String verJsonDir = Tools.DIR_HOME_VERSION + downVName + ".json";
verInfo = findVersion(p1[0]);
if (verInfo.url != null && !new File(verJsonDir).exists()) {
publishProgress("1", mActivity.getString(R.string.mcl_launch_downloading, p1[0] + ".json"));
Tools.downloadFileMonitored(
verInfo.url,
verJsonDir,
new Tools.DownloaderFeedback(){
@Override
public void updateProgress(int curr, int max) {
publishDownloadProgress(p1[0] + ".json", curr, max);
}
}
);
}
verInfo = Tools.getVersionInfo(p1[0]);
assets = downloadIndex(verInfo.assets, new File(Tools.ASSETS_PATH, "indexes/" + verInfo.assets + ".json"));
File outLib;
String libPathURL;
setMax(verInfo.libraries.length);
zeroProgress();
for (final DependentLibrary libItem : verInfo.libraries) {
if (
libItem.name.startsWith("net.java.jinput") ||
libItem.name.startsWith("org.lwjgl")
) { // Black list
publishProgress("1", "Ignored " + libItem.name);
//Thread.sleep(100);
} else {
String[] libInfo = libItem.name.split(":");
String libArtifact = Tools.artifactToPath(libInfo[0], libInfo[1], libInfo[2]);
outLib = new File(Tools.DIR_HOME_LIBRARY + "/" + libArtifact);
outLib.getParentFile().mkdirs();
if (!outLib.exists()) {
publishProgress("1", mActivity.getString(R.string.mcl_launch_downloading, libItem.name));
boolean skipIfFailed = false;
if (libItem.downloads == null || libItem.downloads.artifact == null) {
MinecraftLibraryArtifact artifact = new MinecraftLibraryArtifact();
artifact.url = (libItem.url == null ? "https://libraries.minecraft.net/" : libItem.url) + libArtifact;
libItem.downloads = new DependentLibrary.LibraryDownloads(artifact);
skipIfFailed = true;
}
try {
libPathURL = libItem.downloads.artifact.url;
Tools.downloadFileMonitored(
libPathURL,
outLib.getAbsolutePath(),
new Tools.DownloaderFeedback() {
@Override
public void updateProgress(int curr, int max) {
publishDownloadProgress(libItem.name, curr, max);
}
}
);
} catch (Throwable th) {
if (!skipIfFailed) {
throw th;
} else {
th.printStackTrace();
publishProgress("0", th.getMessage());
}
}
}
}
}
setMax(3);
zeroProgress();
publishProgress("1", mActivity.getString(R.string.mcl_launch_downloading, p1[0] + ".jar"));
File minecraftMainFile = new File(minecraftMainJar);
if (!minecraftMainFile.exists() || minecraftMainFile.length() == 0l) {
try {
Tools.downloadFileMonitored(
verInfo.downloads.values().toArray(new MinecraftClientInfo[0])[0].url,
minecraftMainJar,
new Tools.DownloaderFeedback() {
@Override
public void updateProgress(int curr, int max) {
publishDownloadProgress(p1[0] + ".jar", curr, max);
}
}
);
} catch (Throwable th) {
if (verInfo.inheritsFrom != null) {
minecraftMainFile.delete();
FileInputStream is = new FileInputStream(new File(Tools.DIR_HOME_VERSION, verInfo.inheritsFrom + "/" + verInfo.inheritsFrom + ".jar"));
FileOutputStream os = new FileOutputStream(minecraftMainFile);
IOUtils.copy(is, os);
is.close();
os.close();
} else {
throw th;
}
}
}
} catch (Throwable e) {
launchWithError = true;
throw e;
}
publishProgress("1", mActivity.getString(R.string.mcl_launch_cleancache));
// new File(inputPath).delete();
for (File f : new File(Tools.DIR_HOME_VERSION).listFiles()) {
if(f.getName().endsWith(".part")) {
System.out.println("Cleaning cache: " + f);
f.delete();
}
}
mActivity.mIsAssetsProcessing = true;
mActivity.mPlayButton.post(new Runnable(){
@Override
public void run()
{
mActivity.mPlayButton.setText("Skip");
mActivity.mPlayButton.setEnabled(true);
}
});
publishProgress("1", mActivity.getString(R.string.mcl_launch_download_assets));
setMax(assets.objects.size());
zeroProgress();
try {
downloadAssets(assets, verInfo.assets, new File(Tools.ASSETS_PATH));
} catch (Exception e) {
e.printStackTrace();
// Ignore it
launchWithError = false;
} finally {
mActivity.mIsAssetsProcessing = false;
}
} catch (Throwable th){
throwable = th;
} finally {
return throwable;
}
}
private int addProgress = 0;
public void zeroProgress() {
addProgress = 0;
}
public void setMax(final int value)
{
mActivity.mLaunchProgress.post(new Runnable(){
@Override
public void run()
{
mActivity.mLaunchProgress.setMax(value);
}
});
}
private void publishDownloadProgress(String target, int curr, int max) {
// array length > 2 ignores append log on dev console
publishProgress("0", mActivity.getString(R.string.mcl_launch_downloading_progress, target,
curr / 1024d / 1024d, max / 1024d / 1024d), "");
}
@Override
protected void onProgressUpdate(String... p1)
{
int addedProg = Integer.parseInt(p1[0]);
if (addedProg != -1) {
addProgress = addProgress + addedProg;
mActivity.mLaunchProgress.setProgress(addProgress);
mActivity.mLaunchTextStatus.setText(p1[1]);
}
if (p1.length < 3) {
mActivity.mConsoleView.putLog(p1[1] + "\n");
}
}
@Override
protected void onPostExecute(Throwable p1)
{
mActivity.mPlayButton.setText("Play");
mActivity.mPlayButton.setEnabled(true);
mActivity.mLaunchProgress.setMax(100);
mActivity.mLaunchProgress.setProgress(0);
mActivity.statusIsLaunching(false);
if(p1 != null) {
p1.printStackTrace();
Tools.showError(mActivity, p1);
}
if(!launchWithError) {
mActivity.mCrashView.setLastCrash("");
try {
/*
List<String> jvmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();
jvmArgs.add("-Xms128M");
jvmArgs.add("-Xmx1G");
*/
Intent mainIntent = new Intent(mActivity, MainActivity.class /* MainActivity.class */);
// mainIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
if (LauncherPreferences.PREF_FREEFORM) {
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
ActivityOptions options = (ActivityOptions) ActivityOptions.class.getMethod("makeBasic").invoke(null);
Rect freeformRect = new Rect(0, 0, dm.widthPixels / 2, dm.heightPixels / 2);
options.getClass().getDeclaredMethod("setLaunchBounds", Rect.class).invoke(options, freeformRect);
mActivity.startActivity(mainIntent, options.toBundle());
} else {
mActivity.startActivity(mainIntent);
}
}
catch (Throwable e) {
Tools.showError(mActivity, e);
}
/*
FloatingIntent maini = new FloatingIntent(PojavLauncherActivity.this, MainActivity.class);
maini.startFloatingActivity();
*/
}
mActivity.mTask = null;
}
public static final String MINECRAFT_RES = "https://resources.download.minecraft.net/";
public JAssets downloadIndex(String versionName, File output) throws Throwable {
if (!output.exists()) {
output.getParentFile().mkdirs();
DownloadUtils.downloadFile(verInfo.assetIndex != null ? verInfo.assetIndex.url : "http://s3.amazonaws.com/Minecraft.Download/indexes/" + versionName + ".json", output);
}
return Tools.GLOBAL_GSON.fromJson(Tools.read(output.getAbsolutePath()), JAssets.class);
}
public void downloadAsset(JAssetInfo asset, File objectsDir) throws IOException, Throwable {
String assetPath = asset.hash.substring(0, 2) + "/" + asset.hash;
File outFile = new File(objectsDir, assetPath);
if (!outFile.exists()) {
DownloadUtils.downloadFile(MINECRAFT_RES + assetPath, outFile);
}
}
public void downloadAssets(JAssets assets, String assetsVersion, File outputDir) throws IOException, Throwable {
File hasDownloadedFile = new File(outputDir, "downloaded/" + assetsVersion + ".downloaded");
if (!hasDownloadedFile.exists()) {
System.out.println("Assets begin time: " + System.currentTimeMillis());
Map<String, JAssetInfo> assetsObjects = assets.objects;
mActivity.mLaunchProgress.setMax(assetsObjects.size());
zeroProgress();
File objectsDir = new File(outputDir, "objects");
int downloadedSs = 0;
for (JAssetInfo asset : assetsObjects.values()) {
if (!mActivity.mIsAssetsProcessing) {
return;
}
downloadAsset(asset, objectsDir);
publishProgress("1", mActivity.getString(R.string.mcl_launch_downloading, assetsObjects.keySet().toArray(new String[0])[downloadedSs]));
downloadedSs++;
}
hasDownloadedFile.getParentFile().mkdirs();
hasDownloadedFile.createNewFile();
System.out.println("Assets end time: " + System.currentTimeMillis());
}
}
private JMinecraftVersionList.Version findVersion(String version) {
if (mActivity.mVersionList != null) {
for (JMinecraftVersionList.Version valueVer: mActivity.mVersionList.versions) {
if (valueVer.id.equals(version)) {
return valueVer;
}
}
}
// Custom version, inherits from base.
return Tools.getVersionInfo(version);
}
}
@@ -1,132 +0,0 @@
package net.kdt.pojavlaunch.tasks;
import android.os.*;
import androidx.appcompat.widget.*;
import android.view.*;
import android.widget.*;
import android.widget.AdapterView.*;
import java.io.*;
import java.util.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.prefs.*;
import net.kdt.pojavlaunch.utils.*;
import androidx.appcompat.widget.PopupMenu;
public class RefreshVersionListTask extends AsyncTask<Void, Void, ArrayList<String>>
{
private BaseLauncherActivity mActivity;
public RefreshVersionListTask(BaseLauncherActivity activity) {
mActivity = activity;
}
@Override
protected ArrayList<String> doInBackground(Void[] p1)
{
try {
mActivity.mVersionList = Tools.GLOBAL_GSON.fromJson(DownloadUtils.downloadString("https://launchermeta.mojang.com/mc/game/version_manifest.json"), JMinecraftVersionList.class);
ArrayList<String> versionStringList = filter(mActivity.mVersionList.versions, new File(Tools.DIR_HOME_VERSION).listFiles());
return versionStringList;
} catch (Exception e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(ArrayList<String> result)
{
super.onPostExecute(result);
final PopupMenu popup = new PopupMenu(mActivity, mActivity.mVersionSelector);
popup.getMenuInflater().inflate(R.menu.menu_versionopt, popup.getMenu());
if(result != null && result.size() > 0) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_spinner_item, result);
adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);
mActivity.mVersionSelector.setAdapter(adapter);
mActivity.mVersionSelector.setSelection(selectAt(result.toArray(new String[0]), mActivity.mProfile.selectedVersion));
} else {
mActivity.mVersionSelector.setSelection(selectAt(mActivity.mAvailableVersions, mActivity.mProfile.selectedVersion));
}
mActivity.mVersionSelector.setOnItemSelectedListener(new OnItemSelectedListener(){
@Override
public void onItemSelected(AdapterView<?> p1, View p2, int p3, long p4)
{
String version = p1.getItemAtPosition(p3).toString();
mActivity.mProfile.selectedVersion = version;
PojavProfile.setCurrentProfile(mActivity, mActivity.mProfile);
if (PojavProfile.isFileType(mActivity)) {
try {
PojavProfile.setCurrentProfile(mActivity, mActivity.mProfile.save());
} catch (IOException e) {
Tools.showError(mActivity, e);
}
}
mActivity.mTextVersion.setText(mActivity.getString(R.string.mcl_version_msg, version));
}
@Override
public void onNothingSelected(AdapterView<?> p1)
{
// TODO: Implement this method
}
});
mActivity.mVersionSelector.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener(){
@Override
public boolean onItemLongClick(AdapterView<?> p1, View p2, int p3, long p4)
{
// Implement copy, remove, reinstall,...
popup.show();
return true;
}
});
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
return true;
}
});
mActivity.mTextVersion.setText(mActivity.getString(R.string.mcl_version_msg) + mActivity.mVersionSelector.getSelectedItem());
}
private ArrayList<String> filter(JMinecraftVersionList.Version[] list1, File[] list2) {
ArrayList<String> output = new ArrayList<String>();
for (JMinecraftVersionList.Version value1: list1) {
if ((value1.type.equals("release") && LauncherPreferences.PREF_VERTYPE_RELEASE) ||
(value1.type.equals("snapshot") && LauncherPreferences.PREF_VERTYPE_SNAPSHOT) ||
(value1.type.equals("old_alpha") && LauncherPreferences.PREF_VERTYPE_OLDALPHA) ||
(value1.type.equals("old_beta") && LauncherPreferences.PREF_VERTYPE_OLDBETA)) {
output.add(value1.id);
}
}
for (File value2: list2) {
if (!output.contains(value2.getName())) {
output.add(value2.getName());
}
}
return output;
}
private int selectAt(String[] strArr, String select) {
int count = 0;
for(String str : strArr){
if (str.equals(select)) {
return count;
} else {
count++;
}
}
return -1;
}
}
@@ -10,130 +10,14 @@ import java.util.*;
// import libcore.io.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.prefs.*;
import org.lwjgl.glfw.*;
public class JREUtils
{
private JREUtils() {}
public static String LD_LIBRARY_PATH;
private static String nativeLibDir;
public static String findInLdLibPath(String libName) {
for (String libPath : System.getenv("LD_LIBRARY_PATH").split(":")) {
File f = new File(libPath, libName);
if (f.exists() && f.isFile()) {
return f.getAbsolutePath();
}
}
return libName;
}
public static void initJavaRuntime() {
/*
dlopen(findInLdLibPath("libjli.dylib"));
dlopen(findInLdLibPath("libjvm.dylib"));
dlopen(findInLdLibPath("libverify.dylib"));
dlopen(findInLdLibPath("libjava.dylib"));
// dlopen(findInLdLibPath("libjsig.so"));
dlopen(findInLdLibPath("libnet.dylib"));
dlopen(findInLdLibPath("libnio.dylib"));
dlopen(findInLdLibPath("libawt.dylib"));
dlopen(findInLdLibPath("libawt_headless.dylib"));
dlopen(findInLdLibPath("libfreetype.dylib"));
dlopen(findInLdLibPath("libfontmanager.dylib"));
*/
dlopen(nativeLibDir + "/libopenal.dylib");
/*
if (LauncherPreferences.PREF_CUSTOM_OPENGL_LIBNAME.equals("libgl04es.so")) {
LauncherPreferences.PREF_CUSTOM_OPENGL_LIBNAME = nativeLibDir + "/libgl04es.so";
}
if (!dlopen(LauncherPreferences.PREF_CUSTOM_OPENGL_LIBNAME) && !dlopen(findInLdLibPath(LauncherPreferences.PREF_CUSTOM_OPENGL_LIBNAME))) {
System.err.println("Failed to load custom OpenGL library " + LauncherPreferences.PREF_CUSTOM_OPENGL_LIBNAME + ". Fallbacking to GL4ES.");
dlopen(nativeLibDir + "/libgl04es.so");
}
*/
}
public static Map<String, String> readJREReleaseProperties() throws IOException {
Map<String, String> jreReleaseMap = new ArrayMap<>();
BufferedReader jreReleaseReader = new BufferedReader(new FileReader(Tools.DIR_HOME_JRE + "/release"));
String currLine;
while ((currLine = jreReleaseReader.readLine()) != null) {
if (!currLine.isEmpty() || currLine.contains("=")) {
String[] keyValue = currLine.split("=");
jreReleaseMap.put(keyValue[0], keyValue[1].replace("\"", ""));
}
}
jreReleaseReader.close();
return jreReleaseMap;
}
private static boolean checkAccessTokenLeak = true;
public static void redirectAndPrintJRELog(final String accessToken) {
}
public static void relocateLibPath() throws Exception {
StringBuilder ldLibraryPath = new StringBuilder();
ldLibraryPath.append(
// To make libjli.so ignore re-execute
Tools.DIR_HOME_JRE + "/" + Tools.DIRNAME_HOME_JRE + "/server:" +
Tools.DIR_HOME_JRE + "/" + Tools.DIRNAME_HOME_JRE + "/jli:" +
Tools.DIR_HOME_JRE + "/" + Tools.DIRNAME_HOME_JRE + ":" +
Tools.DIR_DATA + "/Frameworks:"+
System.getenv("DYLD_LIBRARY_PATH")
);
LD_LIBRARY_PATH = ldLibraryPath.toString();
}
public static void setJavaEnvironment() throws Throwable {
Map<String, String> envMap = new ArrayMap<>();
envMap.put("JAVA_HOME", Tools.DIR_HOME_JRE);
envMap.put("HOME", Tools.DIR_GAME_NEW);
envMap.put("TMPDIR", System.getProperty("java.io.tmpdir"));
envMap.put("LIBGL_MIPMAP", "3");
// Fix white color on banner and sheep, since GL4ES 1.1.5
envMap.put("LIBGL_NORMALIZE", "1");
envMap.put("MESA_GLSL_CACHE_DIR", System.getProperty("java.io.tmpdir"));
envMap.put("DYLD_LIBRARY_PATH", LD_LIBRARY_PATH);
// envMap.put("PATH", Tools.DIR_HOME_JRE + "/bin:" + Os.getenv("PATH"));
File customEnvFile = new File(Tools.DIR_GAME_NEW, "custom_env.txt");
if (customEnvFile.exists() && customEnvFile.isFile()) {
BufferedReader reader = new BufferedReader(new FileReader(customEnvFile));
String line;
while ((line = reader.readLine()) != null) {
// Not use split() as only split first one
int index = line.indexOf("=");
envMap.put(line.substring(0, index), line.substring(index + 1));
}
reader.close();
}
for (Map.Entry<String, String> env : envMap.entrySet()) {
setenv(env.getKey(), env.getValue(), true);
}
setLdLibraryPath(LD_LIBRARY_PATH);
// return ldLibraryPath;
}
public static native int chdir(String path);
public static native boolean dlopen(String libPath);
public static native void redirectLogcat(String path);
public static native void setLdLibraryPath(String ldLibraryPath);
public static native void saveGLContext();
public static native void setenv(String key, String value, boolean overwrite);
// Obtain AWT screen pixels to render on Android SurfaceView
public static native int[] renderAWTScreenFrame(/* Object canvas, int width, int height */);
static {
System.loadLibrary("pojavexec");
+37 -10
View File
@@ -1,19 +1,33 @@
cmake_minimum_required(VERSION 3.6)
project(PojavLauncher)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcommon -fobjc-arc -ObjC -I'${CMAKE_CURRENT_LIST_DIR}/resources/Frameworks/MetalANGLE.framework/Headers'")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcommon -fobjc-arc -ObjC -I'${CMAKE_CURRENT_LIST_DIR}/resources/Frameworks/MetalANGLE.framework/Headers' -I'${CMAKE_CURRENT_LIST_DIR}/external/DBNumberedSlider/Classes'"
)
set(CMAKE_SHARED_LINKER_FLAGS "'${CMAKE_SHARED_LINKER_FLAGS}' -rpath @executable_path/Frameworks -rpath @loader_path/Frameworks")
add_executable(PojavLauncher main.m log.m JavaLauncher.m)
target_link_libraries(PojavLauncher
"-framework UIKit"
)
set_target_properties(PojavLauncher PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_FRAMEWORK_IDENTIFIER org.cmake.ExecutableTarget
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/Info.plist")
set(CMAKE_EXE_LINKER_FLAGS "'${CMAKE_EXE_LINKER_FLAGS}' -rpath @executable_path/Frameworks -rpath @loader_path/Frameworks")
add_library(pojavexec SHARED log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LauncherPreferencesViewController.m LauncherFAQViewController.m LoginViewController.m SurfaceViewController.m UpdateHistoryViewController.m AboutLauncherViewController.m ios_uikit_bridge.m customcontrols/ControlButton.m egl_bridge.m input_bridge_v3.m utils.m)
add_library(pojavexec SHARED
AboutLauncherViewController.m
AppDelegate.m
CustomControlsViewController.m
LauncherFAQViewController.m
LauncherPreferences.m
LauncherPreferencesViewController.m
LauncherViewController.m
LoginViewController.m
SceneDelegate.m
SurfaceViewController.m
UpdateHistoryViewController.m
customcontrols/ControlButton.m
egl_bridge.m
external/DBNumberedSlider/Classes/DBNumberedSlider.m
input_bridge_v3.m
ios_uikit_bridge.m
log.m
utils.m
)
target_link_libraries(pojavexec
"-F'${CMAKE_CURRENT_LIST_DIR}/resources/Frameworks'"
"-framework UIKit"
@@ -22,3 +36,16 @@ target_link_libraries(pojavexec
"-framework AuthenticationServices"
"-Wl,-undefined -Wl,dynamic_lookup"
)
add_executable(PojavLauncher
main.m
log.m
JavaLauncher.m)
target_link_libraries(PojavLauncher
"-L'${CMAKE_CURRENT_LIST_DIR}/build'"
"-framework UIKit -lpojavexec"
)
set_target_properties(PojavLauncher PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_FRAMEWORK_IDENTIFIER org.cmake.ExecutableTarget
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/Info.plist")
+5
View File
@@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>
@interface CustomControlsViewController : UIViewController
@end
+58
View File
@@ -0,0 +1,58 @@
#import "CustomControlsViewController.h"
#include "utils.h"
@interface CustomControlsViewController () {
}
// - (void)method
@end
@implementation CustomControlsViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:YES];
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
[self setTitle:@"Custom controls"];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGFloat screenScale = [[UIScreen mainScreen] scale];
int width = (int) roundf(screenBounds.size.width);
int height = (int) roundf(screenBounds.size.height);
// Update color mode once
if(@available(iOS 13.0, *)) {
[self traitCollectionDidChange:nil];
} else {
self.view.backgroundColor = [UIColor whiteColor];
}
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeBottom;
}
- (BOOL)prefersHomeIndicatorAutoHidden {
return NO;
}
-(void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
if(@available(iOS 13.0, *)) {
if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
self.view.backgroundColor = [UIColor blackColor];
} else {
self.view.backgroundColor = [UIColor whiteColor];
}
}
}
@end
-1
View File
@@ -5,4 +5,3 @@
static bool started = false;
int launchJVM(int argc, char *argv[]);
int launchUI(int argc, char *argv[]);
+43 -29
View File
@@ -18,6 +18,8 @@
#include "utils.h"
#include "JavaLauncher.h"
#import "LauncherPreferences.h"
// PojavLancher: fixme: are these wrong?
#define FULL_VERSION "1.8.0-internal"
#define DOT_VERSION "1.8"
@@ -81,43 +83,55 @@ void init_loadCustomEnv() {
}
void init_loadCustomJvmFlags() {
char jvmargs[10000];
FILE* argsFile = fopen(args_path, "r");
debug("[Pre-init] Reading custom JVM args (overrideargs.txt), opened=%d\n", argsFile != NULL);
if (argsFile) {
if (!fgets(jvmargs, 10000, argsFile)) {
debug("[Pre-init] Warning: could not read overrideargs.txt");
fclose(argsFile);
return;
}
char *pch;
pch = strtok(jvmargs, " ");
while (pch != NULL) {
margv[margc] = (char*)calloc(1, (strlen(pch)+1) * sizeof(char));
strcpy(margv[margc], pch);
debug("[Pre-init] Added custom flag: %s", margv[margc]);
pch = strtok(NULL, " ");
++margc;
}
fclose(argsFile);
NSString *jvmargs = getPreference(@"java_args");
for (NSString *jvmarg in [jvmargs componentsSeparatedByString:@" -"]) {
if ([jvmarg length] == 0) continue;
margv[margc] = (char *) [jvmarg UTF8String];
NSLog(@"[Pre-init] Added custom JVM flag: %@", jvmarg);
++margc;
}
}
void init_migrateToPlist(char* prefKey, char* filename) {
// NSString *readmeStr = @"#README - this file has been merged into launcher_preferences.plist";
NSError *error;
NSString *str, *path_str;
// overrideargs.txt
path_str = [NSString stringWithFormat:@"%s/%s", getenv("POJAV_HOME"), filename];
str = [NSString stringWithContentsOfFile:path_str encoding:NSUTF8StringEncoding error:&error];
if (error == nil && ![str hasPrefix:@"#README"]) {
setPreference(@(prefKey), str);
[@"#README - this file has been merged into launcher_preferences.plist" writeToFile:path_str atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
}
int launchJVM(int argc, char *argv[]) {
char *homeDir;
if (!started) {
setenv("BUNDLE_PATH", dirname(argv[0]), 1);
// Are we running on a jailbroken environment?
if (strncmp(argv[0], "/Applications", 13) == 0) {
setenv("HOME", "/var/mobile", 1);
homeDir = "/var/mobile/Documents/.pojavlauncher";
} else {
char pojavHome[2048];
sprintf(pojavHome, "%s/Documents", getenv("HOME"));
homeDir = (char *) pojavHome;
}
setenv("POJAV_HOME", homeDir, 1);
} else {
homeDir = getenv("POJAV_HOME");
}
char* homeDir = getenv("HOME");
sprintf((char*) args_path, "%s/Documents/.pojavlauncher/overrideargs.txt", homeDir);
sprintf((char*) env_path, "%s/Documents/.pojavlauncher/custom_env.txt", homeDir);
sprintf((char*) log_path, "%s/Documents/.pojavlauncher/latestlog.txt", homeDir);
loadPreferences();
init_migrateToPlist("selected_version", "config_ver.txt");
init_migrateToPlist("java_args", "overrideargs.txt");
sprintf((char*) env_path, "%s/custom_env.txt", homeDir);
sprintf((char*) log_path, "%s/latestlog.txt", homeDir);
sprintf((char*) java_libs_path, "%s/libs", getenv("BUNDLE_PATH"));
mkdir(dirname(log_path), 755);
@@ -127,7 +141,7 @@ int launchJVM(int argc, char *argv[]) {
// Redirect stdio to latestlog.txt
int ret;
char newname[2048];
sprintf(newname, "%s/Documents/.pojavlauncher/latestlog.old.txt", homeDir);
sprintf(newname, "%s/latestlog.old.txt", homeDir);
ret = rename(log_path, newname);
FILE* logFile = fopen(log_path, "w");
if (!logFile) {
@@ -143,6 +157,8 @@ int launchJVM(int argc, char *argv[]) {
debug("[Pre-init] Beginning JVM launch\n");
// setenv("LIBGL_FB", "2", 1);
setenv("LIBGL_MIPMAP", "3", 1);
// Fix white color on banner and sheep, since GL4ES 1.1.5
setenv("LIBGL_NORMALIZE", "1", 1);
init_loadCustomEnv();
@@ -160,7 +176,7 @@ int launchJVM(int argc, char *argv[]) {
}
char controlPath[2048];
sprintf(controlPath, "%s/Documents/.pojavlauncher/controlmap", homeDir);
sprintf(controlPath, "%s/controlmap", homeDir);
mkdir(controlPath, S_IRWXU | S_IRWXG | S_IRWXO);
setenv("POJAV_PATH_CONTROL", controlPath, 1);
@@ -190,8 +206,8 @@ int launchJVM(int argc, char *argv[]) {
char *userHome = calloc(1, 2048);
snprintf(frameworkPath, 2048, "-Djava.library.path=%s/Frameworks", getenv("BUNDLE_PATH"));
snprintf(javaPath, 2048, "%s/bin/java", javaHome);
snprintf(userDir, 2048, "-Duser.dir=%s/Documents/minecraft", homeDir);
snprintf(userHome, 2048, "-Duser.home=%s/Documents", homeDir);
snprintf(userDir, 2048, "-Duser.dir=%s/Documents/minecraft", getenv("HOME"));
snprintf(userHome, 2048, "-Duser.home=%s/Documents", getenv("HOME"));
chdir(userDir);
@@ -285,11 +301,9 @@ int launchJVM(int argc, char *argv[]) {
debug("[Init] Calling JLI_Launch");
/*
for (int i = 0; i < margc; i++) {
debug("arg[%d] = %s", i, margv[i]);
}
*/
int targc = started ? argc : margc;
char **targv = started ? argv : margv;
+5
View File
@@ -0,0 +1,5 @@
#import <Foundation/Foundation.h>
void loadPreferences();
id getPreference(NSString* key);
void setPreference(NSString* key, id value);
+40
View File
@@ -0,0 +1,40 @@
#import "LauncherPreferences.h"
NSMutableDictionary *prefDict;
NSString* prefPath;
void loadPreferences() {
prefPath = [@(getenv("POJAV_HOME"))
stringByAppendingPathComponent:@"launcher_preferences.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:prefPath]) {
prefDict = [[NSMutableDictionary alloc] init];
prefDict[@"button_scale"] = @(100);
prefDict[@"selected_version"] = @"1.7.10";
prefDict[@"vertype_release"] = @YES;
prefDict[@"vertype_snapshot"] = @NO;
prefDict[@"vertype_oldalpha"] = @NO;
prefDict[@"vertype_oldbeta"] = @NO;
prefDict[@"time_longPressTrigger"] = @(400);
prefDict[@"default_ctrl"] = @"default.json";
prefDict[@"java_args"] = @"";
prefDict[@"custom_envVars"] = @""; // TODO
[prefDict writeToFile:prefPath atomically:YES];
} else {
prefDict = [NSMutableDictionary dictionaryWithContentsOfFile:prefPath];
}
}
id getPreference(NSString* key) {
NSObject *object = prefDict[key];
if (object == [NSNull null] || object == nil) {
NSLog(@"LauncherPreferences: %@ is NULL", key);
}
return object;
}
void setPreference(NSString* key, id value) {
prefDict[key] = value;
[prefDict writeToFile:prefPath atomically:YES];
}
+23 -8
View File
@@ -1,3 +1,5 @@
#import "DBNumberedSlider.h"
#import "LauncherPreferences.h"
#import "LauncherPreferencesViewController.h"
#include "utils.h"
@@ -39,27 +41,40 @@ UITextField* versionTextField;
self.view.backgroundColor = [UIColor whiteColor];
}
// not yet finished, empty view controller for now
/*
UILabel *btnsizeTextView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, 4.0, 0.0, 30.0)];
btnsizeTextView.text = @"Button size: ";
UILabel *btnsizeTextView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, 8.0, 0.0, 30.0)];
btnsizeTextView.text = @"Button scale: ";
btnsizeTextView.numberOfLines = 0;
btnsizeTextView.textAlignment = NSTextAlignmentCenter;
[btnsizeTextView sizeToFit];
CGRect tempRect = btnsizeTextView.frame;
tempRect.size.height = 30.0;
btnsizeTextView.frame = tempRect;
[scrollView addSubview:btnsizeTextView];
UISlider *buttonSizeSlider = [[UISlider alloc] initWithFrame:CGRectMake(8.0 + btnsizeTextView.frame.x, 4.0, 200.0, 30.0)];
// [buttonSizeSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
DBNumberedSlider *buttonSizeSlider = [[DBNumberedSlider alloc] initWithFrame:CGRectMake(8.0 + btnsizeTextView.frame.size.width, 8.0, self.view.frame.size.width - 8.0 + btnsizeTextView.frame.origin.x, btnsizeTextView.frame.size.height)];
buttonSizeSlider.tag = 1;
[buttonSizeSlider addTarget:self action:@selector(sliderMoved:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
[buttonSizeSlider setBackgroundColor:[UIColor clearColor]];
buttonSizeSlider.minimumValue = 50.0;
buttonSizeSlider.maximumValue = 200.0;
buttonSizeSlider.continuous = YES;
buttonSizeSlider.value = 50.0;
buttonSizeSlider.value = ((NSNumber *) getPreference(@"button_scale")).floatValue;
[scrollView addSubview:buttonSizeSlider];
*/
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, scrollView.frame.size.height + 200);
}
- (void)sliderMoved:(DBNumberedSlider *)sender {
switch (sender.tag) {
case 1:
setPreference(@"button_scale", @(sender.value));
break;
default:
NSLog(@"what does slider %ld for? implement me!", sender.tag);
break;
}
}
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeBottom;
+14 -13
View File
@@ -1,5 +1,7 @@
#import "LauncherViewController.h"
#import "CustomControlsViewController.h"
#import "LauncherPreferences.h"
#import "LauncherPreferencesViewController.h"
#import "LauncherViewController.h"
#include "utils.h"
@@ -12,8 +14,6 @@
@implementation LauncherViewController
NSString* configver_path;
NSArray* versionList;
UIPickerView* versionPickerView;
UITextField* versionTextField;
@@ -45,13 +45,6 @@ int versionSelectedAt = 0;
self.view.backgroundColor = [UIColor whiteColor];
}
NSError *error;
configver_path = [NSString stringWithFormat:@"%s/Documents/.pojavlauncher/config_ver.txt", getenv("HOME")];
NSString *configver = [NSString stringWithContentsOfFile:configver_path encoding:NSUTF8StringEncoding error:&error];
if (error) {
NSLog(@"Error: could not read config_ver.txt: %@", error.localizedDescription);
}
UILabel *versionTextView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, 4.0, 0.0, 0.0)];
versionTextView.text = @"Minecraft version: ";
versionTextView.numberOfLines = 0;
@@ -61,7 +54,7 @@ int versionSelectedAt = 0;
versionTextField = [[UITextField alloc] initWithFrame:CGRectMake(versionTextView.bounds.size.width + 4.0, 4.0, width - versionTextView.bounds.size.width - 8.0, height - 58.0)];
[versionTextField addTarget:versionTextField action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
versionTextField.placeholder = @"Specify version...";
versionTextField.text = configver;
versionTextField.text = (NSString *) getPreference(@"selected_version");
versionTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
versionTextField.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
@@ -79,7 +72,10 @@ int versionSelectedAt = 0;
[scrollView addSubview:versionTextField];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Settings" style:UIBarButtonItemStyleDone target:self action:@selector(enterPreferences)];
self.navigationItem.rightBarButtonItems = @[
[[UIBarButtonItem alloc] initWithTitle:@"Custom controls" style:UIBarButtonItemStyleDone target:self action:@selector(enterCustomControls)],
[[UIBarButtonItem alloc] initWithTitle:@"Settings" style:UIBarButtonItemStyleDone target:self action:@selector(enterPreferences)]
];
install_progress_bar = [[UIProgressView alloc] initWithFrame:CGRectMake(4.0, height - 58.0, width - 8.0, 6.0)];
[scrollView addSubview:install_progress_bar];
@@ -185,6 +181,11 @@ int versionSelectedAt = 0;
}
#pragma mark - Button click events
- (void)enterCustomControls {
CustomControlsViewController *vc = [[CustomControlsViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
- (void)enterPreferences {
LauncherPreferencesViewController *vc = [[LauncherPreferencesViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
@@ -207,7 +208,7 @@ int versionSelectedAt = 0;
#pragma mark - UIPickerView stuff
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
versionTextField.text = [self pickerView:pickerView titleForRow:row forComponent:component];
[versionTextField.text writeToFile:configver_path atomically:NO encoding:NSUTF8StringEncoding error:nil];
setPreference(@"selected_version", versionTextField.text);
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
+2 -2
View File
@@ -384,7 +384,7 @@ NSMutableArray *accountList;
DIR *d;
struct dirent *dir;
char accPath[2048];
sprintf(accPath, "%s/Documents/.pojavlauncher/accounts", getenv("HOME"));
sprintf(accPath, "%s/accounts", getenv("POJAV_HOME"));
d = opendir(accPath);
if (d) {
int i = 0;
@@ -438,7 +438,7 @@ NSMutableArray *accountList;
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSString *str = [accountList objectAtIndex:indexPath.row];
char accPath[2048];
sprintf(accPath, "%s/Documents/.pojavlauncher/accounts/%s.json", getenv("HOME"), [str UTF8String]);
sprintf(accPath, "%s/accounts/%s.json", getenv("POJAV_HOME"), [str UTF8String]);
remove(accPath);
[accountList removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
+22 -34
View File
@@ -1,3 +1,4 @@
#import "LauncherPreferences.h"
#import "SurfaceViewController.h"
#import "egl_bridge.h"
#import "ios_uikit_bridge.h"
@@ -94,7 +95,7 @@ int notchOffset;
[touchView addGestureRecognizer:tapGesture];
UILongPressGestureRecognizer *longpressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(surfaceOnLongpress:)];
longpressGesture.minimumPressDuration = 0.4;
longpressGesture.minimumPressDuration = ((NSNumber *)getPreference(@"time_longPressTrigger")).floatValue / 1000;
[touchView addGestureRecognizer:longpressGesture];
[self.view addSubview:touchView];
@@ -111,9 +112,10 @@ int notchOffset;
[touchView addGestureRecognizer:mouseWheelGesture];
}
CGFloat rectBtnWidth = 80.0;
CGFloat rectBtnHeight = 30.0;
CGFloat squareBtnSize = 50.0;
CGFloat buttonScale = ((NSNumber *) getPreference(@"button_scale")).floatValue / 100.0;
CGFloat rectBtnWidth = 80.0 * buttonScale;
CGFloat rectBtnHeight = 30.0 * buttonScale;
CGFloat squareBtnSize = 50.0 * buttonScale;
#ifndef DEBUG_VISIBLE_TEXT_FIELD
inputView = [[UITextField alloc] initWithFrame:CGRectMake(5 * 3 + rectBtnWidth * 2, 5, rectBtnWidth, rectBtnHeight)];
@@ -136,30 +138,16 @@ int notchOffset;
// Temporary fallback controls
BOOL cc_fallback = YES;
char controlFilePath[2048];
sprintf(controlFilePath, "%s/default.json", getenv("POJAV_PATH_CONTROL"));
FILE *cc_file = fopen(controlFilePath, "r");
// 100kb (might not safe)
char cc_data[102400];
long cc_size;
if (cc_file) {
fseek(cc_file, 0L, SEEK_END);
cc_size = ftell(cc_file);
rewind(cc_file);
}
NSString *controlFilePath = [NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), (NSString *)getPreference(@"default_ctrl")];
NSError *cc_error;
if (cc_size > 102400) {
NSLog(@"Error: control data is too big (over 100kb).");
fclose(cc_file);
} else if (!cc_file || !fread(cc_data, cc_size, 1, cc_file)) {
NSLog(@"Error: could not read \"default.json\", falling back to default control, error: %s", strerror(errno));
fclose(cc_file);
NSString *cc_data = [NSString stringWithContentsOfFile:controlFilePath encoding:NSUTF8StringEncoding error:&cc_error];
if (cc_error != nil) {
NSLog(@"Error: could not read \"%@\", falling back to default control, error: %@", controlFilePath, cc_error.localizedDescription);
} else {
fclose(cc_file);
NSData* cc_objc_data = [@(cc_data) dataUsingEncoding:NSUTF8StringEncoding];
NSData* cc_objc_data = [cc_data dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *cc_dictionary = [NSJSONSerialization JSONObjectWithData:cc_objc_data options:kNilOptions error:&cc_error];
if (cc_error != nil) {
showDialog(self, @"Error parsing JSON", cc_error.localizedDescription);
@@ -180,11 +168,11 @@ int notchOffset;
}
if (cc_fallback == YES) {
ADD_BUTTON(@"GUI", SPECIALBTN_TOGGLECTRL, CGRectMake(5, height - 5 - 50, squareBtnSize, squareBtnSize), NO);
ADD_BUTTON(@"GUI", SPECIALBTN_TOGGLECTRL, CGRectMake(5, height - 5 - squareBtnSize, squareBtnSize, squareBtnSize), NO);
ADD_BUTTON(@"Keyboard", SPECIALBTN_KEYBOARD, CGRectMake(5 * 3 + rectBtnWidth * 2, 5, rectBtnWidth, rectBtnHeight), YES);
ADD_BUTTON(@"Pri", SPECIALBTN_MOUSEPRI, CGRectMake(5, height - 5 * 3 - 50 * 3, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Sec", SPECIALBTN_MOUSESEC, CGRectMake(5 * 3 + 50 * 2, height - 5 * 3 - 50 * 3, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Pri", SPECIALBTN_MOUSEPRI, CGRectMake(5, height - 5 * 3 - squareBtnSize * 3, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Sec", SPECIALBTN_MOUSESEC, CGRectMake(5 * 3 + squareBtnSize * 2, height - 5 * 3 - squareBtnSize * 3, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Debug", GLFW_KEY_F3, CGRectMake(5, 5, rectBtnWidth, rectBtnHeight), YES);
ADD_BUTTON(@"Chat", GLFW_KEY_T, CGRectMake(5 * 2 + rectBtnWidth, 5, rectBtnWidth, rectBtnHeight), YES);
@@ -193,14 +181,14 @@ int notchOffset;
ADD_BUTTON(@"Offhand", GLFW_KEY_F, CGRectMake(5 * 6 + rectBtnWidth * 5, 5, rectBtnWidth, rectBtnHeight), YES);
ADD_BUTTON(@"3rd", GLFW_KEY_F5, CGRectMake(5, 5 * 2 + rectBtnHeight, rectBtnWidth, rectBtnHeight), YES);
ADD_BUTTON(@"▲", GLFW_KEY_W, CGRectMake(5 * 2 + 50, height - 5 * 3 - 50 * 3, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"◀", GLFW_KEY_A, CGRectMake(5, height - 5 * 2 - 50 * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"▼", GLFW_KEY_S, CGRectMake(5 * 2 + 50, height - 5 - 50, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"▶", GLFW_KEY_D, CGRectMake(5 * 3 + 50 * 2, height - 5 * 2 - 50 * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"◇", GLFW_KEY_LEFT_SHIFT, CGRectMake(5 * 2 + 50, height - 5 * 2 - 50 * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Inv", GLFW_KEY_E, CGRectMake(5 * 3 + 50 * 2, height - 5 - 50, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"▲", GLFW_KEY_W, CGRectMake(5 * 2 + squareBtnSize, height - 5 * 3 - squareBtnSize * 3, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"◀", GLFW_KEY_A, CGRectMake(5, height - 5 * 2 - squareBtnSize * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"▼", GLFW_KEY_S, CGRectMake(5 * 2 + squareBtnSize, height - 5 - squareBtnSize, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"▶", GLFW_KEY_D, CGRectMake(5 * 3 + squareBtnSize * 2, height - 5 * 2 - squareBtnSize * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"◇", GLFW_KEY_LEFT_SHIFT, CGRectMake(5 * 2 + squareBtnSize, height - 5 * 2 - squareBtnSize * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Inv", GLFW_KEY_E, CGRectMake(5 * 3 + squareBtnSize * 2, height - 5 - squareBtnSize, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"⬛", GLFW_KEY_SPACE, CGRectMake(width - 5 * 2 - 50 * 2, height - 5 * 2 - 50 * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"⬛", GLFW_KEY_SPACE, CGRectMake(width - 5 * 2 - squareBtnSize * 2, height - 5 * 2 - squareBtnSize * 2, squareBtnSize, squareBtnSize), YES);
ADD_BUTTON(@"Esc", GLFW_KEY_ESCAPE, CGRectMake(width - 5 - rectBtnWidth, height - 5 - rectBtnHeight, rectBtnWidth, rectBtnHeight), YES);
-14
View File
@@ -1,14 +0,0 @@
//
// main.m
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#include "JavaLauncher.h"
int launchUI(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
+9 -4
View File
@@ -9,14 +9,16 @@
* TODO:
* - Implements glfwSetCursorPos() to handle grab camera pos correctly.
*/
#include "jni.h"
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#include <assert.h>
#include <stdlib.h>
#include "jni.h"
#include "glfw_keycodes.h"
#include "ios_uikit_bridge.h"
#include "log.h"
#include "utils.h"
@@ -264,7 +266,10 @@ JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_uikit_UIKit_runOnUIThread(JNIEnv
JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_uikit_UIKit_launchUI(JNIEnv* env, jclass clazz, jobjectArray args) {
int argc = (*env)->GetArrayLength(env, args);
char **argv = convert_to_char_array(env, args);
return launchUI(argc, argv);
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeAttachThreadToOther(JNIEnv* env, jclass clazz, jboolean isAndroid, jboolean isUseStackQueueBool) {
+1 -1
View File
@@ -134,7 +134,7 @@ void UIKit_launchMinecraftSurfaceVC() {
if (@available(iOS 13.0, *)) {
rootController = UIApplication.sharedApplication.windows.lastObject.rootViewController;
} else {
rootController =(UIViewController*) [[(AppDelegate*) [[UIApplication sharedApplication]delegate] window] rootViewController];
rootController = (UIViewController*) [[(AppDelegate*) [[UIApplication sharedApplication]delegate] window] rootViewController];
}
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MinecraftSurface" bundle:nil];
+4 -3
View File
@@ -61,15 +61,16 @@ PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way w
@genericrandom64
## Third party components and their licenses
- [Apache Commons](https://commons.apache.org): [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt).
- [Caciocavallo](https://github.com/PojavLauncherTeam/caciocavallo): [GNU GPLv2 License](https://github.com/PojavLauncherTeam/caciocavallo/blob/master/LICENSE).
- [jsr305](https://code.google.com/p/jsr-305): [3-Clause BSD License](http://opensource.org/licenses/BSD-3-Clause).
- [org.json](https://github.com/stleary/JSON-java): [The JSON License](https://www.json.org/license.html).
- [Boardwalk](https://github.com/zhuowei/Boardwalk) (JVM Launcher): [Apache License 2.0](https://github.com/zhuowei/Boardwalk/blob/master/LICENSE)
- [Boardwalk](https://github.com/zhuowei/Boardwalk): [Apache 2.0 License](https://github.com/zhuowei/Boardwalk/blob/master/LICENSE)
- [GL4ES](https://github.com/ptitSeb/gl4es) by @lunixbochs @ptitSeb: [MIT License](https://github.com/ptitSeb/gl4es/blob/master/LICENSE).
- [MetalANGLE](https://github.com/kakashidinho/metalangle) by @kakashidinho and ANGLE team: [BSD License 2.0](https://github.com/kakashidinho/metalangle/blob/master/LICENSE).
- [MetalANGLE](https://github.com/kakashidinho/metalangle) by @kakashidinho and ANGLE team: [BSD 2.0 License](https://github.com/kakashidinho/metalangle/blob/master/LICENSE).
- [OpenJDK 16](https://www.ios-repo-updates.com/repository/procursus/package/openjdk-16-jre) ported to iOS by @Diatrus: [GNU GPLv2 License](https://openjdk.java.net/legal/gplv2+ce.html).
- [LWJGL3](https://github.com/PojavLauncherTeam/lwjgl3): [BSD-3 License](https://github.com/LWJGL/lwjgl3/blob/master/LICENSE.md).
- [LWJGLX](https://github.com/PojavLauncherTeam/lwjglx) (LWJGL2 API compatibility layer for LWJGL3): unknown license.
- [DBNumberedSlider](https://github.com/immago/DBNumberedSlider): [Apache 2.0 License](https://github.com/immago/DBNumberedSlider/blob/master/LICENSE)
<!-- Ava was here -->