Welcome to the new Settings UI
What's new? - Settings are now categorized - Re-designed Game Directory manager - Moved help detail to subtitles, toggleable - Some settings are now made accessible ingame - Added Auto Renderer Removed settings: - Restart before launching: not needed anymore, also it would break JIT/debugger.
This commit is contained in:
30 files changed
+1137
-1200
No files matched your search
+4
-1
@@ -1,6 +1,6 @@
|
||||
[submodule "Natives/external/DBNumberedSlider"]
|
||||
path = Natives/external/DBNumberedSlider
|
||||
url = https://github.com/immago/DBNumberedSlider
|
||||
url = https://github.com/khanhduytran0/DBNumberedSlider
|
||||
[submodule "Natives/external/fishhook"]
|
||||
path = Natives/external/fishhook
|
||||
url = https://github.com/khanhduytran0/fishhook
|
||||
@@ -8,3 +8,6 @@
|
||||
[submodule "Natives/external/AFNetworking"]
|
||||
path = Natives/external/AFNetworking
|
||||
url = https://github.com/AFNetworking/AFNetworking
|
||||
[submodule "Natives/external/TOInsetGroupedTableView"]
|
||||
path = Natives/external/TOInsetGroupedTableView
|
||||
url = https://github.com/TimOliver/TOInsetGroupedTableView
|
||||
@@ -74,7 +74,6 @@ public class PojavLauncher {
|
||||
}
|
||||
}
|
||||
|
||||
System.setProperty("org.lwjgl.opengl.libname", System.getenv("POJAV_RENDERER"));
|
||||
System.setProperty("org.lwjgl.vulkan.libname", "libMoltenVK.dylib");
|
||||
|
||||
Tools.mGLFWWindowWidth = Integer.parseInt(size[0]);
|
||||
|
||||
@@ -108,7 +108,9 @@ public final class GL {
|
||||
GL = Library.loadNative(GL.class, "org.lwjgl.opengl", Configuration.OPENGL_LIBRARY_NAME, "libGL.so.1", "libGL.so");
|
||||
break;
|
||||
case MACOSX:
|
||||
String override = Configuration.OPENGL_LIBRARY_NAME.get();
|
||||
// Configuration does not get updated if the value changes, so we have to use System.getProperty()
|
||||
String override = System.getProperty("org.lwjgl.opengl.libname");
|
||||
//Configuration.OPENGL_LIBRARY_NAME.get();
|
||||
GL = override != null
|
||||
? Library.loadNative(GL.class, "org.lwjgl.opengl", override)
|
||||
: MacOSXLibrary.getWithIdentifier("com.apple.opengl");
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface BKSSystemService : NSObject
|
||||
|
||||
- (unsigned int)createClientPort;
|
||||
- (void)openApplication:(NSString *)app options:(id)arg2 withResult:(id)arg3 ;
|
||||
- (void)openURL:(NSURL *)url application:(NSString *)app options:(id)options clientPort:(unsigned int)port withResult:(id)result;
|
||||
|
||||
@end
|
||||
@@ -15,6 +15,7 @@ include_directories(
|
||||
"external/AFNetworking/AFNetworking"
|
||||
"external/AFNetworking/UIKit+AFNetworking"
|
||||
"external/DBNumberedSlider/Classes"
|
||||
"external/TOInsetGroupedTableView/TOInsetGroupedTableView"
|
||||
"external/fishhook"
|
||||
"external/mesa"
|
||||
"external/Apple"
|
||||
@@ -101,6 +102,7 @@ add_executable(PojavLauncher
|
||||
customcontrols/CustomControlsUtils.m
|
||||
|
||||
external/DBNumberedSlider/Classes/DBNumberedSlider.m
|
||||
external/TOInsetGroupedTableView/TOInsetGroupedTableView/TOInsetGroupedTableView.m
|
||||
|
||||
input/ControllerInput.m
|
||||
input/KeyboardInput.m
|
||||
@@ -115,7 +117,8 @@ add_executable(PojavLauncher
|
||||
LauncherFAQViewController.m
|
||||
LauncherMenuViewController.m
|
||||
LauncherPreferences.m
|
||||
LauncherPreferencesViewController.m
|
||||
LauncherPreferencesViewController2.m
|
||||
LauncherPrefGameDirViewController.m
|
||||
LauncherSplitViewController.m
|
||||
LauncherViewController.m
|
||||
LoginViewController.m
|
||||
|
||||
+12
-20
@@ -24,25 +24,16 @@ static char args_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
|
||||
|
||||
static int margc = -1;
|
||||
static char* margv[1000];
|
||||
|
||||
const char *javaHome;
|
||||
const char *renderer;
|
||||
const char *allocmem;
|
||||
const char *multidir;
|
||||
|
||||
char *homeDir;
|
||||
|
||||
NSString *renderer_pre;
|
||||
NSString *renderer;
|
||||
NSString *allocmem_pre;
|
||||
NSString *multidir_pre;
|
||||
|
||||
@@ -138,6 +129,9 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
|
||||
regLog("[JavaLauncher] Beginning JVM launch\n");
|
||||
|
||||
NSString *javaHome_pre = getPreference(@"java_home");
|
||||
if (![javaHome_pre hasPrefix:@"/"]) {
|
||||
javaHome_pre = [NSString stringWithFormat:@"%s/jvm/%@", getenv("POJAV_DETECTEDJB") ? "/usr/lib" : getenv("BUNDLE_PATH"), javaHome_pre];
|
||||
}
|
||||
|
||||
// We handle unset JAVA_HOME right there
|
||||
if (getSelectedJavaVersion() < minVersion) {
|
||||
@@ -149,7 +143,7 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
|
||||
setPreference(@"java_home", javaHome_pre);
|
||||
NSLog(@"[JavaLauncher] JAVA_HOME environment variable was not set. Default to %@ for future use.\n", javaHome_pre);
|
||||
} */ else {
|
||||
if (![NSFileManager.defaultManager fileExistsAtPath:javaHome_pre]) {
|
||||
if (![fm fileExistsAtPath:javaHome_pre]) {
|
||||
javaHome_pre = environmentFailsafes(minVersion);
|
||||
setPreference(@"java_home", javaHome_pre);
|
||||
NSLog(@"[JavaLauncher] Failed to locate %@. Restored default value for JAVA_HOME.", javaHome_pre);
|
||||
@@ -165,17 +159,15 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
|
||||
javaHome = javaHome_pre.UTF8String;
|
||||
setenv("JAVA_HOME", javaHome, 1);
|
||||
|
||||
renderer_pre = getPreference(@"renderer");
|
||||
renderer = renderer_pre.UTF8String;
|
||||
if (renderer_pre.length == 0) {
|
||||
renderer_pre = @"libgl4es_114.dylib";
|
||||
setPreference(@"renderer", renderer_pre);
|
||||
renderer = [renderer_pre cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
regLog("[JavaLauncher] RENDERER environment variable was not set. Defaulting to %s for future use.\n", renderer);
|
||||
renderer = getPreference(@"renderer");
|
||||
if (renderer.length == 0) {
|
||||
renderer = @"auto";
|
||||
setPreference(@"renderer", renderer);
|
||||
NSLog(@"[JavaLauncher] RENDERER environment variable was not set. Defaulting to %@ for future use.\n", renderer);
|
||||
} else {
|
||||
regLog("[JavaLauncher] Restored preference: RENDERER is set to %s\n", renderer);
|
||||
NSLog(@"[JavaLauncher] Restored preference: RENDERER is set to %@\n", renderer);
|
||||
}
|
||||
setenv("POJAV_RENDERER", renderer, 1);
|
||||
setenv("POJAV_RENDERER", renderer.UTF8String, 1);
|
||||
|
||||
allocmem_pre = [getPreference(@"allocated_memory") stringValue];
|
||||
allocmem = [allocmem_pre cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#import "authenticator/BaseAuthenticator.h"
|
||||
#import "AccountListViewController.h"
|
||||
#import "LauncherMenuViewController.h"
|
||||
#import "LauncherPreferencesViewController.h"
|
||||
#import "LauncherPreferencesViewController2.h"
|
||||
#import "LauncherViewController.h"
|
||||
#import "UIButton+AFNetworking.h"
|
||||
#import "UIImageView+AFNetworking.h"
|
||||
@@ -20,10 +20,10 @@
|
||||
// View controllers are put into an array to keep its state
|
||||
self.options = @[
|
||||
[[LauncherViewController alloc] init],
|
||||
[[LauncherPreferencesViewController alloc] init]
|
||||
[[LauncherPreferencesViewController2 alloc] init]
|
||||
];
|
||||
self.options[0].title = @"PojavLauncher";
|
||||
self.options[1].title = @"Preferences";
|
||||
self.options[1].title = NSLocalizedString(@"Settings", nil);
|
||||
//@[@"News", @"Development Console", @"Crash logs"];
|
||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
selected.navigationItem.leftItemsSupplementBackButton = true;
|
||||
}
|
||||
|
||||
// This button is placed temporarily while migrating to the new UI
|
||||
// Put a close button, as iOS does not have a dedicated back button
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"❌" style:UIBarButtonItemStyleDone target:self.splitViewController action:@selector(dismissViewController)];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface LauncherPrefGameDirViewController : UITableViewController
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPrefGameDirViewController.h"
|
||||
#import "TOInsetGroupedTableView.h"
|
||||
#import "ios_uikit_bridge.h"
|
||||
|
||||
@interface LauncherPrefGameDirViewController ()<UITextFieldDelegate>
|
||||
@property NSMutableArray *array;
|
||||
@end
|
||||
|
||||
@implementation LauncherPrefGameDirViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self setTitle:NSLocalizedString(@"preference.title.game_directory", nil)];
|
||||
|
||||
self.array = [[NSMutableArray alloc] init];
|
||||
[self.array addObject:@"default"];
|
||||
|
||||
self.tableView = [[TOInsetGroupedTableView alloc] init];
|
||||
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
|
||||
self.tableView.sectionFooterHeight = 50;
|
||||
|
||||
NSString *path = [NSString stringWithFormat:@"%s/instances", getenv("POJAV_HOME")];
|
||||
|
||||
NSFileManager *fm = NSFileManager.defaultManager;
|
||||
NSArray *files = [fm contentsOfDirectoryAtPath:path error:nil];
|
||||
BOOL isDir;
|
||||
for (NSString *file in files) {
|
||||
[fm fileExistsAtPath:path isDirectory:(&isDir)];
|
||||
if (isDir && ![file isEqualToString:@"default"]) {
|
||||
[self.array addObject:file];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)changeSelectionTo:(NSString *)name {
|
||||
setPreference(@"game_directory", name);
|
||||
NSString *multidirPath = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), name];
|
||||
NSString *lasmPath = [NSString stringWithFormat:@"%s/Library/Application Support/minecraft", getenv("POJAV_HOME")];
|
||||
[NSFileManager.defaultManager removeItemAtPath:lasmPath error:nil];
|
||||
[NSFileManager.defaultManager createSymbolicLinkAtPath:lasmPath withDestinationPath:multidirPath error:nil];
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
return self.array.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITextField *view;
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
|
||||
if (cell == nil) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
|
||||
|
||||
if (indexPath.row == 0) {
|
||||
cell.textLabel.text = self.array[indexPath.row];
|
||||
} else {
|
||||
view = [[UITextField alloc] initWithFrame:CGRectMake(20, 10, (cell.bounds.size.width-40)/2, cell.bounds.size.height-20)];
|
||||
[view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
|
||||
view.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
view.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
view.delegate = self;
|
||||
view.returnKeyType = UIReturnKeyDone;
|
||||
[cell.contentView addSubview:view];
|
||||
}
|
||||
}
|
||||
if (indexPath.row > 0) {
|
||||
view = cell.contentView.subviews.lastObject;
|
||||
view.placeholder = self.array[indexPath.row];
|
||||
view.text = self.array[indexPath.row];
|
||||
}
|
||||
|
||||
if ([getPreference(@"game_directory") isEqualToString:self.array[indexPath.row]]) {
|
||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
} else {
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
}
|
||||
|
||||
// TODO: display size in the detail label
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView
|
||||
viewForFooterInSection:(NSInteger)section
|
||||
{
|
||||
UITextField *view = [[UITextField alloc] init];
|
||||
[view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
|
||||
view.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
view.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
view.delegate = self;
|
||||
view.placeholder = NSLocalizedString(@"preference.multidir.add_directory", nil);
|
||||
view.returnKeyType = UIReturnKeyDone;
|
||||
return view;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[self changeSelectionTo:self.array[indexPath.row]];
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
for (int i = 0; i < self.array.count; i++) {
|
||||
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
|
||||
if (i == indexPath.row) {
|
||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
} else {
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point API_AVAILABLE(ios(13.0))
|
||||
{
|
||||
// You can't delete or rename the default instance, though there will be a reset action (TODO)
|
||||
if (indexPath.row == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIAction *delete = [UIAction actionWithTitle:@"Delete" image:[UIImage systemImageNamed:@"trash"] identifier:@"deleteAction" handler:^(__kindof UIAction * _Nonnull action) {
|
||||
[self actionDeleteAtIndexPath:indexPath];
|
||||
}];
|
||||
delete.attributes = UIMenuElementAttributesDestructive;
|
||||
|
||||
UIAction *rename = [UIAction actionWithTitle:@"Rename" image:[UIImage systemImageNamed:@"pencil"] identifier:@"editAction" handler:^(__kindof UIAction * _Nonnull action) {
|
||||
UITableViewCell *view = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
[view.contentView.subviews.lastObject becomeFirstResponder];
|
||||
}];
|
||||
|
||||
return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu * _Nullable(NSArray<UIMenuElement *> * _Nonnull suggestedActions) {
|
||||
return [UIMenu menuWithTitle:self.array[indexPath.row] children:@[delete, rename]];
|
||||
}];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
[self actionDeleteAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if (indexPath.row == 0) {
|
||||
// TODO: Reset action?
|
||||
return UITableViewCellEditingStyleNone;
|
||||
} else {
|
||||
return UITableViewCellEditingStyleDelete;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)actionDeleteAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *view = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
NSString *title = NSLocalizedString(@"preference.title.confirm", nil);
|
||||
NSString *message = [NSString stringWithFormat:NSLocalizedString(@"preference.title.confirm.delete_game_directory", nil), self.array[indexPath.row]];
|
||||
UIAlertController *confirmAlert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
confirmAlert.popoverPresentationController.sourceView = view;
|
||||
confirmAlert.popoverPresentationController.sourceRect = view.bounds;
|
||||
UIAlertAction *ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
NSString *directory = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), self.array[indexPath.row]];
|
||||
NSError *error;
|
||||
if([NSFileManager.defaultManager removeItemAtPath:directory error:&error]) {
|
||||
if ([getPreference(@"game_directory") isEqualToString:self.array[indexPath.row]]) {
|
||||
[self changeSelectionTo:self.array[0]];
|
||||
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
}
|
||||
[self.array removeObjectAtIndex:indexPath.row];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
} else {
|
||||
showDialog(self, NSLocalizedString(@"Error", nil), error.localizedDescription);
|
||||
}
|
||||
}];
|
||||
UIAlertAction *cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
|
||||
[confirmAlert addAction:cancel];
|
||||
[confirmAlert addAction:ok];
|
||||
[self presentViewController:confirmAlert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark UITextField
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)sender {
|
||||
BOOL isFooterView = sender.superview == self.tableView;
|
||||
if (!sender.hasText || [sender.text isEqualToString:sender.placeholder]) {
|
||||
if (isFooterView) {
|
||||
return;
|
||||
}
|
||||
sender.text = sender.placeholder;
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *error;
|
||||
|
||||
NSString *dest = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), sender.text];
|
||||
if (isFooterView) {
|
||||
[NSFileManager.defaultManager createDirectoryAtPath:dest withIntermediateDirectories:NO attributes:nil error:&error];
|
||||
} else {
|
||||
NSString *source = [NSString stringWithFormat:@"%s/instances/%@", getenv("POJAV_HOME"), sender.placeholder];
|
||||
[NSFileManager.defaultManager moveItemAtPath:source toPath:dest error:&error];
|
||||
}
|
||||
|
||||
if (error == nil) {
|
||||
[self changeSelectionTo:sender.text];
|
||||
if (isFooterView) {
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.array.count inSection:0];
|
||||
[self.array addObject:sender.text];
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
[self.tableView endUpdates];
|
||||
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
|
||||
// Clear text
|
||||
sender.text = @"";
|
||||
} else {
|
||||
int index = [self.array indexOfObject:sender.placeholder];
|
||||
self.array[index] = sender.placeholder = sender.text;
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
|
||||
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
|
||||
}
|
||||
} else {
|
||||
// Restore to the previous name if we encounter an error
|
||||
if (!isFooterView) {
|
||||
sender.text = sender.placeholder;
|
||||
}
|
||||
showDialog(self, NSLocalizedString(@"Error", nil), error.localizedDescription);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
|
||||
[textField invalidateIntrinsicContentSize];
|
||||
CGRect frame = textField.frame;
|
||||
frame.size.width = MAX(50, textField.intrinsicContentSize.width + 10);
|
||||
textField.frame = frame;
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -4,13 +4,14 @@
|
||||
#define JRE16_HOME_JB @"/usr/lib/jvm/java-16-openjdk"
|
||||
#define JRE17_HOME_JB @"/usr/lib/jvm/java-17-openjdk"
|
||||
|
||||
void loadPreferences();
|
||||
void loadPreferences(BOOL reset);
|
||||
id getPreference(NSString* key);
|
||||
NSMutableDictionary* getDictionary(NSString *type);
|
||||
int getJavaVersion(NSString* java);
|
||||
int getSelectedJavaVersion();
|
||||
void setDefaultValueForPref(NSMutableDictionary *dict, NSString* key, id value);
|
||||
void setPreference(NSString* key, id value);
|
||||
void resetWarnings();
|
||||
|
||||
CGRect getDefaultSafeArea();
|
||||
BOOL getEntitlementValue(NSString *key);
|
||||
@@ -78,18 +78,30 @@ void setPreference(NSString* key, id value) {
|
||||
[prefDict writeToFile:prefPath atomically:YES];
|
||||
}
|
||||
|
||||
void loadPreferences() {
|
||||
void fillDefaultWarningDict() {
|
||||
setDefaultValueForPref(warnPrefDict, @"option_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"local_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"mem_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"java_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"demo_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"jb_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"customctrl_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"int_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"auto_ram_warn", @YES);
|
||||
}
|
||||
|
||||
void loadPreferences(BOOL reset) {
|
||||
assert(getenv("POJAV_HOME"));
|
||||
prefPath = [@(getenv("POJAV_HOME"))
|
||||
stringByAppendingPathComponent:@"launcher_preferences.plist"];
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if (![fileManager fileExistsAtPath:prefPath]) {
|
||||
prefDict = [NSMutableDictionary dictionaryWithContentsOfFile:prefPath];
|
||||
if (reset || ![fileManager fileExistsAtPath:prefPath]) {
|
||||
prefDict = [[NSMutableDictionary alloc] init];
|
||||
envPrefDict = [[NSMutableDictionary alloc] init];
|
||||
warnPrefDict = [[NSMutableDictionary alloc] init];
|
||||
} else {
|
||||
prefDict = [NSMutableDictionary dictionaryWithContentsOfFile:prefPath];
|
||||
envPrefDict = prefDict[@"env_vars"];
|
||||
warnPrefDict = prefDict[@"warnings"];
|
||||
}
|
||||
@@ -101,30 +113,23 @@ void loadPreferences() {
|
||||
setDefaultValueForPref(prefDict, @"button_scale", @(100));
|
||||
setDefaultValueForPref(prefDict, @"selected_version", @"1.7.10");
|
||||
setDefaultValueForPref(prefDict, @"selected_version_type", @(0));
|
||||
setDefaultValueForPref(envPrefDict, @"time_longPressTrigger", @(400));
|
||||
setDefaultValueForPref(envPrefDict, @"press_duration", @(400));
|
||||
setDefaultValueForPref(envPrefDict, @"mouse_scale", @(100));
|
||||
setDefaultValueForPref(envPrefDict, @"mouse_speed", @(100));
|
||||
setDefaultValueForPref(envPrefDict, @"default_ctrl", @"default.json");
|
||||
setDefaultValueForPref(envPrefDict, @"game_directory", @"default");
|
||||
setDefaultValueForPref(envPrefDict, @"java_args", @"");
|
||||
setDefaultValueForPref(envPrefDict, @"allocated_memory", [NSNumber numberWithFloat:roundf(([[NSProcessInfo processInfo] physicalMemory] / 1048576) * 0.30)]);
|
||||
setDefaultValueForPref(prefDict, @"restart_before_launch", @NO);
|
||||
setDefaultValueForPref(envPrefDict, @"allocated_memory", [NSNumber numberWithFloat:roundf(([[NSProcessInfo processInfo] physicalMemory] / 1048576) * 0.25)]);
|
||||
setDefaultValueForPref(prefDict, @"debug_logging", CONFIG_TYPE);
|
||||
setDefaultValueForPref(prefDict, @"arccapes_enable", @YES);
|
||||
setDefaultValueForPref(envPrefDict, @"java_home", @"");
|
||||
setDefaultValueForPref(envPrefDict, @"renderer", @"libgl4es_114.dylib");
|
||||
setDefaultValueForPref(warnPrefDict, @"option_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"local_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"mem_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"java_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"demo_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"jb_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"customctrl_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"int_warn", @YES);
|
||||
setDefaultValueForPref(warnPrefDict, @"ram_unjb_warn", @YES);
|
||||
setDefaultValueForPref(envPrefDict, @"renderer", @"auto");
|
||||
fillDefaultWarningDict();
|
||||
setDefaultValueForPref(prefDict, @"a7_allow", @NO);
|
||||
setDefaultValueForPref(prefDict, @"slideable_hotbar", @NO);
|
||||
setDefaultValueForPref(prefDict, @"virtmouse_enable", @NO);
|
||||
setDefaultValueForPref(prefDict, @"check_sha", @YES);
|
||||
setDefaultValueForPref(prefDict, @"ram_unjb_enable", @NO);
|
||||
setDefaultValueForPref(prefDict, @"auto_ram", @(getenv("POJAV_DETECTEDJB") == NULL));
|
||||
|
||||
if (0 != [fileManager fileExistsAtPath:@"/var/mobile/Documents/.pojavlauncher"]) {
|
||||
setDefaultValueForPref(prefDict, @"disable_home_symlink", @NO);
|
||||
@@ -132,7 +137,8 @@ void loadPreferences() {
|
||||
setDefaultValueForPref(prefDict, @"disable_home_symlink", @YES);
|
||||
}
|
||||
|
||||
setDefaultValueForPref(prefDict, @"control_safe_area", NSStringFromCGRect(getDefaultSafeArea()));
|
||||
// Migrate some prefs
|
||||
setPreference(@"java_home", [getPreference(@"java_home") lastPathComponent]);
|
||||
|
||||
prefDict[@"env_vars"] = envPrefDict;
|
||||
prefDict[@"warnings"] = warnPrefDict;
|
||||
@@ -140,6 +146,13 @@ void loadPreferences() {
|
||||
[prefDict writeToFile:prefPath atomically:YES];
|
||||
}
|
||||
|
||||
void resetWarnings() {
|
||||
[warnPrefDict removeAllObjects];
|
||||
fillDefaultWarningDict();
|
||||
prefDict[@"warnings"] = warnPrefDict;
|
||||
[prefDict writeToFile:prefPath atomically:YES];
|
||||
}
|
||||
|
||||
CGRect getDefaultSafeArea() {
|
||||
CGRect defaultSafeArea = UIScreen.mainScreen.bounds;
|
||||
UIEdgeInsets insets = UIApplication.sharedApplication.windows.firstObject.safeAreaInsets;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -5,6 +5,6 @@
|
||||
#define JRE17_NAME_JB @"Java 17"
|
||||
#define JRE8_NAME_SB @"Java 8 (sandbox)"
|
||||
|
||||
@interface LauncherPreferencesViewController : UIViewController <UITextFieldDelegate>
|
||||
@interface LauncherPreferencesViewController2 : UITableViewController<UITextFieldDelegate>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,573 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "DBNumberedSlider.h"
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPreferencesViewController2.h"
|
||||
#import "LauncherPrefGameDirViewController.h"
|
||||
#import "TOInsetGroupedTableView.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
|
||||
|
||||
@interface LauncherPreferencesViewController2()<UIPickerViewDataSource, UIPickerViewDelegate> {}
|
||||
@property NSArray<NSString*>* prefSections;
|
||||
@property NSArray<NSArray<NSDictionary*>*>* prefContents;
|
||||
@property BOOL prefDetailVisible;
|
||||
|
||||
@property CreateView typeButton, typeChildPane, typePickField, typeTextField, typeSlider, typeSwitch;
|
||||
@end
|
||||
|
||||
@implementation LauncherPreferencesViewController2
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self initViewCreation];
|
||||
|
||||
self.prefDetailVisible = self.navigationController == nil;
|
||||
|
||||
self.tableView = [[TOInsetGroupedTableView alloc] init];
|
||||
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
|
||||
self.tableView.sectionHeaderHeight = 50;
|
||||
|
||||
if (self.navigationController == nil) {
|
||||
self.tableView.alpha = 0.9;
|
||||
}
|
||||
|
||||
BOOL(^whenNotInGame)() = ^BOOL(){
|
||||
return self.navigationController != nil;
|
||||
};
|
||||
|
||||
self.prefSections = @[@"general", @"video", @"control", @"java"];
|
||||
|
||||
self.prefContents = @[
|
||||
@[
|
||||
// General settings
|
||||
@{@"key": @"game_directory",
|
||||
@"icon": @"folder",
|
||||
@"type": self.typeChildPane,
|
||||
@"enableCondition": whenNotInGame,
|
||||
@"class": LauncherPrefGameDirViewController.class,
|
||||
},
|
||||
@{@"key": @"home_symlink",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"link",
|
||||
@"type": self.typeSwitch,
|
||||
@"enableCondition": ^BOOL(){
|
||||
return getenv("POJAV_DETECTEDJB") != NULL && whenNotInGame();
|
||||
}
|
||||
},
|
||||
@{@"key": @"check_sha",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"lock.shield",
|
||||
@"type": self.typeSwitch,
|
||||
@"enableCondition": whenNotInGame
|
||||
},
|
||||
@{@"key": @"cosmetica",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"eyeglasses",
|
||||
@"type": self.typeSwitch,
|
||||
@"enableCondition": whenNotInGame
|
||||
},
|
||||
@{@"key": @"debug_logging",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"doc.badge.gearshape",
|
||||
@"type": self.typeSwitch
|
||||
},
|
||||
@{@"key": @"reset_warnings",
|
||||
@"icon": @"exclamationmark.triangle",
|
||||
@"type": self.typeButton,
|
||||
@"enableCondition": whenNotInGame,
|
||||
@"action": ^void(){
|
||||
resetWarnings();
|
||||
}
|
||||
},
|
||||
@{@"key": @"reset_settings",
|
||||
@"icon": @"trash",
|
||||
@"type": self.typeButton,
|
||||
@"enableCondition": whenNotInGame,
|
||||
@"requestReload": @YES,
|
||||
@"showConfirmPrompt": @YES,
|
||||
@"destructive": @YES,
|
||||
@"action": ^void(){
|
||||
loadPreferences(YES);
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
},
|
||||
], @[
|
||||
// Video and renderer settings
|
||||
@{@"key": @"renderer",
|
||||
@"icon": @"cpu",
|
||||
@"type": self.typePickField,
|
||||
@"enableCondition": whenNotInGame,
|
||||
@"pickKeys": @[
|
||||
@"auto",
|
||||
@ RENDERER_NAME_GL4ES,
|
||||
@ RENDERER_NAME_MTL_ANGLE,
|
||||
@ RENDERER_NAME_VK_ZINK
|
||||
],
|
||||
@"pickList": @[
|
||||
NSLocalizedString(@"preference.title.renderer.auto", nil),
|
||||
NSLocalizedString(@"preference.title.renderer.gl4es", nil),
|
||||
NSLocalizedString(@"preference.title.renderer.tinygl4angle", nil),
|
||||
NSLocalizedString(@"preference.title.renderer.zink", nil)
|
||||
]
|
||||
},
|
||||
@{@"key": @"resolution",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"viewfinder",
|
||||
@"type": self.typeSlider,
|
||||
@"min": @(25),
|
||||
@"max": @(150)
|
||||
},
|
||||
], @[
|
||||
// Control settings
|
||||
/*
|
||||
@"disable_gesture": @{
|
||||
@"type": self.typeSwitch
|
||||
},
|
||||
*/
|
||||
@{@"key": @"press_duration",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"timer",
|
||||
@"type": self.typeSlider,
|
||||
@"min": @(100),
|
||||
@"max": @(1000)
|
||||
},
|
||||
@{@"key": @"button_scale",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"aspectratio",
|
||||
@"type": self.typeSlider,
|
||||
@"min": @(50), // 80?
|
||||
@"max": @(500)
|
||||
},
|
||||
@{@"key": @"mouse_scale",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"arrow.up.left.and.arrow.down.right.circle",
|
||||
@"type": self.typeSlider,
|
||||
@"min": @(25),
|
||||
@"max": @(300)
|
||||
},
|
||||
@{@"key": @"mouse_speed",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"arrow.left.and.right",
|
||||
@"type": self.typeSlider,
|
||||
@"min": @(25),
|
||||
@"max": @(300)
|
||||
},
|
||||
@{@"key": @"virtmouse_enable",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"cursorarrow.rays",
|
||||
@"type": self.typeSwitch
|
||||
},
|
||||
@{@"key": @"slideable_hotbar",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"slider.horizontal.below.rectangle",
|
||||
@"type": self.typeSwitch
|
||||
}
|
||||
], @[
|
||||
// Java tweaks
|
||||
@{@"key": @"java_home", // Use Java 17 for Minecraft < 1.17
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"cube",
|
||||
@"type": self.typeSwitch,
|
||||
@"enableCondition": whenNotInGame,
|
||||
// false: 8, true: 17
|
||||
@"customSwitchValue": @[@"java-8-openjdk", @"java-17-openjdk"]
|
||||
},
|
||||
@{@"key": @"java_args",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"slider.vertical.3",
|
||||
@"type": self.typeTextField,
|
||||
@"enableCondition": whenNotInGame
|
||||
},
|
||||
@{@"key": @"auto_ram",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"slider.horizontal.3",
|
||||
@"type": self.typeSwitch,
|
||||
@"enableCondition": ^BOOL(){
|
||||
return getenv("POJAV_DETECTEDJB") == NULL && whenNotInGame();
|
||||
},
|
||||
@"warnCondition": ^BOOL(){
|
||||
return getenv("POJAV_DETECTEDJB") == NULL && whenNotInGame();
|
||||
},
|
||||
@"warnKey": @"auto_ram_warn",
|
||||
@"requestReload": @YES
|
||||
},
|
||||
@{@"key": @"allocated_memory",
|
||||
@"hasDetail": @YES,
|
||||
@"icon": @"memorychip",
|
||||
@"type": self.typeSlider,
|
||||
@"min": @(NSProcessInfo.processInfo.physicalMemory / 1048576 * 0.25),
|
||||
@"max": @(NSProcessInfo.processInfo.physicalMemory / 1048576 * 0.85),
|
||||
@"enableCondition": ^BOOL(){
|
||||
return ![getPreference(@"auto_ram") boolValue] && whenNotInGame();
|
||||
},
|
||||
@"warnCondition": ^BOOL(DBNumberedSlider *view){
|
||||
return view.value >= NSProcessInfo.processInfo.physicalMemory / 1048576 * 0.37;
|
||||
},
|
||||
@"warnKey": @"mem_warn"
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
UIBarButtonItem *helpButton;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
helpButton = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"questionmark.circle"] style:UIBarButtonItemStyleDone target:self action:@selector(toggleDetailVisibility)];
|
||||
} else {
|
||||
helpButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Help", nil) style:UIBarButtonItemStyleDone target:self action:@selector(toggleDetailVisibility)];
|
||||
}
|
||||
self.navigationItem.rightBarButtonItems = @[helpButton];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// Scan for child pane cells and reload them
|
||||
// FIXME: any cheaper operations?
|
||||
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
|
||||
for (int section = 0; section < self.prefContents.count; section++) {
|
||||
for (int row = 0; row < self.prefContents[section].count; row++) {
|
||||
if (self.prefContents[section][row][@"type"] == self.typeChildPane) {
|
||||
[indexPaths addObject:[NSIndexPath indexPathForRow:row inSection:section]];
|
||||
}
|
||||
}
|
||||
}
|
||||
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
- (void)dismissViewController {
|
||||
[self.presentingViewController performSelector:@selector(updatePreferenceChanges)];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)toggleDetailVisibility {
|
||||
self.prefDetailVisible = !self.prefDetailVisible;
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark UITableView
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return self.prefSections.count;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
||||
if (section != 0 || self.navigationController != nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[doneButton setTitle:NSLocalizedString(@"Done", nil) forState:UIControlStateNormal];
|
||||
[doneButton addTarget:self action:@selector(dismissViewController) forControlEvents:UIControlEventTouchUpInside];
|
||||
return doneButton;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
return NSLocalizedString(([NSString stringWithFormat:@"preference.section.%@", self.prefSections[section]]), nil);
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
|
||||
NSString *footer = NSLocalizedStringWithDefaultValue(([NSString stringWithFormat:@"preference.section.footer.%@", self.prefSections[section]]), @"Localizable", NSBundle.mainBundle, @" ", nil);
|
||||
if ([footer isEqualToString:@" "]) {
|
||||
return nil;
|
||||
}
|
||||
return footer;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.prefContents[section].count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
|
||||
NSString *cellID;
|
||||
UITableViewCellStyle cellStyle;
|
||||
if (item[@"type"] == self.typeChildPane) {
|
||||
cellID = @"cellValue1";
|
||||
cellStyle = UITableViewCellStyleValue1;
|
||||
} else {
|
||||
cellID = @"cellSubtitle";
|
||||
cellStyle = UITableViewCellStyleSubtitle;
|
||||
}
|
||||
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
|
||||
if (cell == nil) {
|
||||
cell = [[UITableViewCell alloc] initWithStyle:cellStyle reuseIdentifier:cellID];
|
||||
cell.detailTextLabel.numberOfLines = 0;
|
||||
cell.detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
}
|
||||
// Reset cell properties, as it could be reused
|
||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
cell.accessoryView = nil;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
cell.textLabel.textColor = nil;
|
||||
cell.detailTextLabel.text = nil;
|
||||
|
||||
NSString *key = item[@"key"];
|
||||
CreateView createView = item[@"type"];
|
||||
createView(cell, key, item);
|
||||
if (cell.accessoryView) {
|
||||
objc_setAssociatedObject(cell.accessoryView, @"key", key, OBJC_ASSOCIATION_ASSIGN);
|
||||
objc_setAssociatedObject(cell.accessoryView, @"item", item, OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
|
||||
// Set general properties
|
||||
if (@available(iOS 13.0, *)) {
|
||||
BOOL destructive = [item[@"destructive"] boolValue];
|
||||
cell.imageView.tintColor = destructive ? UIColor.systemRedColor : nil;
|
||||
cell.imageView.image = [UIImage systemImageNamed:item[@"icon"]];
|
||||
}
|
||||
cell.textLabel.text = NSLocalizedString(([NSString stringWithFormat:@"preference.title.%@", key]), nil);
|
||||
if ([item[@"hasDetail"] boolValue] && self.prefDetailVisible) {
|
||||
cell.detailTextLabel.text = NSLocalizedString(([NSString stringWithFormat:@"preference.detail.%@", key]), nil);
|
||||
} else if (createView != self.typeChildPane) {
|
||||
cell.detailTextLabel.text = nil;
|
||||
}
|
||||
|
||||
// Check if one has enable condition and call if it does
|
||||
BOOL(^checkEnable)(void) = item[@"enableCondition"];
|
||||
cell.userInteractionEnabled = !checkEnable || checkEnable();
|
||||
cell.textLabel.enabled = cell.detailTextLabel.enabled = cell.userInteractionEnabled;
|
||||
[(id)cell.accessoryView setEnabled:cell.userInteractionEnabled];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark initViewCreation, showAlert, checkWarn
|
||||
|
||||
- (void)initViewCreation {
|
||||
__weak LauncherPreferencesViewController2 *weakSelf = self;
|
||||
|
||||
self.typeButton = ^void(UITableViewCell *cell, NSString *key, NSDictionary *item) {
|
||||
BOOL destructive = [item[@"destructive"] boolValue];
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleGray;
|
||||
cell.textLabel.textColor = destructive ? UIColor.systemRedColor : weakSelf.view.tintColor;
|
||||
};
|
||||
|
||||
self.typeChildPane = ^void(UITableViewCell *cell, NSString *key, NSDictionary *item) {
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleGray;
|
||||
cell.detailTextLabel.text = getPreference(key);
|
||||
};
|
||||
|
||||
self.typeTextField = ^void(UITableViewCell *cell, NSString *key, NSDictionary *item) {
|
||||
UITextField *view = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, cell.bounds.size.width / 2.1, cell.bounds.size.height)];
|
||||
[view addTarget:view action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
|
||||
view.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
view.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin;
|
||||
view.delegate = weakSelf;
|
||||
view.placeholder = NSLocalizedString(([NSString stringWithFormat:@"preference.placeholder.%@", key]), nil);
|
||||
view.returnKeyType = UIReturnKeyDone;
|
||||
view.text = getPreference(key);
|
||||
view.textAlignment = NSTextAlignmentRight;
|
||||
view.adjustsFontSizeToFitWidth = YES;
|
||||
cell.accessoryView = view;
|
||||
};
|
||||
|
||||
self.typePickField = ^void(UITableViewCell *cell, NSString *key, NSDictionary *item) {
|
||||
weakSelf.typeTextField(cell, key, item);
|
||||
UITextField *view = (UITextField *)cell.accessoryView;
|
||||
UIPickerView *picker = [[UIPickerView alloc] init];
|
||||
objc_setAssociatedObject(picker, @"item", item, OBJC_ASSOCIATION_ASSIGN);
|
||||
objc_setAssociatedObject(picker, @"view", cell.accessoryView, OBJC_ASSOCIATION_ASSIGN);
|
||||
picker.delegate = weakSelf;
|
||||
picker.dataSource = weakSelf;
|
||||
[picker reloadAllComponents];
|
||||
[picker selectRow:[item[@"pickKeys"] indexOfObject:getPreference(key)] inComponent:0 animated:NO];
|
||||
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, weakSelf.view.frame.size.width, 44.0)];
|
||||
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
|
||||
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:view action:@selector(resignFirstResponder)];
|
||||
toolbar.items = @[flexibleSpace, doneButton];
|
||||
view.inputAccessoryView = toolbar;
|
||||
view.inputView = picker;
|
||||
};
|
||||
|
||||
self.typeSlider = ^void(UITableViewCell *cell, NSString *key, NSDictionary *item) {
|
||||
DBNumberedSlider *view = [[DBNumberedSlider alloc] initWithFrame:CGRectMake(0, 0, cell.bounds.size.width / 2.1, cell.bounds.size.height)];
|
||||
[view addTarget:weakSelf action:@selector(sliderMoved:) forControlEvents:UIControlEventValueChanged];
|
||||
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin;
|
||||
view.minimumValue = [item[@"min"] intValue];
|
||||
view.maximumValue = [item[@"max"] intValue];
|
||||
view.continuous = YES;
|
||||
view.value = [getPreference(key) intValue];
|
||||
cell.accessoryView = view;
|
||||
};
|
||||
|
||||
self.typeSwitch = ^void(UITableViewCell *cell, NSString *key, NSDictionary *item) {
|
||||
UISwitch *view = [[UISwitch alloc] init];
|
||||
NSArray *customSwitchValue = item[@"customSwitchValue"];
|
||||
if (customSwitchValue == nil) {
|
||||
[view setOn:[getPreference(key) boolValue] animated:NO];
|
||||
} else {
|
||||
[view setOn:[getPreference(key) isEqualToString:customSwitchValue[1]] animated:NO];
|
||||
}
|
||||
[view addTarget:weakSelf action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
cell.accessoryView = view;
|
||||
};
|
||||
}
|
||||
|
||||
- (void)showAlertOnView:(UIView *)view title:(NSString *)title message:(NSString *)message {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
alert.popoverPresentationController.sourceView = view;
|
||||
alert.popoverPresentationController.sourceRect = view.bounds;
|
||||
UIAlertAction *ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleCancel handler:nil];
|
||||
[alert addAction:ok];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)checkWarn:(UIView *)view {
|
||||
NSDictionary *item = objc_getAssociatedObject(view, @"item");
|
||||
NSString *key = item[@"key"];
|
||||
|
||||
BOOL(^isWarnable)(UIView *) = item[@"warnCondition"];
|
||||
NSString *warnKey = item[@"warnKey"];
|
||||
// Display warning if: warn condition is met and either one of these:
|
||||
// - does not have warnKey, always warn
|
||||
// - has warnKey and its value is YES, warn once and set it to NO
|
||||
if (isWarnable && isWarnable(view) && (!warnKey || [getPreference(warnKey) boolValue])) {
|
||||
if (warnKey) {
|
||||
setPreference(warnKey, @NO);
|
||||
}
|
||||
|
||||
NSString *message = NSLocalizedString(([NSString stringWithFormat:@"preference.warn.%@", key]), nil);
|
||||
[self showAlertOnView:view title:NSLocalizedString(@"Warning", nil) message:message];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerView
|
||||
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
|
||||
NSDictionary *item = objc_getAssociatedObject(pickerView, @"item");
|
||||
UITextField *view = objc_getAssociatedObject(pickerView, @"view");
|
||||
|
||||
// If there is key, use it
|
||||
if (item[@"pickKeys"] != nil) {
|
||||
view.text = item[@"pickKeys"][row];
|
||||
} else {
|
||||
view.text = item[@"pickList"][row];
|
||||
}
|
||||
|
||||
// Save the preference
|
||||
[self textFieldDidEndEditing:view];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
|
||||
NSDictionary *item = objc_getAssociatedObject(pickerView, @"item");
|
||||
return [item[@"pickList"] count];
|
||||
}
|
||||
|
||||
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
|
||||
NSDictionary *item = objc_getAssociatedObject(pickerView, @"item");
|
||||
return item[@"pickList"][row];
|
||||
}
|
||||
|
||||
#pragma mark Control event handlers
|
||||
|
||||
- (void)sliderMoved:(DBNumberedSlider *)sender {
|
||||
[self checkWarn:sender];
|
||||
NSString *key = objc_getAssociatedObject(sender, @"key");
|
||||
|
||||
sender.value = (int)sender.value;
|
||||
setPreference(key, @(sender.value));
|
||||
}
|
||||
|
||||
- (void)switchChanged:(UISwitch *)sender {
|
||||
[self checkWarn:sender];
|
||||
NSDictionary *item = objc_getAssociatedObject(sender, @"item");
|
||||
NSString *key = item[@"key"];
|
||||
|
||||
// Special switches may define custom value instead of NO/YES
|
||||
NSArray *customSwitchValue = item[@"customSwitchValue"];
|
||||
if (customSwitchValue != nil) {
|
||||
setPreference(key, customSwitchValue[sender.isOn]);
|
||||
} else {
|
||||
setPreference(key, @(sender.isOn));
|
||||
}
|
||||
|
||||
// Some settings may affect the availability of other settings
|
||||
// In this case, a switch may request to reload to apply user interaction change
|
||||
if ([item[@"requestReload"] boolValue]) {
|
||||
// TODO: only reload needed rows
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
|
||||
if (item[@"type"] == self.typeButton) {
|
||||
[self tableView:tableView invokeActionWithPromptAtIndexPath:indexPath];
|
||||
} else if (item[@"type"] == self.typeChildPane) {
|
||||
[self tableView:tableView openChildPaneAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark External UITableView functions
|
||||
|
||||
- (void)tableView:(UITableView *)tableView openChildPaneAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
UIViewController *vc = [[item[@"class"] alloc] init];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView invokeActionWithPromptAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *view = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
NSString *key = item[@"key"];
|
||||
|
||||
if ([item[@"showConfirmPrompt"] boolValue]) {
|
||||
BOOL destructive = [item[@"destructive"] boolValue];
|
||||
NSString *title = NSLocalizedString(@"preference.title.confirm", nil);
|
||||
NSString *message = NSLocalizedString(([NSString stringWithFormat:@"preference.title.confirm.%@", key]), nil);
|
||||
UIAlertController *confirmAlert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
confirmAlert.popoverPresentationController.sourceView = view;
|
||||
confirmAlert.popoverPresentationController.sourceRect = view.bounds;
|
||||
UIAlertAction *ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:destructive?UIAlertActionStyleDestructive:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
[self tableView:tableView invokeActionAtIndexPath:indexPath];
|
||||
}];
|
||||
UIAlertAction *cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
|
||||
[confirmAlert addAction:cancel];
|
||||
[confirmAlert addAction:ok];
|
||||
[self presentViewController:confirmAlert animated:YES completion:nil];
|
||||
} else {
|
||||
[self tableView:tableView invokeActionAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView invokeActionAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSDictionary *item = self.prefContents[indexPath.section][indexPath.row];
|
||||
NSString *key = item[@"key"];
|
||||
|
||||
void(^invokeAction)(void) = item[@"action"];
|
||||
if (invokeAction) {
|
||||
invokeAction();
|
||||
}
|
||||
|
||||
UIView *view = [self.tableView cellForRowAtIndexPath:indexPath];
|
||||
NSString *title = NSLocalizedString(([NSString stringWithFormat:@"preference.title.done.%@", key]), nil);
|
||||
//NSString *message = NSLocalizedString(([NSString stringWithFormat:@"preference.message.done.%@", key]), nil);
|
||||
[self showAlertOnView:view title:title message:nil];
|
||||
}
|
||||
|
||||
#pragma mark UITextField
|
||||
|
||||
- (void)textFieldDidEndEditing:(UITextField *)sender {
|
||||
[self checkWarn:sender];
|
||||
NSString *key = objc_getAssociatedObject(sender, @"key");
|
||||
|
||||
setPreference(key, sender.text);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2,7 +2,6 @@
|
||||
#import "CustomControlsViewController.h"
|
||||
#import "JavaGUIViewController.h"
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPreferencesViewController.h"
|
||||
#import "LauncherViewController.h"
|
||||
#import "MinecraftResourceUtils.h"
|
||||
#import "ios_uikit_bridge.h"
|
||||
@@ -54,8 +53,6 @@ int versionSelectedAt = 0;
|
||||
|
||||
|
||||
self.versionList = [[NSMutableArray alloc] init];
|
||||
int selectedVersionType = [getPreference(@"selected_version_type") intValue];
|
||||
[self reloadVersionList:selectedVersionType];
|
||||
versionPickerView = [[UIPickerView alloc] init];
|
||||
versionPickerView.delegate = self;
|
||||
versionPickerView.dataSource = self;
|
||||
@@ -68,7 +65,7 @@ int versionSelectedAt = 0;
|
||||
NSLocalizedString(@"Old-beta", nil),
|
||||
NSLocalizedString(@"Old-alpha", nil)
|
||||
]];
|
||||
versionTypeControl.selectedSegmentIndex = selectedVersionType;
|
||||
versionTypeControl.selectedSegmentIndex = [getPreference(@"selected_version_type") intValue];
|
||||
[versionTypeControl addTarget:self action:@selector(changeVersionType:) forControlEvents:UIControlEventValueChanged];
|
||||
UIBarButtonItem *versionTypeItem = [[UIBarButtonItem alloc] initWithCustomView:versionTypeControl];
|
||||
UIBarButtonItem *versionFlexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
|
||||
@@ -114,6 +111,11 @@ int versionSelectedAt = 0;
|
||||
[scrollView addSubview:self.progressText];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
[self reloadVersionList:[getPreference(@"selected_version_type") intValue]];
|
||||
}
|
||||
|
||||
- (BOOL)isVersionInstalled:(NSString *)versionId
|
||||
{
|
||||
NSString *localPath = [NSString stringWithFormat:@"%s/versions/%@", getenv("POJAV_GAME_DIR"), versionId];
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#define TYPE_MICROSOFT 1
|
||||
#define TYPE_OFFLINE 2
|
||||
|
||||
extern NSMutableDictionary *prefDict;
|
||||
|
||||
#pragma mark - LoginViewController
|
||||
@interface LoginViewController () <ASWebAuthenticationPresentationContextProviding>{
|
||||
}
|
||||
@@ -36,6 +38,8 @@
|
||||
[super viewDidLoad];
|
||||
setViewBackgroundColor(self.view);
|
||||
|
||||
setDefaultValueForPref(prefDict, @"control_safe_area", NSStringFromCGRect(getDefaultSafeArea()));
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(msaLoginCallback:) name:@"MSALoginCallback" object:nil];
|
||||
|
||||
CGRect screenBounds = [[UIScreen mainScreen] bounds];
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#import "JavaLauncher.h"
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPreferencesViewController2.h"
|
||||
#import "MinecraftResourceUtils.h"
|
||||
#import "SurfaceViewController.h"
|
||||
|
||||
@@ -193,6 +194,7 @@ BOOL slideableHotbar;
|
||||
@property id mouseConnectCallback, mouseDisconnectCallback;
|
||||
@property id controllerConnectCallback, controllerDisconnectCallback;
|
||||
|
||||
@property CGFloat mouseSpeed;
|
||||
@property CGRect clickRange;
|
||||
@property BOOL shouldTriggerClick;
|
||||
|
||||
@@ -219,10 +221,9 @@ BOOL slideableHotbar;
|
||||
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
||||
|
||||
resolutionScale = ((NSNumber *)getPreference(@"resolution")).floatValue / 100.0;
|
||||
slideableHotbar = [getPreference(@"slideable_hotbar") boolValue];
|
||||
|
||||
savedWidth = roundf(screenBounds.size.width * screenScale);
|
||||
savedHeight = roundf(screenBounds.size.height * screenScale);
|
||||
savedWidth = roundf(screenBounds.size.width * screenScale * resolutionScale);
|
||||
savedHeight = roundf(screenBounds.size.height * screenScale * resolutionScale);
|
||||
|
||||
self.rootView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width + 30.0, self.view.frame.size.height)];
|
||||
[self.view addSubview:self.rootView];
|
||||
@@ -249,7 +250,7 @@ BOOL slideableHotbar;
|
||||
[menuSwipeView addSubview:menuSwipeLineView];
|
||||
[self.rootView addSubview:menuSwipeView];
|
||||
|
||||
self.menuArray = @[@"game.menu.forceClose" /*, @"game.menu.logOutput" */];
|
||||
self.menuArray = @[@"game.menu.force_close", @"Settings" /*, @"game.menu.log_output" */];
|
||||
|
||||
self.menuView = [[UITableView alloc] initWithFrame:CGRectMake(self.view.frame.size.width + 30.0, 0,
|
||||
self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)];
|
||||
@@ -272,9 +273,6 @@ self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)];
|
||||
[self.rootView addSubview:self.surfaceView];
|
||||
[self.rootView addSubview:self.ctrlView];
|
||||
|
||||
|
||||
CGFloat buttonScale = [getPreference(@"button_scale") floatValue] / 100.0;
|
||||
|
||||
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(surfaceOnClick:)];
|
||||
tapGesture.allowedTouchTypes = @[@(UITouchTypeDirect)];
|
||||
@@ -304,7 +302,6 @@ self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)];
|
||||
longpressGesture.allowedTouchTypes = @[@(UITouchTypeDirect)];
|
||||
longpressGesture.cancelsTouchesInView = NO;
|
||||
longpressGesture.delegate = self;
|
||||
longpressGesture.minimumPressDuration = [getPreference(@"time_longPressTrigger") floatValue] / 1000;
|
||||
[self.surfaceView addGestureRecognizer:longpressGesture];
|
||||
|
||||
self.scrollPanGesture = [[UIPanGestureRecognizer alloc]
|
||||
@@ -349,35 +346,6 @@ self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)];
|
||||
|
||||
self.swipeableButtons = [[NSMutableArray alloc] init];
|
||||
|
||||
self.cc_dictionary = parseJSONFromFile(controlFilePath);
|
||||
if (self.cc_dictionary[@"error"] != nil) {
|
||||
showDialog(self, @"Error", [NSString stringWithFormat:@"Could not open %@: %@", controlFilePath, [self.cc_dictionary[@"error"] localizedDescription]]);
|
||||
} else {
|
||||
CGFloat currentScale = [self.cc_dictionary[@"scaledAt"] floatValue];
|
||||
CGFloat savedScale = [getPreference(@"button_scale") floatValue];
|
||||
loadControlObject(self.ctrlView, self.cc_dictionary, ^void(ControlButton* button) {
|
||||
BOOL isSwipeable = [button.properties[@"isSwipeable"] boolValue];
|
||||
|
||||
button.canBeHidden = YES;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int keycodeInt = [button.properties[@"keycodes"][i] intValue];
|
||||
button.canBeHidden &= keycodeInt != SPECIALBTN_TOGGLECTRL;
|
||||
}
|
||||
|
||||
[button addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown];
|
||||
[button addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
|
||||
|
||||
if (isSwipeable) {
|
||||
UIPanGestureRecognizer *panRecognizerButton = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(executebtn_swipe:)];
|
||||
panRecognizerButton.delegate = self;
|
||||
[button addGestureRecognizer:panRecognizerButton];
|
||||
[self.swipeableButtons addObject:button];
|
||||
}
|
||||
});
|
||||
|
||||
self.cc_dictionary[@"scaledAt"] = @(savedScale);
|
||||
}
|
||||
|
||||
[KeyboardInput initKeycodeTable];
|
||||
if (@available(iOS 14.0, tvOS 14.0, *)) {
|
||||
self.mouseConnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCMouseDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
|
||||
@@ -432,10 +400,41 @@ self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)];
|
||||
*/
|
||||
|
||||
// [self setPreferredFramesPerSecond:1000];
|
||||
[self updatePreferenceChanges];
|
||||
[self executebtn_special_togglebtn:0];
|
||||
[self launchMinecraft];
|
||||
}
|
||||
|
||||
- (void)updatePreferenceChanges {
|
||||
self.mouseSpeed = [getPreference(@"mouse_speed") floatValue] / 100.0;
|
||||
slideableHotbar = [getPreference(@"slideable_hotbar") boolValue];
|
||||
|
||||
virtualMouseEnabled = [getPreference(@"virtmouse_enable") boolValue];
|
||||
self.mousePointerView.hidden = isGrabbing || !virtualMouseEnabled;
|
||||
|
||||
CGRect screenBounds = UIScreen.mainScreen.bounds;
|
||||
CGFloat screenScale = UIScreen.mainScreen.scale;
|
||||
|
||||
// Update virtual mouse scale
|
||||
CGFloat mouseScale = [getPreference(@"mouse_scale") floatValue] / 100.0;
|
||||
virtualMouseFrame = CGRectMake(screenBounds.size.width / 2, screenBounds.size.height / 2, 18.0 * mouseScale, 27 * mouseScale);
|
||||
self.mousePointerView.frame = virtualMouseFrame;
|
||||
|
||||
// May break anytime lol, current: edge, tap, doubleTap, hover, longPress, scrollPan
|
||||
UILongPressGestureRecognizer *longpressGesture = self.surfaceView.gestureRecognizers[4];
|
||||
longpressGesture.minimumPressDuration = [getPreference(@"press_duration") floatValue] / 1000.0;
|
||||
|
||||
self.ctrlView.frame = CGRectFromString(getPreference(@"control_safe_area"));
|
||||
[self loadCustomControls];
|
||||
|
||||
// Update resolution
|
||||
resolutionScale = [getPreference(@"resolution") floatValue] / 100.0;
|
||||
self.surfaceView.layer.contentsScale = screenScale * resolutionScale;
|
||||
savedWidth = roundf(screenBounds.size.width * screenScale * resolutionScale);
|
||||
savedHeight = roundf(screenBounds.size.height * screenScale * resolutionScale);
|
||||
CallbackBridge_nativeSendScreenSize(savedWidth, savedHeight);
|
||||
}
|
||||
|
||||
- (void)launchMinecraft {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[MinecraftResourceUtils downloadClientJson:getPreference(@"selected_version") progress:nil callback:nil success:^(NSMutableDictionary *json) {
|
||||
@@ -443,22 +442,59 @@ self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)];
|
||||
launchJVM(
|
||||
BaseAuthenticator.current.authData[@"username"],
|
||||
json,
|
||||
savedWidth * resolutionScale, savedHeight * resolutionScale,
|
||||
savedWidth, savedHeight,
|
||||
[json[@"javaVersion"][@"majorVersion"] intValue]
|
||||
);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)loadCustomControls {
|
||||
[self.ctrlView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
[self.swipeableButtons removeAllObjects];
|
||||
[self.cc_dictionary removeAllObjects];
|
||||
|
||||
NSString *controlFilePath = [NSString stringWithFormat:@"%s/controlmap/%@", getenv("POJAV_HOME"), (NSString *)getPreference(@"default_ctrl")];
|
||||
|
||||
self.cc_dictionary = parseJSONFromFile(controlFilePath);
|
||||
if (self.cc_dictionary[@"error"] != nil) {
|
||||
showDialog(self, NSLocalizedString(@"Error", nil), [NSString stringWithFormat:@"Could not open %@: %@", controlFilePath, [self.cc_dictionary[@"error"] localizedDescription]]);
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat currentScale = [self.cc_dictionary[@"scaledAt"] floatValue];
|
||||
CGFloat savedScale = [getPreference(@"button_scale") floatValue];
|
||||
loadControlObject(self.ctrlView, self.cc_dictionary, ^void(ControlButton* button) {
|
||||
BOOL isSwipeable = [button.properties[@"isSwipeable"] boolValue];
|
||||
|
||||
button.canBeHidden = YES;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int keycodeInt = [button.properties[@"keycodes"][i] intValue];
|
||||
button.canBeHidden &= keycodeInt != SPECIALBTN_TOGGLECTRL;
|
||||
}
|
||||
|
||||
[button addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown];
|
||||
[button addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
|
||||
|
||||
if (isSwipeable) {
|
||||
UIPanGestureRecognizer *panRecognizerButton = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(executebtn_swipe:)];
|
||||
panRecognizerButton.delegate = self;
|
||||
[button addGestureRecognizer:panRecognizerButton];
|
||||
[self.swipeableButtons addObject:button];
|
||||
}
|
||||
});
|
||||
|
||||
self.cc_dictionary[@"scaledAt"] = @(savedScale);
|
||||
}
|
||||
|
||||
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
|
||||
return UIRectEdgeBottom | UIRectEdgeRight;
|
||||
}
|
||||
|
||||
- (BOOL)prefersHomeIndicatorAutoHidden {
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Menu functions
|
||||
|
||||
CGPoint lastCenterPoint;
|
||||
@@ -515,7 +551,7 @@ CGPoint lastCenterPoint;
|
||||
|
||||
- (void)actionForceClose {
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:nil
|
||||
message:NSLocalizedString(@"game.menu.confirm.forceClose", nil)
|
||||
message:NSLocalizedString(@"game.menu.confirm.force_close", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleDefault handler:nil];
|
||||
@@ -531,7 +567,12 @@ CGPoint lastCenterPoint;
|
||||
}];
|
||||
[alert addAction:okAction];
|
||||
|
||||
[currentVC() presentViewController:alert animated:YES completion:nil];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)actionOpenPreferences {
|
||||
LauncherPreferencesViewController2 *vc = [[LauncherPreferencesViewController2 alloc] init];
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)actionToggleLogOutput {
|
||||
@@ -567,6 +608,9 @@ CGPoint lastCenterPoint;
|
||||
[self actionForceClose];
|
||||
break;
|
||||
case 1:
|
||||
[self actionOpenPreferences];
|
||||
break;
|
||||
case 2:
|
||||
[self actionToggleLogOutput];
|
||||
break;
|
||||
}
|
||||
@@ -587,12 +631,12 @@ CGPoint lastCenterPoint;
|
||||
screenScale *= resolutionScale;
|
||||
if (virtualMouseEnabled) {
|
||||
if (event == ACTION_MOVE) {
|
||||
virtualMouseFrame.origin.x += location.x - lastVirtualMousePoint.x;
|
||||
virtualMouseFrame.origin.y += location.y - lastVirtualMousePoint.y;
|
||||
virtualMouseFrame.origin.x += (location.x - lastVirtualMousePoint.x) * self.mouseSpeed;
|
||||
virtualMouseFrame.origin.y += (location.y - lastVirtualMousePoint.y) * self.mouseSpeed;
|
||||
} else if (event == ACTION_MOVE_MOTION) {
|
||||
event = ACTION_MOVE;
|
||||
virtualMouseFrame.origin.x += location.x;
|
||||
virtualMouseFrame.origin.y += location.y;
|
||||
virtualMouseFrame.origin.x += location.x * self.mouseSpeed;
|
||||
virtualMouseFrame.origin.y += location.y * self.mouseSpeed;
|
||||
}
|
||||
virtualMouseFrame.origin.x = clamp(virtualMouseFrame.origin.x, 0, self.view.frame.size.width);
|
||||
virtualMouseFrame.origin.y = clamp(virtualMouseFrame.origin.y, 0, self.view.frame.size.height);
|
||||
|
||||
+47
-27
@@ -91,15 +91,14 @@ pid_t gettid() {
|
||||
return (pid_t) pthread_mach_thread_np(pthread_self());
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_setenv(JNIEnv *env, jclass clazz, jstring name, jstring value, jboolean overwrite) {
|
||||
char const *name_c = (*env)->GetStringUTFChars(env, name, NULL);
|
||||
char const *value_c = (*env)->GetStringUTFChars(env, value, NULL);
|
||||
|
||||
setenv(name_c, value_c, overwrite);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, name, name_c);
|
||||
(*env)->ReleaseStringUTFChars(env, value, value_c);
|
||||
void JNI_LWJGL_changeRenderer(const char* value_c) {
|
||||
JNIEnv *env;
|
||||
(*runtimeJavaVMPtr)->GetEnv(runtimeJavaVMPtr, (void **)&env, JNI_VERSION_1_4);
|
||||
jstring key = (*env)->NewStringUTF(env, "org.lwjgl.opengl.libname");
|
||||
jstring value = (*env)->NewStringUTF(env, value_c);
|
||||
jclass clazz = (*env)->FindClass(env, "java/lang/System");
|
||||
jmethodID method = (*env)->GetStaticMethodID(env, clazz, "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
|
||||
(*env)->CallStaticObjectMethod(env, clazz, method, key, value);
|
||||
}
|
||||
|
||||
void pojavTerminate() {
|
||||
@@ -225,11 +224,17 @@ jboolean pojavInit_OpenGL() {
|
||||
if (config_renderer) return JNI_TRUE;
|
||||
|
||||
NSString *renderer = @(getenv("POJAV_RENDERER"));
|
||||
JNI_LWJGL_changeRenderer(renderer.UTF8String);
|
||||
BOOL isAuto = [renderer isEqualToString:@"auto"];
|
||||
if ([renderer isEqualToString:@"libOSMesa.8.dylib"]) {
|
||||
config_renderer = RENDERER_VIRGL;
|
||||
setenv("GALLIUM_DRIVER", "virpipe", 1);
|
||||
loadSymbolsVirGL();
|
||||
} else if ([renderer hasPrefix:@"libgl4es"] || [renderer hasPrefix:@"libtinygl4angle"]) {
|
||||
} else if (isAuto || [renderer isEqualToString:@ RENDERER_NAME_GL4ES]) {
|
||||
config_renderer = RENDERER_MTL_ANGLE;
|
||||
setenv("POJAV_RENDERER", RENDERER_NAME_GL4ES, 1);
|
||||
loadSymbols();
|
||||
} else if ([renderer isEqualToString:@ RENDERER_NAME_MTL_ANGLE]) {
|
||||
config_renderer = RENDERER_MTL_ANGLE;
|
||||
loadSymbols();
|
||||
} else if ([renderer hasPrefix:@"libOSMesa"]) {
|
||||
@@ -248,9 +253,17 @@ jboolean pojavInit_OpenGL() {
|
||||
}
|
||||
|
||||
// Pre-load the renderer library
|
||||
// FIXME: gl4es has to be pre-loaded if it is going to be used later,
|
||||
// or glCheckFramebufferStatus will return an error
|
||||
void *renderer_handle = dlopen(getenv("POJAV_RENDERER"), RTLD_GLOBAL);
|
||||
debugLog("%s=%p, error=%s", getenv("POJAV_RENDERER"), renderer_handle, dlerror());
|
||||
|
||||
// Set back to the previous value
|
||||
setenv("POJAV_RENDERER", renderer.UTF8String, 1);
|
||||
if (isAuto) {
|
||||
JNI_LWJGL_changeRenderer(RENDERER_NAME_GL4ES);
|
||||
}
|
||||
|
||||
debugLog("EGLBridge: Initializing");
|
||||
// printf("EGLBridge: ANativeWindow pointer = %p\n", potatoBridge.androidWindow);
|
||||
//(*env)->ThrowNew(env,(*env)->FindClass(env,"java/lang/Exception"),"Trace exception");
|
||||
@@ -293,8 +306,8 @@ jboolean pojavInit_OpenGL() {
|
||||
eglBindAPI_p(EGL_OPENGL_ES_API);
|
||||
}
|
||||
|
||||
potatoBridge.eglSurface = eglCreateWindowSurface_p(potatoBridge.eglDisplay, config, (__bridge EGLNativeWindowType) ((SurfaceViewController *)currentVC()).surfaceView.layer, NULL);
|
||||
//NSLog(@"Layer %@", ((SurfaceViewController *)currentVC()).surfaceView.layer);
|
||||
potatoBridge.eglSurface = eglCreateWindowSurface_p(potatoBridge.eglDisplay, config, (__bridge EGLNativeWindowType) ((SurfaceViewController *)currentWindow().rootViewController).surfaceView.layer, NULL);
|
||||
//NSLog(@"Layer %@", ((SurfaceViewController *)currentWindow().rootViewController).surfaceView.layer);
|
||||
|
||||
if (!potatoBridge.eglSurface) {
|
||||
debugLog("EGLBridge: Error eglCreateWindowSurface failed: 0x%x", eglGetError_p());
|
||||
@@ -351,19 +364,26 @@ jboolean pojavInit_OpenGL() {
|
||||
}
|
||||
|
||||
void pojavSetWindowHint(int hint, int value) {
|
||||
if (hint != GLFW_CLIENT_API) return;
|
||||
switch (value) {
|
||||
case GLFW_NO_API:
|
||||
config_renderer = RENDERER_VULKAN;
|
||||
/* Nothing to do: initialization is handled in Java-side */
|
||||
// pojavInit_Vulkan();
|
||||
break;
|
||||
case GLFW_OPENGL_API:
|
||||
pojavInit_OpenGL();
|
||||
break;
|
||||
default:
|
||||
NSLog(@"GLFW: Unimplemented API 0x%x", value);
|
||||
abort();
|
||||
if (hint == GLFW_CLIENT_API) {
|
||||
switch (value) {
|
||||
case GLFW_NO_API:
|
||||
config_renderer = RENDERER_VULKAN;
|
||||
/* Nothing to do: initialization is handled in Java-side */
|
||||
// pojavInit_Vulkan();
|
||||
break;
|
||||
case GLFW_OPENGL_API:
|
||||
pojavInit_OpenGL();
|
||||
break;
|
||||
default:
|
||||
NSLog(@"GLFW: Unimplemented API 0x%x", value);
|
||||
abort();
|
||||
}
|
||||
} else if (strcmp(getenv("POJAV_RENDERER"), "auto")==0 && hint == GLFW_CONTEXT_VERSION_MAJOR && value >= 3) {
|
||||
// Free unused gl4es library
|
||||
void *renderer_handle = dlopen(RENDERER_NAME_GL4ES, RTLD_GLOBAL);
|
||||
dlclose(renderer_handle);
|
||||
|
||||
JNI_LWJGL_changeRenderer(RENDERER_NAME_MTL_ANGLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +412,7 @@ void pojavSwapBuffers() {
|
||||
case RENDERER_VK_ZINK: {
|
||||
glFinish_p();
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[((SurfaceViewController *)currentVC()).surfaceView displayLayer];
|
||||
[((SurfaceViewController *)currentWindow().rootViewController).surfaceView displayLayer];
|
||||
});
|
||||
} break;
|
||||
}
|
||||
@@ -472,7 +492,7 @@ void pojavMakeCurrent(void* window) {
|
||||
|
||||
void* pojavCreateContext(void* contextSrc) {
|
||||
if (config_renderer == RENDERER_VULKAN) {
|
||||
return (__bridge void *)(((SurfaceViewController *)currentVC()).surfaceView.layer);
|
||||
return (__bridge void *)(((SurfaceViewController *)currentWindow().rootViewController).surfaceView.layer);
|
||||
}
|
||||
|
||||
if (config_renderer == RENDERER_MTL_ANGLE) {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
StringLocalization
|
||||
*/
|
||||
|
||||
"game.menu.forceClose" = "Force close";
|
||||
"game.menu.confirm.forceClose" = "Are you sure you want to force close?";
|
||||
"game.menu.logOutput" = "Log output";
|
||||
"game.menu.customControls" = "Custom controls";
|
||||
"game.menu.force_close" = "Force close";
|
||||
"game.menu.confirm.force_close" = "Are you sure you want to force close?";
|
||||
"game.menu.log_output" = "Log output";
|
||||
"game.menu.custom_controls" = "Custom controls";
|
||||
|
||||
"Installed" = "Installed";
|
||||
"Snapshot" = "Snapshot";
|
||||
@@ -64,3 +64,74 @@
|
||||
"login.msa.progress.acquireXboxProfile" = "(3/5) Acquiring the Xbox profile";
|
||||
"login.msa.progress.acquireMCToken" = "(4/5) Acquiring the Minecraft token";
|
||||
"login.msa.progress.checkMCProfile" = "(5/5) Checking the Minecraft profile";
|
||||
|
||||
"Settings" = "Settings";
|
||||
|
||||
"preference.section.general" = "General Settings";
|
||||
"preference.section.footer.general" = "* Compatibility symlink option is planned to be removed in a future release.";
|
||||
"preference.section.video" = "Video Settings";
|
||||
"preference.section.footer.video" = "Auto renderer allows Minecraft to decide which renderer to use. Decreasing resolution reduces GPU workload for better performance.";
|
||||
"preference.section.control" = "Control customization";
|
||||
//"preference.section.footer.control" = "";
|
||||
"preference.section.java" = "Java Tweaks";
|
||||
//"preference.section.footer.java" = "";
|
||||
|
||||
"preference.title.confirm" = "Are you sure?";
|
||||
|
||||
"preference.title.game_directory" = "Minecraft game directory";
|
||||
"preference.title.confirm.delete_game_directory" = "The instance %@ will be deleted forever and cannot be restored.";
|
||||
"preference.multidir.add_directory" = "add game directory";
|
||||
|
||||
"preference.title.home_symlink" = "Enable compatibility symlink *";
|
||||
"preference.detail.home_symlink" = "Make a symlink at /var/mobile/Documents/.pojavlauncher. Unavailable in sandboxed environment.";
|
||||
"preference.title.check_sha" = "Check files after downloading";
|
||||
"preference.detail.check_sha" = "This option forces launcher to check the file hash if it's available. Prevents broken downloads.";
|
||||
"preference.title.cosmetica" = "Cosmetica Capes";
|
||||
"preference.detail.cosmetica" = "Enable capes from Cosmetica (previously Arc). For more information please visit https://cosmetica.cc. Requires OptiFine";
|
||||
"preference.title.debug_logging" = "Debug logging";
|
||||
"preference.detail.debug_logging" = "Logs internal settings and actions to latestlog.txt. This helps the developers find issues easier, but Minecraft may run slower as the logs will be written to more often.";
|
||||
|
||||
"preference.title.reset_warnings" = "Reset all warnings";
|
||||
"preference.title.done.reset_warnings" = "All warnings have been reset.";
|
||||
|
||||
"preference.title.reset_settings" = "Reset all settings";
|
||||
"preference.title.confirm.reset_settings" = "This will remove all of your custom preferences, including resolution, button size, and Java arguments.";
|
||||
"preference.title.done.reset_settings" = "All of the default settings have been restored.";
|
||||
|
||||
"preference.title.renderer" = "Renderer";
|
||||
"preference.title.renderer.auto" = "Auto: gl4es or tinygl4angle";
|
||||
"preference.title.renderer.gl4es" = "gl4es 1.1.4 - exports OpenGL 2.1";
|
||||
"preference.title.renderer.tinygl4angle" = "tinygl4angle (1.17+) - exports OpenGL 3.2 (Core Profile, limited)";
|
||||
"preference.title.renderer.zink" = "Zink (Mesa 21.0) - exports OpenGL 4.1";
|
||||
"preference.detail.renderer" = "Change the OpenGL render engine to use";
|
||||
|
||||
"preference.title.resolution" = "Resolution (%)";
|
||||
"preference.detail.resolution" = "Allows you to decrease the game resolution.";
|
||||
"preference.title.disable_gesture" = "Disable gestures";
|
||||
"preference.title.press_duration" = "Long-press duration (ms)";
|
||||
"preference.detail.press_duration" = "Change trigger time for long press in destroy block and drop item.";
|
||||
"preference.title.button_scale" = "On-screen button scale (%)";
|
||||
"preference.detail.button_scale" = "Upscale them if buttons are too small, usually needed for iPad users.";
|
||||
"preference.title.mouse_scale" = "Mouse scaling (%)";
|
||||
"preference.detail.mouse_scale" = "Change the size of the virtual mouse";
|
||||
"preference.title.mouse_speed" = "Mouse speed (%)";
|
||||
"preference.detail.mouse_speed" = "Change the speed of the virtual mouse";
|
||||
"preference.title.virtmouse_enable" = "Virtual mouse";
|
||||
"preference.detail.virtmouse_enable" = "Enable this option to start with virtual mouse on";
|
||||
"preference.title.slideable_hotbar" = "Slideable hotbar";
|
||||
"preference.detail.slideable_hotbar" = "Make the hotbar slideable like the mouse wheel";
|
||||
"preference.title.java_home" = "Use Java 17 for Minecraft < 1.17";
|
||||
"preference.detail.java_home" = "Java 8 is used by default for those versions. Enable this option to force use Java 17, however compatibility with modded is not guaranteed.";
|
||||
"preference.title.java_args" = "JVM Launch arguments";
|
||||
"preference.detail.java_args" = "Be careful, this can make the game crash if modified without any prior knowledge.";
|
||||
"preference.placeholder.java_args" = "Specify arguments...";
|
||||
"preference.title.auto_ram" = "Auto RAM";
|
||||
"preference.detail.auto_ram" = "Enables automatic RAM adjuster";
|
||||
"preference.warn.auto_ram" = "Disabling this option on an unjailbroken device can create instability if altered. Proceed with caution.";
|
||||
"preference.title.allocated_memory" = "Memory allocation (MB)";
|
||||
"preference.detail.allocated_memory" = "Controls how much memory is given to Minecraft";
|
||||
"preference.warn.allocated_memory" = "Due to limitations in the operating system itself, this option may cause instability at this and higher values. Proceed with caution.";
|
||||
"preference.title.custom_env" = "Environment variables";
|
||||
"preference.detail.custom_env" = "This option is under construction.";
|
||||
// sha check
|
||||
// home symlink
|
||||
Vendored
+1
-1
Submodule Natives/external/DBNumberedSlider updated: bc6ea60353...4eddc68b5f.
+1
Submodule Natives/external/TOInsetGroupedTableView added at a17c55acd5.
@@ -35,6 +35,8 @@
|
||||
#define GLFW_NO_API 0
|
||||
#define GLFW_OPENGL_API 0x30001
|
||||
|
||||
#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002
|
||||
|
||||
/*! @defgroup hat_state Joystick hat states
|
||||
* @brief Joystick hat states.
|
||||
*
|
||||
|
||||
@@ -169,7 +169,7 @@ BOOL leftShiftHeld;
|
||||
return;
|
||||
}
|
||||
|
||||
UIImageView *pointerView = [(id)currentVC() mousePointerView];
|
||||
UIImageView *pointerView = [(id)currentWindow().rootViewController mousePointerView];
|
||||
virtualMouseFrame.origin.x += xValue;
|
||||
virtualMouseFrame.origin.y += yValue;
|
||||
pointerView.frame = virtualMouseFrame;
|
||||
|
||||
@@ -270,16 +270,16 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(JNIE
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIView *surfaceView = ((SurfaceViewController *)currentVC()).surfaceView;
|
||||
UIView *surfaceView = ((SurfaceViewController *)currentWindow().rootViewController).surfaceView;
|
||||
if (isGrabbing == JNI_TRUE) {
|
||||
CGFloat screenScale = [[UIScreen mainScreen] scale] * resolutionScale;
|
||||
callback_SurfaceViewController_onTouch(ACTION_DOWN, lastVirtualMousePoint.x * screenScale, lastVirtualMousePoint.y * screenScale);
|
||||
((SurfaceViewController *)currentVC()).mousePointerView.frame = virtualMouseFrame;
|
||||
((SurfaceViewController *)currentWindow().rootViewController).mousePointerView.frame = virtualMouseFrame;
|
||||
}
|
||||
((SurfaceViewController *)currentVC()).scrollPanGesture.enabled = !isGrabbing;
|
||||
((SurfaceViewController *)currentVC()).mousePointerView.hidden = isGrabbing || !virtualMouseEnabled;
|
||||
((SurfaceViewController *)currentWindow().rootViewController).scrollPanGesture.enabled = !isGrabbing;
|
||||
((SurfaceViewController *)currentWindow().rootViewController).mousePointerView.hidden = isGrabbing || !virtualMouseEnabled;
|
||||
if(@available(iOS 14.0, *)) {
|
||||
[(SurfaceViewController *)currentVC() setNeedsUpdateOfPrefersPointerLocked];
|
||||
[(SurfaceViewController *)currentWindow().rootViewController setNeedsUpdateOfPrefersPointerLocked];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+14
-28
@@ -1,6 +1,5 @@
|
||||
#import "authenticator/BaseAuthenticator.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "BKSSystemService.h"
|
||||
#import "SceneDelegate.h"
|
||||
#import "LoginViewController.h"
|
||||
#import "LauncherPreferences.h"
|
||||
@@ -104,37 +103,24 @@ jstring UIKit_accessClipboard(JNIEnv* env, jint action, jstring copySrc) {
|
||||
}
|
||||
|
||||
void UIKit_launchMinecraftSurfaceVC() {
|
||||
setPreference(@"internal_launch_on_boot", getPreference(@"restart_before_launch"));
|
||||
// Leave this pref, might be useful later for launching with Quick Actions/Shortcuts/URL Scheme
|
||||
//setPreference(@"internal_launch_on_boot", getPreference(@"restart_before_launch"));
|
||||
setPreference(@"internal_selected_account", BaseAuthenticator.current.authData[@"username"]);
|
||||
setPreference(@"internal_useStackQueue", @(isUseStackQueueCall ? YES : NO));
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([getPreference(@"restart_before_launch") boolValue]) {
|
||||
NSURL *url = [NSURL URLWithString:@"pojavlauncher://"];
|
||||
BKSSystemService *service = [[NSClassFromString(@"BKSSystemService") alloc] init];
|
||||
unsigned int port = [service createClientPort];
|
||||
[service openURL:url application:@"net.kdt.pojavlauncher" options:nil clientPort:port withResult:nil];
|
||||
|
||||
// exiting too fast will cause it to fail (race condition?)
|
||||
// [FBSystemService][0xbb88] Caller "PojavLauncher:pid" has a sandbox that does not allow opening URL's.
|
||||
// The request was denied by service delegate (SBMainWorkspace) for reason: Security ("Sandbox check failed for process (PojavLauncher:pid) openURL not allowed").
|
||||
// therefore, sleep for 1ms before exit
|
||||
usleep(1000);
|
||||
exit(0);
|
||||
} else {
|
||||
id delegate = UIApplication.sharedApplication.delegate;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
delegate = UIApplication.sharedApplication.connectedScenes.anyObject.delegate;
|
||||
}
|
||||
UIWindow *window = [delegate window];
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
window.alpha = 0;
|
||||
} completion:^(BOOL b){
|
||||
[window resignKeyWindow];
|
||||
window.alpha = 1;
|
||||
window.rootViewController = [[SurfaceViewController alloc] init];
|
||||
[window makeKeyAndVisible];
|
||||
}];
|
||||
id delegate = UIApplication.sharedApplication.delegate;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
delegate = UIApplication.sharedApplication.connectedScenes.anyObject.delegate;
|
||||
}
|
||||
UIWindow *window = [delegate window];
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
window.alpha = 0;
|
||||
} completion:^(BOOL b){
|
||||
[window resignKeyWindow];
|
||||
window.alpha = 1;
|
||||
window.rootViewController = [[SurfaceViewController alloc] init];
|
||||
[window makeKeyAndVisible];
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -7,7 +7,6 @@
|
||||
#import "AppDelegate.h"
|
||||
#import "customcontrols/CustomControlsUtils.h"
|
||||
#import "LauncherPreferences.h"
|
||||
#import "LauncherPreferencesViewController.h"
|
||||
|
||||
#include <libgen.h>
|
||||
#include <pthread.h>
|
||||
@@ -321,7 +320,7 @@ int main(int argc, char * argv[]) {
|
||||
|
||||
init_hookFunctions();
|
||||
|
||||
loadPreferences();
|
||||
loadPreferences(NO);
|
||||
init_setupResolvConf();
|
||||
init_setupMultiDir();
|
||||
init_setupLauncherProfiles();
|
||||
|
||||
Binary file not shown.
@@ -28,6 +28,10 @@
|
||||
#define GLFW_FOCUSED 0x00020001
|
||||
#define GLFW_VISIBLE 0x00020004
|
||||
|
||||
#define RENDERER_NAME_GL4ES "libgl4es_114.dylib"
|
||||
#define RENDERER_NAME_MTL_ANGLE "libtinygl4angle.dylib"
|
||||
#define RENDERER_NAME_VK_ZINK "libOSMesa.8.dylib"
|
||||
|
||||
#define SPECIALBTN_KEYBOARD -1
|
||||
#define SPECIALBTN_TOGGLECTRL -2
|
||||
#define SPECIALBTN_MOUSEPRI -3
|
||||
@@ -59,6 +63,7 @@ BOOL isControlModifiable;
|
||||
void init_hookFunctions();
|
||||
void init_setupMultiDir();
|
||||
|
||||
UIWindow* currentWindow();
|
||||
UIViewController* currentVC();
|
||||
|
||||
NSMutableDictionary* parseJSONFromFile(NSString *path);
|
||||
|
||||
+6
-2
@@ -43,12 +43,16 @@ BOOL getEntitlementValue(NSString *key);
|
||||
}
|
||||
@end
|
||||
|
||||
UIViewController* currentVC() {
|
||||
UIWindow* currentWindow() {
|
||||
id delegate = UIApplication.sharedApplication.delegate;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
delegate = UIApplication.sharedApplication.connectedScenes.anyObject.delegate;
|
||||
}
|
||||
return [delegate window].visibleViewController;
|
||||
return [delegate window];
|
||||
}
|
||||
|
||||
UIViewController* currentVC() {
|
||||
return currentWindow().visibleViewController;
|
||||
}
|
||||
|
||||
BOOL isJITEnabled() {
|
||||
|
||||
@@ -90,6 +90,7 @@ PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way w
|
||||
- [fishhook](https://github.com/facebook/fishhook) (jailed environment usage only): [BSD-3 License](https://github.com/facebook/fishhook/blob/main/LICENSE).
|
||||
- [Java Native Access](https://github.com/java-native-access/jna): [Apache 2.0 License](https://github.com/java-native-access/jna/blob/master/LICENSE).
|
||||
- [shaderc](https://github.com/google/shaderc) (used by mods that uses Vulkan for rendering): [Apache 2.0 License](https://github.com/google/shaderc/blob/main/LICENSE).
|
||||
- [TOInsetGroupedTableView](https://github.com/TimOliver/TOInsetGroupedTableView): [MIT License](https://github.com/TimOliver/TOInsetGroupedTableView/blob/master/LICENSE).
|
||||
|
||||
## Special thanks to MacStadium!
|
||||
This project is listed under the MacStadium Open Source Program, which allows all of us developers to keep on moving forward even without physical access to a Mac.
|
||||
|
||||
Reference in new issue
Block a user