Files
PojavLauncher_iOS/Natives/JavaLauncher.m
T
64f7e82c1e Merge main into backend-virgl (#316)
* Fix Duy's deploy and install stuffs

* Fix Makefile error and move external_include to external/zink

* Bug fix: version ordering when types are disabled

This commit fixes #293

* Update README.md

* Add option to disable symlink to /var/mobile/Documents/.pojavlauncher (off by default)

* Reset preferences option, switch to POJAV_HOME

* Update bug_report.yml

Update pojavlauncher directory location

* Mitigation for the Apache Log4j RCE in 1.8.x-1.18

* Experimental things

* Multitouch handling, allows one of these actions below to work with
moving camera at the same time.
- Switching hotbar slot; might not work properly
- Destroying block (left mouse button) with another finger
long-pressed (without pressing the PRI button)
- Right mouse trigger with another finger tapped onto the screen
(without pressing the SEC button); not working properly yet
* Sub-pixel cursor support; not yet checked

* Completely fix Log4J RCE (1.7-1.16.5) (not yet tested)

TODO: checker with SHA1

* Log4J RCE patch config: disable XML format output

This applies for Minecraft 1.12+
Disable XML formatting for now until we have a log viewer.

* Create newsfeed.html

* Update newsfeed.html

* Delete newsfeed.html

* WIP Demo mode stuff

Sign in with a Microsoft account that doesn't own the game, demo_user will be made. This is very much WIP as my iPhone 7 doesn't feel like launching PojavLauncher.

* New toggle option: Restart before launching game

This option allows the launcher to restart itself before launching the
game, therefore all changes are applied such as JVM Arguments and Java
version. The restart mechanism doesn't always work, so a toggle is
here for now.

* A few UI changes

Disable the Play button until version list finished loading
Disable ability to go back while a version is downloading
Display loading alert while logging in

* Possible fix for broken Mojang login

* Fix a NullPointerException when launching ≤ 1.6.4

* Bug fix: NPE when setting inherited fields

Unable to insert id=null
java.lang.NoSuchFieldException: id
	at java.lang.Class.getDeclaredField(Class.java:2070)
	at net.kdt.pojavlaunch.Tools.insertSafety(Tools.java:544)
	at net.kdt.pojavlaunch.Tools.getVersionInfo(Tools.java:466)
	at net.kdt.pojavlaunch.PLaunchApp.launchMinecraft(PLaunchApp.java:61)
	at
net.kdt.pojavlaunch.uikit.UIKit.callback_SurfaceViewController_launchMi
necraft(UIKit.java:104)
	at net.kdt.pojavlaunch.uikit.UIKit.launchUI(Native Method)
	at net.kdt.pojavlaunch.PLaunchApp.main(PLaunchApp.java:40)

* Keyboard + Mouse input handling; some cleanups
* Keyboard input: KeyboardInput.m
- Requires iOS 13.4. Used pressesBegan and pressesEnded.
- Not all keys are handled, these will be handled later.

* Mouse input
- Requires iOS 13.0 for hovering. Used UIHoverGestureRecognizer.
- Requires iOS 14.0 for L/R mouse buttons and scroll handling. Used GCMouse for now. We will use iOS 13.4(?)'s API later.
- Pointer lock is not yet handled.

These above apply to iPadOS aswell, not sure about tvOS. iPhone users need to disable "Perform Touch Gestures" in the AssistiveTouch Accessibility settings in order to get the pointer hovering to work.

* Cleanups
- Use asprintf instead of sprintf when possible
- CallbackBridge functions: removed unnecessary JNI fields.
- Condition cleanup (managing virtual mouse position).

* Use the old jvm arguments parser back for now

There’s no handling for backslash yet, or ignoring spaces inside delimiters.

* Remove duplicated code

* Support for input cursor movement from keyboard
New class: TrackedTextField. This class keeps track of the pointer in the text field. The hidden text field now has 40 placeholder spaces and the pointer is placed at the middle. When typing, placeholder spaces won't get removed as before. Autocorrect seem to be broken a bit for now.

Additional changes:
- Added missing GLFW functions (array version of other functions)
- Hotbar handling: doubled barWidth and barHeight

Bug fix:
- Touching onto the hotbar breaks the handling of on-screen tap/long-press gestures

* Bug fix: inputStringLength is not set back to 40

This caused a bug that clears the text when pressing backspace after
the keyboard is displayed again.

* Consolidate some code

* Fix undeclared identifier

* Consolidate some more code, fix my dumb mistake

* Added VGPU renderer

Commit:
https://github.com/PojavLauncherTeam/VGPU/commit/9f4ded5934b24c62368d70
1647855c9c9077d903

* Update LauncherPreferencesViewController.m

This line was mistakenly removed

* Various bug fixes
- Input cursor movement seems too fast, attempt to reduce it by setting larger font size in the hidden text field.
- latestlog.txt doesn't log in 1.12+ since Log4j patch. Fixed by adding some config lines.
- Makefile: building is broken when run make from a path with space(s). Fixed by handling spaces with backslashes.
- text2speech is not overridden properly. Fixed by excluding it from download list and adding launcher.jar itself to the classpath.
- XML log output in < 1.12 since Log4j patch. Fixed by using our own configuration file.

Some more changes:
- Commented out a debug line in LWJGLX
- Fix a typo.
- JavaLauncher: use (ObjC)BOOL instead of (std)bool.

* Better click handling

* Finish make ipa

Still requires proper codesigning afterwards, and until I figure out the depends folder you'll need to download a copy of the Azul JDK artifact on our android-openjdk-build-multiarch repository and extract it to depends/jre. Tested and working on my MacBook Pro, although I need to find out why libjsig.dylib is defined twice (this issue doesn't hinder the build though, install_name_tool just doesn't apply changes).

* Added readable MSA errors

* Merge unjailbroken changes with main (#313)

* fix that lol

* IPABuilder moment

* typo moment

* Hooking changes
Now hook only dladdr and realpath, JRE works now. However, need to obtain libffi.

* Sole more changes

Add RPATH to libraries
Hook dlopen since loading libawt_headless somehow point to Frameworks
directory.

* Update development.yml

* Update development.yml

Co-authored-by: Duy Tran Khanh <[email protected]>
Co-authored-by: Duy Tran Khanh <[email protected]>

* Fix issue with text alignment

* Makefile: multi-jobs building native code

* Bump to Xcode 13.2.1

* Bump to Xcode 13.2.1 pt 2

* use gnproc and nproc (for procursus on macos)

on the road development is bumpy

* oops

* [Custom controls] Added color picker for iOS < 14

Might aswell add an option to optionally use this instead of the system
color picker on iOS 14+. Used library: Alderis

Other changes
- [Custom controls] The editor is now fullscreen due to the
presentation of the color picker.
- Fixes scroll wheel input is always int

* I’m too tired of getting dpkg exits, so it’s here

* Fix broken share log

* Bug fix: Fabric 1.17+ crash at startup(fixes #304)

Microsoft account now set accountType to msa.
Minor change in custom control view controller.

* Add Arc capes

* Minor bug fix for Arc capes switch

* Change how the login progress is displayed

Login progress now displays on the title bar instead of a dialog. This
will prevent infinite loading in case a connection error occurs.
Closes #315

* Bug fix: Arc DNS injector breaks on Java 16+

This is caused by a missing function in our class loader.

Error:
System class loader does not define the
appendToClassPathForInstrumentation method
Unable to add
/Applications/PojavLauncher.app/libs/arc_dns_injector.jar to system
class path - the system class loader does not define the
appendToClassPathForInstrumentation method or the method failed
FATAL ERROR in native method: processing of -javaagent failed,
appending to system class path failed

* Why did I add set -e

* Add changelog for 2.1 release

* FAQ changes

* Workflow changes and typo fix

* Workflow changes part 2

* Fixes swipeable button state handling

* Update informational.yml

* Add A7 warning

* Remove codesign from Alderis + thin lib

* Only load Alderis.framework when needed

* CC editor: view controller now follow bounds(#326)

* Update README.md (#324)

* Update LauncherPreferencesViewController.m

Co-authored-by: Duy Tran Khanh <[email protected]>
Co-authored-by: Duy Tran Khanh <[email protected]>
Co-authored-by: Silly Sock <[email protected]>
2022-02-14 09:13:58 -05:00

737 lines
28 KiB
Objective-C

#include <assert.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <libgen.h>
#include <pthread.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include "jni.h"
#include "log.h"
#include "utils.h"
#include "JavaLauncher.h"
#include "external/fishhook/fishhook.h"
#import "customcontrols/CustomControlsUtils.h"
#import "LauncherPreferences.h"
// PojavLancher: fixme: are these wrong?
#define FULL_VERSION "1.8.0-internal"
#define DOT_VERSION "1.8"
#if CONFIG_RELEASE == 1
# define CONFIG_TYPE "release"
#else
# define CONFIG_TYPE "debug"
#endif
#ifndef CONFIG_COMMIT
# define CONFIG_COMMIT unspecified
#endif
static char java_libs_path[2048];
static char args_path[2048];
static char env_path[2048];
static char log_path[2048];
extern char **environ;
static const char* const_progname = "java";
static const char* const_launcher = "openjdk";
static const char** const_jargs = NULL;
static const char** const_appclasspath = NULL;
static const jboolean const_javaw = JNI_FALSE;
static const jboolean const_cpwildcard = JNI_TRUE;
static const jint const_ergo_class = 0; // DEFAULT_POLICY
typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */
int jargc, const char** jargv, /* java args */
int appclassc, const char** appclassv, /* app classpath */
const char* fullversion, /* full version defined */
const char* dotversion, /* dot version defined */
const char* pname, /* program name */
const char* lname, /* launcher name */
jboolean javaargs, /* JAVA_ARGS */
jboolean cpwildcard, /* classpath wildcard*/
jboolean javaw, /* windows-only javaw */
jint ergo /* ergonomics class policy */
);
int main(int argc, char * argv[]);
static int (*orig_dladdr)(const void* addr, Dl_info* info);
static void* (*orig_dlopen)(const char* path, int mode);
//static void* (*orig_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
static char* (*orig_realpath)(const char *restrict path, char *restrict resolved_path);
//static void (*orig_sys_icache_invalidate)(void *start, size_t len);
static int margc = 0;
static char* margv[1000];
static int pfd[2];
static int log_fd;
static pthread_t logger;
static BOOL filteredSessionID;
const char *javaHome;
const char *renderer;
const char *allocmem;
const char *multidir;
char *homeDir;
NSString *javaHome_pre;
NSString *renderer_pre;
NSString *allocmem_pre;
NSString *multidir_pre;
int hooked_dladdr(const void* addr, Dl_info* info) {
//NSLog(@"hook dladdr(%p, %p)", addr, info);
int retVal = orig_dladdr(addr, info);
if (addr == main) {
//NSLog(@"hooked dladdr");
info->dli_fname = getenv("JAVA_EXT_EXECNAME");
} else if (retVal != 0) {
//NSLog(@"hooked dladdr");
char *libname = basename((char *)info->dli_fname);
char src[2048], dst[2048];
sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH"));
if (0 == strncmp(info->dli_fname, src, strlen(src))) {
if (0 == strncmp(libname, "libjli.dylib", 12)) {
info->dli_fname = getenv("INTERNAL_JLI_PATH");
} else if (0 == strncmp(libname, "libjvm.dylib", 12)) {
sprintf((char *)dst, "%s/lib/server/libjvm.dylib", getenv("JAVA_HOME"));
info->dli_fname = (char *)dst;
}
}
}
//if (retVal) NSLog(@"dli_fname=%s", info->dli_fname);
return retVal;
}
void* hooked_dlopen(const char* path, int mode) {
void *handle = orig_dlopen(path, mode);
if (handle) {
return handle;
}
char src[2048], dst[2048];
sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH"));
//NSLog(@"path=%s, src=%s, length=%lu, compare=%d", path, src, strlen(src), strncmp(path, src, strlen(src)));
if (!strncmp(path, src, strlen(src))) {
//NSLog(@"hooked dlopen %s", path);
char *libname = basename((char *)path);
sprintf((char *)dst, "%s/%s.framework/%s", src, libname, libname);
handle = orig_dlopen(dst, mode);
if (handle) {
dlerror(); // clear error
}
}
return handle;
}
/*
void *hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) {
NSLog(@"mmap(%p, %ld, %d, %d, %d, %lld)", addr, len, prot, flags, fd, offset);
if (flags & MAP_JIT) {
NSLog(@"'-> Found JIT mmap");
//flags &= ~MAP_JIT;
}
// raise(SIGINT);
return orig_mmap(addr, len, prot, flags, fd, offset);
}
*/
char *hooked_realpath(const char *restrict path, char *restrict resolved_path) {
//NSLog(@"hook realpath %s", path);
if (0 == strncmp(path, javaHome, strlen(javaHome))) {
strcpy(resolved_path, path);
return resolved_path;
} else {
return orig_realpath(path, resolved_path);
}
}
/*
void hooked_sys_icache_invalidate(void *start, size_t len) {
// mprotect(start, 16384, PROT_EXEC | PROT_READ);
// NSLog(@"mprotect errno %d", errno);
orig_sys_icache_invalidate(start, len);
}
*/
static void *logger_thread() {
ssize_t rsize;
char buf[2048];
while((rsize = read(pfd[0], buf, sizeof(buf)-1)) > 0) {
// Filter out Session ID here
int index;
if (!filteredSessionID) {
char *sessionStr = strstr(buf, "(Session ID is ");
if (sessionStr) {
char *censorStr = "(Session ID is <censored>)\n\0";
strcpy(sessionStr, censorStr);
rsize = strlen(buf);
filteredSessionID = true;
}
}
write(log_fd, buf, rsize);
}
close(log_fd);
return NULL;
}
void init_hookFunctions() {
// if (!started && strncmp(argv[0], "/Applications", 13))
// Jailed only: hook some functions for symlinked JRE home dir
int retval = rebind_symbols((struct rebinding[3]){
{"dladdr", hooked_dladdr, (void *)&orig_dladdr},
{"dlopen", hooked_dlopen, (void *)&orig_dlopen},
//{"realpath", hooked_realpath, (void *)&orig_realpath},
{"realpath$DARWIN_EXTSN", hooked_realpath, (void *)&orig_realpath}
//{"mmap", hooked_mmap, (void *)&orig_mmap},
//{"sys_icache_invalidate", hooked_sys_icache_invalidate, (void *)&orig_sys_icache_invalidate}
}, 3);
NSLog(@"hook retval = %d", retval);
}
void init_loadCustomEnv() {
FILE *envFile = fopen(env_path, "r");
debug("[Pre-init] Reading custom environment variables (custom_env.txt), opened=%d\n", envFile != NULL);
if (envFile) {
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, envFile)) != -1) {
if (line[0] == '#' || line[0] == '\n') continue;
if (line[read-1] == '\n') {
line[read-1] = '\0';
}
if (strchr(line, '=') != NULL) {
debug("[Pre-init] Added custom env: %s", line);
setenv(strtok(line, "="), strtok(NULL, "="), 1);
} else {
debug("[Pre-init] Warning: skipped empty value custom env: %s", line);
}
}
fclose(envFile);
}
}
void init_loadCustomJvmFlags() {
NSString *jvmargs = getPreference(@"java_args");
BOOL isFirstArg = YES;
for (NSString *jvmarg in [jvmargs componentsSeparatedByString:@" -"]) {
if ([jvmarg length] == 0) continue;
//margv[margc] = (char *) [jvmarg UTF8String];
if (isFirstArg) {
isFirstArg = NO;
margv[margc] = (char *) [jvmarg UTF8String];
} else {
margv[margc] = (char *) [[@"-" stringByAppendingString:jvmarg] UTF8String];
}
NSLog(@"[Pre-init] Added custom JVM flag: %s", margv[margc]);
++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];
}
}
void init_logDeviceAndVer (char *argument) {
struct utsname systemInfo;
uname(&systemInfo);
// Hardware + software
const char *deviceHardware = systemInfo.machine;
const char *deviceSoftware = [[[UIDevice currentDevice] systemVersion] cStringUsingEncoding:NSUTF8StringEncoding];
// Jailbreak
const char *jbStrap;
if (strncmp(argument, "/Applications", 13) == 0) {
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/.procursus_strapped"]) {
jbStrap = "Procursus";
} else {
jbStrap = "Other";
}
debug("[Pre-Init] %s with iOS %s (%s)", deviceHardware, deviceSoftware, jbStrap);
} else {
debug("[Pre-Init] %s with iOS %s", deviceHardware, deviceSoftware);
}
// PojavLauncher version
debug("[Pre-Init] PojavLauncher version: %s - %s", CONFIG_TYPE, CONFIG_COMMIT);
setenv("POJAV_DETECTEDHW", deviceHardware, 1);
setenv("POJAV_DETECTEDSW", deviceSoftware, 1);
if (strncmp(argument, "/Applications", 13) == 0) {
setenv("POJAV_DETECTEDJB", jbStrap, 1);
}
}
void init_redirectStdio(char* homeDir) {
debug("[Pre-init] Staring logging STDIO as jrelog:V\n");
// Redirect stdio to latestlog.txt
char newname[2048];
sprintf(newname, "%s/latestlog.old.txt", homeDir);
rename(log_path, newname);
FILE* logFile = fopen(log_path, "w");
if (!logFile) {
debug("[Pre-init] Error: failed to open %s: %s", log_path, strerror(errno));
assert(0 && "Failed to open latestlog.txt. Check oslog for more details.");
}
log_fd = fileno(logFile);
setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered
setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered
/* create the pipe and redirect stdout and stderr */
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
/* spawn the logging thread */
if(pthread_create(&logger, 0, logger_thread, 0) == -1) {
char *fail_str = "Failed to start logging!";
write(log_fd, fail_str, strlen(fail_str));
close(log_fd);
}
pthread_detach(logger);
}
void environmentFailsafes(char *argv[]) {
if (strncmp(argv[0], "/Applications", 13) == 0) {
if (0 == access("/usr/lib/jvm/java-8-openjdk/", F_OK)) {
javaHome_pre = @"/usr/lib/jvm/java-8-openjdk";
} else if (0 == access("/usr/lib/jvm/java-16-openjdk/", F_OK)) {
debug("[Pre-init] Java 8 wasn't found on your device. Install Java 8 for more compatibility and the mod installer.");
javaHome_pre = @"/usr/lib/jvm/java-16-openjdk";
} else if (0 == access("/usr/lib/jvm/java-17-openjdk/", F_OK)) {
debug("[Pre-init] Java 8 wasn't found on your device. Install Java 8 for more compatibility and the mod installer.");
javaHome_pre = @"/usr/lib/jvm/java-17-openjdk";
} else {
debug("[Pre-init] FATAL ERROR: Java wasn't found on your device, PojavLauncher cannot continue, aborting.");
abort();
}
javaHome = [javaHome_pre cStringUsingEncoding:NSUTF8StringEncoding];
setPreference(@"java_home", javaHome_pre);
} else {
asprintf((char **)&javaHome, "%s/jre", homeDir);
}
}
int launchJVM(int argc, char *argv[]) {
if (0 != [[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher"] && 0 == [[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher/migration_complete"]) {
NSString *newDir = @"/usr/share/pojavlauncher";
if([[[UIDevice currentDevice] systemVersion] containsString:@"15."]) {
newDir = @"/private/preboot/procursus/usr/share/pojavlauncher";
}
NSString *oldDir = @"/var/mobile/Documents/.pojavlauncher";
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *files = [fm contentsOfDirectoryAtPath:oldDir error:nil];
for (NSString *file in files) {
[fm moveItemAtPath:[oldDir stringByAppendingPathComponent:file] toPath:[newDir stringByAppendingPathComponent:file] error:nil];
}
[fm removeItemAtPath:oldDir error:nil];
symlink([newDir cStringUsingEncoding:NSUTF8StringEncoding], [oldDir cStringUsingEncoding:NSUTF8StringEncoding]);
FILE* file_ptr = fopen("/var/mobile/Documents/.pojavlauncher/migration_complete", "w");
fprintf(file_ptr, "#README - The PojavLauncher data directory is now %s. All of your existing data has been moved to the new location.", [newDir cStringUsingEncoding:NSUTF8StringEncoding]);
fclose(file_ptr);
}
if (!started) {
setenv("EXEC_PATH", argv[0], 1);
setenv("BUNDLE_PATH", dirname(argv[0]), 1);
// Are we running on a jailbroken environment?
if (strncmp(argv[0], "/Applications", 13) == 0) {
setenv("HOME", "/usr/share", 1);
setenv("OLD_POJAV_HOME", "/var/mobile/Documents/.pojavlauncher", 1);
homeDir = "/usr/share/pojavlauncher";
} else {
char pojavHome[2048];
sprintf(pojavHome, "%s/Documents", getenv("HOME"));
homeDir = (char *) pojavHome;
init_hookFunctions();
}
setenv("POJAV_HOME", homeDir, 1);
} else {
homeDir = getenv("POJAV_HOME");
}
init_loadCustomEnv();
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);
if (!started) {
init_redirectStdio(homeDir);
}
init_logDeviceAndVer(argv[0]);
debug("[Pre-init] Beginning JVM launch\n");
char javaAwtPath[4096];
// I accidentally patched a bit wrong, the value should be a path containing libawt_xawt.dylib, but here is libawt.dylib path (no need to exist)
sprintf(javaAwtPath, "%s/Frameworks/libawt.dylib", getenv("BUNDLE_PATH"));
setenv("JAVA_AWT_PATH", javaAwtPath, 1);
// 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);
// Disable overloaded functions hack for Minecraft 1.17+
setenv("LIBGL_NOINTOVLHACK", "1", 1);
// Override OpenGL version to 4.1 for Zink
setenv("MESA_GL_VERSION_OVERRIDE", "4.1", 1);
javaHome_pre = getPreference(@"java_home");
javaHome = [javaHome_pre cStringUsingEncoding:NSUTF8StringEncoding];
if ([javaHome_pre length] == 0) {
environmentFailsafes(argv);
debug("[Pre-init] JAVA_HOME environment variable was not set. Defaulting to %s for future use.\n", javaHome);
} else {
if (0 == [[NSFileManager defaultManager] fileExistsAtPath:javaHome_pre]) {
debug("[Pre-Init] Failed to locate %s. Restoring default value for JAVA_HOME.", javaHome);
environmentFailsafes(argv);
} else {
debug("[Pre-Init] Restored preference: JAVA_HOME is set to %s\n", javaHome);
}
}
setenv("JAVA_HOME", javaHome, 1);
if (!started && strncmp(argv[0], "/Applications", 13)) {
char src[2048], dst[2048];
// Symlink frameworks -> dylibs on jailed environment
mkdir(javaHome, 755);
// Symlink the skeleton part of JRE
sprintf((char *)src, "%s/jre/man", getenv("BUNDLE_PATH"));
sprintf((char *)dst, "%s/man", javaHome);
symlink(src, dst);
sprintf((char *)src, "%s/jre/lib", getenv("BUNDLE_PATH"));
sprintf((char *)dst, "%s/lib", javaHome);
mkdir(dst, 755);
DIR *d;
struct dirent *dir;
d = opendir(src);
assert(d);
int i = 0;
while ((dir = readdir(d)) != NULL) {
// Skip "." and ".."
if (i < 2) {
i++;
continue;
} else if (!strncmp(dir->d_name, "jli", 3)) {
sprintf((char *)dst, "%s/lib/jli", javaHome);
mkdir(dst, 755);
// libjli.dylib
sprintf((char *)src, "%s/Frameworks/libjli.dylib.framework/libjli.dylib", getenv("BUNDLE_PATH"));
sprintf((char *)dst, "%s/lib/jli/libjli.dylib", javaHome);
symlink(src, dst);
} else if (!strncmp(dir->d_name, "server", 6)) {
sprintf((char *)dst, "%s/lib/server", javaHome);
mkdir(dst, 755);
// libjsig.dylib
sprintf((char *)src, "%s/Frameworks/libjsig.dylib.framework/libjsig.dylib", getenv("BUNDLE_PATH"));
sprintf((char *)dst, "%s/lib/server/libjsig.dylib", javaHome);
symlink(src, dst);
// libjvm.dylib
sprintf((char *)src, "%s/Frameworks/libjvm.dylib.framework/libjvm.dylib", getenv("BUNDLE_PATH"));
sprintf((char *)dst, "%s/lib/server/libjvm.dylib", javaHome);
symlink(src, dst);
// Xusage.txt
sprintf((char *)src, "%s/jre/lib/server/Xusage.txt", getenv("BUNDLE_PATH"));
sprintf((char *)dst, "%s/lib/server/Xusage.txt", javaHome);
symlink(src, dst);
} else {
sprintf((char *)src, "%s/jre/lib/%s", getenv("BUNDLE_PATH"), dir->d_name);
sprintf((char *)dst, "%s/lib/%s", javaHome, dir->d_name);
symlink(src, dst);
}
}
closedir(d);
// Symlink dylibs
sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH"));
d = opendir(src);
assert(d);
i = 0;
while ((dir = readdir(d)) != NULL) {
// Skip "." and ".."
if (i < 2) {
i++;
continue;
} else if (!strncmp(dir->d_name, "lib", 3) && strlen(dir->d_name) > 12) {
char *dylibName = strdup(dir->d_name);
dylibName[strlen(dylibName) - 10] = '\0';
sprintf((char *)src, "%s/Frameworks/%s/%s", getenv("BUNDLE_PATH"), dir->d_name, dylibName);
if (!strncmp(dir->d_name, "libjvm.dylib", 12)) {
sprintf((char *)dst, "%s/lib/server/%s", javaHome, dylibName);
} else {
sprintf((char *)dst, "%s/lib/%s", javaHome, dylibName);
}
symlink(src, dst);
dylibName[strlen(dylibName) - 11] = '.';
free(dylibName);
}
}
closedir(d);
}
renderer_pre = getPreference(@"renderer");
renderer = [renderer_pre cStringUsingEncoding:NSUTF8StringEncoding];
if ([renderer_pre length] == 0) {
renderer_pre = @"libgl4es_114.dylib";
setPreference(@"renderer", renderer_pre);
renderer = [renderer_pre cStringUsingEncoding:NSUTF8StringEncoding];
setenv("RENDERER", renderer, 1);
debug("[Pre-init] RENDERER environment variable was not set. Defaulting to %s for future use.\n", renderer);
} else {
debug("[Pre-Init] Restored preference: RENDERER is set to %s\n", renderer);
}
allocmem_pre = [getPreference(@"allocated_memory") stringValue];
allocmem = [allocmem_pre cStringUsingEncoding:NSUTF8StringEncoding];
char *controlPath;
asprintf(&controlPath, "%s/controlmap", homeDir);
mkdir(controlPath, S_IRWXU | S_IRWXG | S_IRWXO);
setenv("POJAV_PATH_CONTROL", controlPath, 1);
free(controlPath);
generateAndSaveDefaultControl();
char classpath[10000];
// "/Applications/PojavLauncher.app/libs/launcher.jar:/Applications/PojavLauncher.app/libs/ExagearApacheCommons.jar:/Applications/PojavLauncher.app/libs/gson-2.8.6.jar:/Applications/PojavLauncher.app/libs/jsr305.jar:/Applications/PojavLauncher.app/libs/lwjgl3-minecraft.jar";
// Generate classpath
DIR *d;
struct dirent *dir;
d = opendir(java_libs_path);
int cplen = -2;
if (d) {
// cplen += sprintf(classpath + cplen, "-Xbootclasspath/a:");
while ((dir = readdir(d)) != NULL) {
if (cplen < 0) {
++cplen;
continue;
}
cplen += sprintf(classpath + cplen, "%s/%s:", java_libs_path, dir->d_name);
}
classpath[cplen-1] = '\0';
closedir(d);
}
debug("[Pre-init] Classpath generated: %s", classpath);
multidir_pre = getPreference(@"game_directory");
multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding];
if ([multidir_pre length] == 0) {
multidir_pre = @"default";
multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding];
setPreference(@"game_directory", multidir_pre);
debug("[Pre-init] MULTI_DIR environment variable was not set. Defaulting to %s for future use.\n", multidir);
} else {
multidir = [multidir_pre cStringUsingEncoding:NSUTF8StringEncoding];
debug("[Pre-init] Restored preference: MULTI_DIR is set to %s\n", multidir);
}
char *multidir_char, *librarySym;
asprintf(&multidir_char, "%s/instances/%s", getenv("POJAV_HOME"), multidir);
asprintf(&librarySym, "%s/Library/Application Support/minecraft", getenv("POJAV_HOME"));
remove(librarySym);
if (0 != access(multidir_char, F_OK)) {
mkdir(multidir_char, 755);
}
symlink(multidir_char, librarySym);
setenv("POJAV_GAME_DIR", librarySym, 1);
if (0 == access("/var/mobile/Documents/minecraft", F_OK)) {
rename("/var/mobile/Documents/minecraft", multidir_char);
debug("[Pre-Init] Migrated old minecraft folder to new location.");
}
if (0 == access("/var/mobile/Documents/Library", F_OK)) {
remove("/var/mobile/Documents/Library");
}
// Check if JVM restarts
if (!started) {
char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax, *arcDNS;
asprintf(&frameworkPath, "-Djava.library.path=%s/Frameworks:%s/Frameworks/libOSMesaOverride.dylib.framework", getenv("BUNDLE_PATH"), getenv("BUNDLE_PATH"));
asprintf(&javaPath, "%s/bin/java", javaHome);
asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH"));
asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR"));
asprintf(&userHome, "-Duser.home=%s", getenv("POJAV_HOME"));
asprintf(&memMin, "-Xms%sM", allocmem);
asprintf(&memMax, "-Xmx%sM", allocmem);
asprintf(&arcDNS, "-javaagent:%s/arc_dns_injector.jar=23.95.137.176", java_libs_path);
NSLog(@"[Pre-init] Java executable path: %s", javaPath);
setenv("JAVA_EXT_EXECNAME", javaPath, 1);
chdir(librarySym);
margv[margc++] = javaPath;
margv[margc++] = "-XstartOnFirstThread";
margv[margc++] = "-Djava.system.class.loader=net.kdt.pojavlaunch.PojavClassLoader";
margv[margc++] = memMin;
margv[margc++] = memMax;
margv[margc++] = frameworkPath;
margv[margc++] = jnaLibPath;
margv[margc++] = userDir;
margv[margc++] = userHome;
margv[margc++] = "-Dorg.lwjgl.system.allocator=system";
margv[margc++] = "-Dlog4j2.formatMsgNoLookups=true";
if([getPreference(@"arccapes_enable") boolValue]) {
margv[margc++] = arcDNS;
}
NSString *selectedAccount = getPreference(@"internal_selected_account");
if (selectedAccount != nil) {
margv[margc++] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String;
}
} else {
setenv("RENDERER", renderer, 1);
debug("[Pre-init] RENDERER has been set to %s", getenv("RENDERER"));
}
// Load java
char libjlipath8[2048]; // java 8
char libjlipath16[2048]; // java 16+ (?)
sprintf(libjlipath8, "%s/lib/jli/libjli.dylib", javaHome);
sprintf(libjlipath16, "%s/lib/libjli.dylib", javaHome);
setenv("INTERNAL_JLI_PATH", libjlipath16, 1);
void* libjli = dlopen(libjlipath16, RTLD_LAZY | RTLD_GLOBAL);
if (!libjli) {
debug("[Init] Can't load %s, trying %s", libjlipath16, libjlipath8);
setenv("INTERNAL_JLI_PATH", libjlipath8, 1);
libjli = dlopen(libjlipath8, RTLD_LAZY | RTLD_GLOBAL);
if (!libjli) {
debug("[Init] JLI lib = NULL: %s", dlerror());
return -1;
}
if (!started) {
// Setup Caciocavallo
margv[margc++] = "-Djava.awt.headless=false";
margv[margc++] = "-Dcacio.font.fontmanager=sun.awt.X11FontManager";
margv[margc++] = "-Dcacio.font.fontscaler=sun.font.FreetypeFontScaler";
margv[margc++] = "-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel";
margv[margc++] = "-Dawt.toolkit=net.java.openjdk.cacio.ctc.CTCToolkit";
margv[margc++] = "-Djava.awt.graphicsenv=net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment";
// Generate Caciocavallo bootclasspath
char cacio_libs_path[2048];
char cacio_classpath[8192];
sprintf((char*) cacio_libs_path, "%s/libs_caciocavallo", getenv("BUNDLE_PATH"));
cplen = sprintf(cacio_classpath, "-Xbootclasspath/p");
d = opendir(cacio_libs_path);
int skip = 2;
if (d) {
while ((dir = readdir(d)) != NULL) {
if (skip > 0) {
--skip;
continue;
}
cplen += sprintf(cacio_classpath + cplen, ":%s/%s", cacio_libs_path, dir->d_name);
}
closedir(d);
}
margv[margc++] = cacio_classpath;
}
} else if (!started) {
// Opens to ARC DNS
margv[margc++] = "--add-opens=java.base/java.net=ALL-UNNAMED";
}
if (!started) {
init_loadCustomJvmFlags();
}
debug("[Init] Found JLI lib");
if (!started) {
margv[margc++] = "-cp";
margv[margc++] = classpath;
margv[margc++] = "net.kdt.pojavlaunch.PLaunchApp";
}
JLI_Launch_func *pJLI_Launch =
(JLI_Launch_func *)dlsym(libjli, "JLI_Launch");
if (NULL == pJLI_Launch) {
debug("[Init] JLI_Launch = NULL");
return -2;
}
// Free unused char arrays
free(librarySym);
free(multidir_char);
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;
if (!started) {
started = YES;
}
/* debug:
for (int i = 0; i < targc; i++) {
debug("Arg=%s", targv[i]);
}
*/
return pJLI_Launch(targc, targv,
0, NULL, // sizeof(const_jargs) / sizeof(char *), const_jargs,
0, NULL, // sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
FULL_VERSION,
DOT_VERSION,
const_progname, // (const_progname != NULL) ? const_progname : *margv,
const_launcher, // (const_launcher != NULL) ? const_launcher : *margv,
(const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
const_cpwildcard, const_javaw, const_ergo_class);
}