Many changes and fixes

Changes:
- Decreased multithreaded download max threads to 10
- Moved launcher buttons to match Android UI
- Moved UIKit hooking code to separate file
- The Launcher tab is now marked as under construction.
- Updated README.md to avoid confusion between self-JIT and auto-JIT.

New settings section: UI debugging
- Unlock iPadOS UI: allow iPhone users to unlock every iPadOS-only
features (floating keyboard, popover alert, sheet-styled view
controllers, etc.)
- Show layout bounds, like the one in Android's developer setting
- Show layout overlapping

Fixes:
- App container data is not shown in the Files app due to
`no-container` entitlement, replaced it with `no-sandbox`.
- Ignore jinput-platform libraries to avoid download error
- Multithreaded assets download breaks
- `Send your logs` crashes on iPadOS
This commit is contained in:
Duy Tran Khanh committed 2022-09-22 09:52:56 +07:00
1 parent f404ddd2cb
commit b806c5df3c
14 files changed
+266 -147

No files matched your search

+1
View File
@@ -91,6 +91,7 @@ add_executable(PojavLauncher
log.m
JavaLauncher.m
external/fishhook/fishhook.c
UIKit+hook.m
authenticator/BaseAuthenticator.m
authenticator/LocalAuthenticator.m
+2
View File
@@ -115,5 +115,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UISupportsDocumentBrowser</key>
<true/>
</dict>
</plist>
+28 -11
View File
@@ -3,13 +3,17 @@
NSMutableDictionary *prefDict;
NSString* prefPath;
// developer debug dict
NSMutableDictionary *debugPrefDict;
// environment variables dict
NSMutableDictionary *envPrefDict;
// warnings dict
NSMutableDictionary *warnPrefDict;
id getPreference(NSString* key) {
if (!(envPrefDict[key] == [NSNull null] || envPrefDict[key] == nil)) {
if (!(debugPrefDict[key] == [NSNull null] || debugPrefDict[key] == nil)) {
return debugPrefDict[key];
} else if (!(envPrefDict[key] == [NSNull null] || envPrefDict[key] == nil)) {
return envPrefDict[key];
} else if (!(warnPrefDict[key] == [NSNull null] || warnPrefDict[key] == nil)) {
return warnPrefDict[key];
@@ -58,7 +62,10 @@ void setDefaultValueForPref(NSMutableDictionary *dict, NSString* key, id value)
}
void setPreference(NSString* key, id value) {
if (!(envPrefDict[key] == [NSNull null] || envPrefDict[key] == nil)) {
if (!(debugPrefDict[key] == [NSNull null] || debugPrefDict[key] == nil)) {
debugPrefDict[key] = value;
prefDict[@"debugs"] = debugPrefDict;
} else if (!(envPrefDict[key] == [NSNull null] || envPrefDict[key] == nil)) {
envPrefDict[key] = value;
prefDict[@"env_vars"] = envPrefDict;
} else if (!(warnPrefDict[key] == [NSNull null] || warnPrefDict[key] == nil)) {
@@ -79,11 +86,17 @@ void fillDefaultWarningDict() {
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);
}
NSMutableDictionary* getDictionarySafe(NSString* key) {
if (prefDict[key] == nil) {
return [[NSMutableDictionary alloc] init];
}
return prefDict[key];
}
void loadPreferences(BOOL reset) {
assert(getenv("POJAV_HOME"));
prefPath = [@(getenv("POJAV_HOME"))
@@ -91,16 +104,14 @@ void loadPreferences(BOOL reset) {
NSFileManager *fileManager = [NSFileManager defaultManager];
prefDict = [NSMutableDictionary dictionaryWithContentsOfFile:prefPath];
if (reset || ![fileManager fileExistsAtPath:prefPath]) {
if (reset) {
[prefDict removeAllObjects];
} else if (![fileManager fileExistsAtPath:prefPath]) {
prefDict = [[NSMutableDictionary alloc] init];
envPrefDict = [[NSMutableDictionary alloc] init];
warnPrefDict = [[NSMutableDictionary alloc] init];
} else {
envPrefDict = prefDict[@"env_vars"];
warnPrefDict = prefDict[@"warnings"];
}
assert(prefDict);
debugPrefDict = getDictionarySafe(@"debugs");
envPrefDict = getDictionarySafe(@"env_vars");
warnPrefDict = getDictionarySafe(@"warnings");
// set default value
setDefaultValueForPref(envPrefDict, @"resolution", @(100));
@@ -132,9 +143,15 @@ void loadPreferences(BOOL reset) {
setDefaultValueForPref(prefDict, @"disable_home_symlink", @YES);
}
// Debug settings
setDefaultValueForPref(debugPrefDict, @"debug_ipad_ui", @(UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad));
setDefaultValueForPref(debugPrefDict, @"debug_show_layout_bounds", @NO);
setDefaultValueForPref(debugPrefDict, @"debug_show_layout_overlap", @NO);
// Migrate some prefs
setPreference(@"java_home", [getPreference(@"java_home") lastPathComponent]);
prefDict[@"debugs"] = debugPrefDict;
prefDict[@"env_vars"] = envPrefDict;
prefDict[@"warnings"] = warnPrefDict;
+23 -1
View File
@@ -41,7 +41,7 @@ typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
return self.navigationController != nil;
};
self.prefSections = @[@"general", @"video", @"control", @"java"];
self.prefSections = @[@"general", @"video", @"control", @"java", @"debug"];
self.prefContents = @[
@[
@@ -209,6 +209,28 @@ typedef void(^CreateView)(UITableViewCell *, NSString *, NSDictionary *);
},
@"warnKey": @"mem_warn"
}
], @[
@{@"key": @"debug_ipad_ui",
@"hasDetail": @YES,
@"icon": @"ipad",
@"type": self.typeSwitch,
@"enableCondition": whenNotInGame
},
@{@"key": @"debug_show_layout_bounds",
@"hasDetail": @YES,
@"icon": @"square.dashed",
@"type": self.typeSwitch,
@"enableCondition": whenNotInGame,
@"requestReload": @YES
},
@{@"key": @"debug_show_layout_overlap",
@"hasDetail": @YES,
@"icon": @"square.on.square",
@"type": self.typeSwitch,
@"enableCondition": ^BOOL(){
return [getPreference(@"debug_show_layout_bounds") boolValue] && whenNotInGame();
}
}
]
];
+1
View File
@@ -18,6 +18,7 @@
LauncherMenuViewController *masterVc = [[LauncherMenuViewController alloc] init];
UINavigationController *detailVc = [[UINavigationController alloc] init];
detailVc.toolbarHidden = NO;
self.presentsWithGesture = YES;
self.preferredDisplayMode = UISplitViewControllerDisplayModeOneBesideSecondary;
+55 -75
View File
@@ -8,6 +8,8 @@
#include "utils.h"
#define AUTORESIZE_MASKS UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin
@interface LauncherViewController () <UIDocumentPickerDelegate, UIPickerViewDataSource, UIPickerViewDelegate, UIPopoverPresentationControllerDelegate> {
}
@@ -29,28 +31,25 @@ int versionSelectedAt = 0;
[self setNeedsUpdateOfScreenEdgesDeferringSystemGestures];
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
CGRect screenBounds = self.view.frame;
int width = (int) roundf(screenBounds.size.width);
int height = (int) roundf(screenBounds.size.height) - self.navigationController.navigationBar.frame.size.height;
UIToolbar *toolbar = self.navigationController.toolbar;
CGFloat splitWidth = toolbar.frame.size.width / 3;
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
[self.view addSubview:scrollView];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UILabel *versionTextView = [[UILabel alloc] initWithFrame:CGRectMake(4.0, 4.0, 0.0, 0.0)];
versionTextView.text = @"Minecraft version: ";
versionTextView.text = @"[under construction]";
versionTextView.numberOfLines = 0;
[versionTextView sizeToFit];
[scrollView addSubview:versionTextView];
versionTextField = [[UITextField alloc] initWithFrame:CGRectMake(versionTextView.bounds.size.width + 4.0, 4.0, width - versionTextView.bounds.size.width - 8.0, height - 58.0)];
versionTextField = [[UITextField alloc] initWithFrame:CGRectMake(0, 4, splitWidth, toolbar.frame.size.height/2 - 4)];
[versionTextField addTarget:versionTextField action:@selector(resignFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
versionTextField.autoresizingMask = AUTORESIZE_MASKS;
versionTextField.placeholder = @"Specify version...";
versionTextField.text = (NSString *) getPreference(@"selected_version");
versionTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
versionTextField.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
versionTextField.textAlignment = NSTextAlignmentCenter;
self.versionList = [[NSMutableArray alloc] init];
versionPickerView = [[UIPickerView alloc] init];
@@ -75,40 +74,47 @@ int versionSelectedAt = 0;
versionTextField.inputAccessoryView = versionPickToolbar;
versionTextField.inputView = versionPickerView;
[scrollView addSubview:versionTextField];
[toolbar addSubview:versionTextField];
if (@available(iOS 14.0, *)) {
// use UIMenu
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[[UIImage systemImageNamed:@"ellipsis.circle"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] style:UIBarButtonItemStyleDone target:self action:@selector(displayOptions:)];
UIAction *option1 = [UIAction actionWithTitle:@"Launch a mod installer" image:[[UIImage systemImageNamed:@"internaldrive"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil
handler:^(__kindof UIAction * _Nonnull action) {[self enterModInstaller:self.navigationItem.rightBarButtonItem];}];
UIAction *option2 = [UIAction actionWithTitle:@"Custom controls" image:[[UIImage systemImageNamed:@"dpad.right.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] identifier:nil
handler:^(__kindof UIAction * _Nonnull action) {[self enterCustomControls];}];
UIMenu *menu = [UIMenu menuWithTitle:@"" image:nil identifier:nil
options:UIMenuOptionsDisplayInline children:@[option1, option2]];
self.navigationItem.rightBarButtonItem.action = nil;
self.navigationItem.rightBarButtonItem.primaryAction = nil;
self.navigationItem.rightBarButtonItem.menu = menu;
} else {
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Options" style:UIBarButtonItemStyleDone target:self action:@selector(displayOptions:)];
}
self.progressViewMain = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, toolbar.frame.size.width, 4.0)];
self.progressViewSub = [[UIProgressView alloc] initWithFrame:CGRectMake(0, toolbar.frame.size.height - 4.0, toolbar.frame.size.width, 4.0)];
self.progressViewMain.autoresizingMask = self.progressViewSub.autoresizingMask = AUTORESIZE_MASKS;
self.progressViewMain.hidden = self.progressViewSub.hidden = YES;
[toolbar addSubview:self.progressViewMain];
[toolbar addSubview:self.progressViewSub];
self.progressViewMain = [[UIProgressView alloc] initWithFrame:CGRectMake(4.0, height - 58.0, width - 8.0, 6.0)];
self.progressViewSub = [[UIProgressView alloc] initWithFrame:CGRectMake(4.0, height - 58.0, width - 8.0, 6.0)];
self.progressViewMain.alpha = 0.6;
self.progressViewSub.alpha = 0.4;
[scrollView addSubview:self.progressViewSub];
[scrollView addSubview:self.progressViewMain];
self.buttonInstall = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.buttonInstall = [UIButton buttonWithType:UIButtonTypeSystem];
self.buttonInstall.enabled = NO;
[self.buttonInstall setTitle:@"Play" forState:UIControlStateNormal];
self.buttonInstall.frame = CGRectMake(10.0, height - 54.0, 100.0, 50.0);
[self.buttonInstall setTitle:NSLocalizedString(@"Play", nil) forState:UIControlStateNormal];
self.buttonInstall.autoresizingMask = AUTORESIZE_MASKS;
self.buttonInstall.backgroundColor = [UIColor colorWithRed:54/255.0 green:176/255.0 blue:48/255.0 alpha:1.0];
self.buttonInstall.layer.cornerRadius = 5;
self.buttonInstall.frame = CGRectMake(splitWidth, 6.0, splitWidth, toolbar.frame.size.height - 12.0);
self.buttonInstall.tintColor = UIColor.whiteColor;
[self.buttonInstall addTarget:self action:@selector(launchMinecraft:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:self.buttonInstall];
self.progressText = [[UILabel alloc] initWithFrame:CGRectMake(120.0, height - 54.0, width - 124.0, 50.0)];
[scrollView addSubview:self.progressText];
[toolbar addSubview:self.buttonInstall];
UIButton *buttonCustomControls = [UIButton buttonWithType:UIButtonTypeSystem];
[buttonCustomControls setTitle:NSLocalizedString(@"launcher.menu.custom_controls", nil) forState:UIControlStateNormal];
buttonCustomControls.autoresizingMask = AUTORESIZE_MASKS;
buttonCustomControls.frame = CGRectMake(0, toolbar.frame.size.height/2, splitWidth, toolbar.frame.size.height/2);
[buttonCustomControls addTarget:self action:@selector(enterCustomControls) forControlEvents:UIControlEventTouchUpInside];
[toolbar addSubview:buttonCustomControls];
UIButton *buttonInstallJar = [UIButton buttonWithType:UIButtonTypeSystem];
[buttonInstallJar setTitle:NSLocalizedString(@"launcher.menu.install_jar", nil) forState:UIControlStateNormal];
buttonInstallJar.autoresizingMask = AUTORESIZE_MASKS;
buttonInstallJar.frame = CGRectMake(splitWidth*2, toolbar.frame.size.height/2, splitWidth, toolbar.frame.size.height/2);
[buttonInstallJar addTarget:self action:@selector(enterModInstaller) forControlEvents:UIControlEventTouchUpInside];
[toolbar addSubview:buttonInstallJar];
self.progressText = [[UILabel alloc] initWithFrame:CGRectMake(0, 4, toolbar.frame.size.width, 20)];
self.progressText.adjustsFontSizeToFitWidth = YES;
self.progressText.autoresizingMask = AUTORESIZE_MASKS;
self.progressText.font = [self.progressText.font fontWithSize:16];
self.progressText.textAlignment = NSTextAlignmentCenter;
self.progressText.userInteractionEnabled = NO;
[toolbar addSubview:self.progressText];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -216,45 +222,14 @@ int versionSelectedAt = 0;
[self reloadVersionList:sender.selectedSegmentIndex];
}
#pragma mark - Button click events
- (void)displayOptions:(UIBarButtonItem*)sender {
if (@available(iOS 14.0, *)) {
// use UIMenu
} else {
// use UIAlertController
UIAlertController *fullAlert = [UIAlertController alertControllerWithTitle:@"Options" message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *option1 = [UIAlertAction actionWithTitle:@"Launch a mod installer" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {[self enterModInstaller:self.navigationItem.rightBarButtonItem];}];
UIAlertAction *option2 = [UIAlertAction actionWithTitle:@"Custom controls" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {[self enterCustomControls];}];
fullAlert.popoverPresentationController.barButtonItem = sender;
[self presentViewController:fullAlert animated:YES completion:nil];
[fullAlert addAction:option1];
[fullAlert addAction:option2];
}
}
#pragma mark - Options
- (void)enterCustomControls {
if (![getPreference(@"customctrl_warn") boolValue]) {
CustomControlsViewController *vc = [[CustomControlsViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:vc animated:YES completion:nil];
return;
}
setPreference(@"customctrl_warn", @(NO));
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"This option is unfinished, some might be incomplete or missing." preferredStyle:UIAlertControllerStyleActionSheet];
if (alert.popoverPresentationController != nil) {
alert.popoverPresentationController.sourceView = self.view;
alert.popoverPresentationController.sourceRect = CGRectMake(self.view.frame.size.width-10.0, 0, 10, 10);
}
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[self enterCustomControls];
}];
[self presentViewController:alert animated:YES completion:nil];
[alert addAction:ok];
CustomControlsViewController *vc = [[CustomControlsViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:vc animated:YES completion:nil];
}
- (void)enterModInstaller:(UIBarButtonItem*)sender {
- (void)enterModInstaller {
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"com.sun.java-archive"]
inMode:UIDocumentPickerModeImport];
documentPicker.delegate = self;
@@ -277,7 +252,9 @@ int versionSelectedAt = 0;
return;
}
sender.alpha = 0.5;
sender.enabled = NO;
self.progressViewMain.hidden = self.progressViewSub.hidden = NO;
NSObject *object = [self.versionList objectAtIndex:[versionPickerView selectedRowInComponent:0]];
@@ -288,7 +265,10 @@ int versionSelectedAt = 0;
self.progressViewMain.observedProgress = mainProgress;
self.progressViewSub.observedProgress = progress;
if (stage == nil) {
sender.alpha = 1;
sender.enabled = YES;
self.progressText.text = nil;
self.progressViewMain.hidden = self.progressViewSub.hidden = YES;
if (mainProgress != nil) {
UIKit_launchMinecraftSurfaceVC();
}
+4 -8
View File
@@ -24,15 +24,10 @@
extern NSMutableDictionary *prefDict;
#pragma mark - LoginViewController
@interface LoginViewController () <ASWebAuthenticationPresentationContextProviding>{
}
@property (nonatomic, strong) ASWebAuthenticationSession *authVC;
@property (nonatomic, strong) UIActivityViewController *activityViewController;
@interface LoginViewController () <ASWebAuthenticationPresentationContextProviding> {}
@end
@implementation LoginViewController
@synthesize authVC;
@synthesize activityViewController;
- (void)viewDidLoad {
[super viewDidLoad];
@@ -268,7 +263,7 @@ extern NSMutableDictionary *prefDict;
- (void)loginMicrosoft {
NSURL *url = [NSURL URLWithString:@"https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_url=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf"];
authVC =
ASWebAuthenticationSession *authVC =
[[ASWebAuthenticationSession alloc] initWithURL:url
callbackURLScheme:@"ms-xal-00000000402b5328"
completionHandler:^(NSURL * _Nullable callbackURL,
@@ -434,7 +429,8 @@ extern NSMutableDictionary *prefDict;
{
NSString *latestlogPath = [NSString stringWithFormat:@"file://%s/latestlog.old.txt", getenv("POJAV_HOME")];
NSLog(@"Path is %@", latestlogPath);
activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[@"latestlog.txt", [NSURL URLWithString:latestlogPath]] applicationActivities:nil];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[@"latestlog.txt", [NSURL URLWithString:latestlogPath]] applicationActivities:nil];
activityViewController.popoverPresentationController.barButtonItem = self.navigationItem.rightBarButtonItems[0];
[self presentViewController:activityViewController animated:YES completion:nil];
}
+6 -2
View File
@@ -283,6 +283,7 @@ static AFURLSessionManager* manager;
library[@"skip"] = @(
// Exclude platform-dependant libraries
library[@"downloads"][@"classifiers"] != nil ||
library[@"natives"] != nil ||
// Exclude LWJGL libraries
[library[@"name"] hasPrefix:@"org.lwjgl"]
);
@@ -379,12 +380,15 @@ static AFURLSessionManager* manager;
dispatch_group_t group = dispatch_group_create();
int downloadIndex = -1;
__block int jobsAvailable = 20;
__block int jobsAvailable = 10;
for (NSString *name in assets[@"objects"]) {
if (jobsAvailable < 0) {
break;
} else if (jobsAvailable == 0) {
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
while (jobsAvailable == 0) {
usleep(50000);
}
}
NSString *hash = assets[@"objects"][name][@"hash"];
+124
View File
@@ -0,0 +1,124 @@
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#import "LauncherPreferences.h"
void swizzle(Class class, SEL originalAction, SEL swizzledAction) {
method_exchangeImplementations(class_getInstanceMethod(class, originalAction), class_getInstanceMethod(class, swizzledAction));
}
__attribute__((constructor)) void hookConstructor(void) {
swizzle(UIDevice.class, @selector(userInterfaceIdiom), @selector(hook_userInterfaceIdiom));
swizzle(UIToolbar.class, @selector(sizeThatFits:), @selector(hook_sizeThatFits:));
swizzle(UIView.class, @selector(didMoveToSuperview), @selector(hook_didMoveToSuperview));
swizzle(UIView.class, @selector(setFrame:), @selector(hook_setFrame:));
}
@implementation UIDevice(hook)
- (UIUserInterfaceIdiom)hook_userInterfaceIdiom {
id value = getPreference(@"debug_ipad_ui");
if (value == nil) {
return self.hook_userInterfaceIdiom;
}
return [value boolValue] ? UIUserInterfaceIdiomPad : UIUserInterfaceIdiomPhone;
}
@end
@implementation UIToolbar(hook)
- (CGSize)hook_sizeThatFits:(CGSize)size {
// Make the toolbar taller
CGSize ret = [self hook_sizeThatFits:size];
ret.height += 50;
return ret;
}
@end
@implementation UIView(hook)
const NSString *cornerLayerKey = @"cornerLayer";
- (void)updateCornerLayer {
CAShapeLayer *cornerLayer = objc_getAssociatedObject(self, &cornerLayerKey);
NSNumber *cornerWidth = @5;
NSNumber *cornerSpaceW = @(self.frame.size.width-10);
NSNumber *cornerSpaceH = @(self.frame.size.height-10);
cornerLayer.lineDashPattern = @[cornerWidth,cornerSpaceW,cornerWidth,@0,cornerWidth,cornerSpaceH,cornerWidth,@0,cornerWidth,cornerSpaceW,cornerWidth,@0,cornerWidth,cornerSpaceH,cornerWidth];
cornerLayer.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)].CGPath;
if ([getPreference(@"debug_show_layout_overlap") boolValue]) {
cornerLayer.fillColor = [UIColor.yellowColor colorWithAlphaComponent:0.1].CGColor;
} else {
cornerLayer.fillColor = nil;
}
}
- (void)hook_didMoveToSuperview {
if ([getPreference(@"debug_show_layout_bounds") boolValue]) {
self.layer.borderWidth = 1;
self.layer.borderColor = UIColor.redColor.CGColor;
if (self.layer.sublayers.count == 0) {
CAShapeLayer *cornerLayer = [CAShapeLayer layer];
cornerLayer.strokeColor = UIColor.blueColor.CGColor;
cornerLayer.lineWidth = 1;
[self.layer addSublayer:cornerLayer];
objc_setAssociatedObject(self, &cornerLayerKey, cornerLayer, OBJC_ASSOCIATION_ASSIGN);
[self updateCornerLayer];
}
}
[self hook_didMoveToSuperview];
}
- (void)hook_setFrame:(CGRect)frame {
[self hook_setFrame:frame];
[self updateCornerLayer];
}
@end
@implementation UIWindow(hook)
// Simulate safe area on iPhones without notch
/*
- (UIEdgeInsets)safeAreaInsets {
return UIEdgeInsetsMake(0, 44, 21, 44);
}
*/
- (UIViewController *)visibleViewController {
UIViewController *current = self.rootViewController;
while (current.presentedViewController) {
if ([current.presentedViewController isKindOfClass:UIAlertController.class] || [current.presentedViewController isKindOfClass:NSClassFromString(@"UIInputWindowController")]) {
break;
}
current = current.presentedViewController;
}
if ([current isKindOfClass:UINavigationController.class]) {
return [(UINavigationController *)self.rootViewController visibleViewController];
} else {
return current;
}
}
@end
// This forces the navigation bar to keep its height (44dp) in landscape
@implementation UINavigationBar(forceFullHeightInLandscape)
- (BOOL)forceFullHeightInLandscape {
return YES;
//UIScreen.mainScreen.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPhone;
}
@end
UIWindow* currentWindow() {
id delegate = UIApplication.sharedApplication.delegate;
if (@available(iOS 13.0, *)) {
delegate = UIApplication.sharedApplication.connectedScenes.anyObject.delegate;
}
return [delegate window];
}
UIViewController* currentVC() {
return currentWindow().visibleViewController;
}
+18
View File
@@ -8,6 +8,12 @@
"game.menu.log_output" = "Log output";
"game.menu.custom_controls" = "Custom controls";
// The options button at the top-right corner on iOS 12
"Options" = "Options";
// The play button
"Play" = "Play";
// Version categories
"Installed" = "Installed";
"Snapshot" = "Snapshot";
@@ -17,6 +23,9 @@
"init.migrateDir" = "The PojavLauncher data directory is now %@. All of your existing data has been moved to the new location.";
"launcher.menu.custom_controls" = "Custom controls";
"launcher.menu.install_jar" = "Install .jar";
"login.error.username.outOfRange" = "Username must be at least 3 characters and maximum 16 characters";
"login.alert.field.username" = "Username";
@@ -80,6 +89,8 @@
"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.debug" = "UI Debugging settings";
"preference.section.footer.debug" = "Aside from debugging, these settings may be useful for custom controls. You may need to restart the launcher for changes to take effect.";
//"preference.section.footer.control" = "";
"preference.section.java" = "Java Tweaks";
//"preference.section.footer.java" = "";
@@ -141,3 +152,10 @@
"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.";
"preference.title.debug_ipad_ui" = "Unlock iPadOS UI";
"preference.detail.debug_ipad_ui" = "Unlock iPad-exlusive UI (alert, keyboard, etc.) if enabled or iPhone UI if disabled.";
"preference.title.debug_show_layout_bounds" = "Show layout bounds";
"preference.detail.debug_show_layout_bounds" = "Show clip bounds, margins";
"preference.title.debug_show_layout_overlap" = "Show layout overlapping";
"preference.detail.debug_show_layout_overlap" = "Overlay every view with a transparent color to reveal overlapping views.";
+2 -2
View File
@@ -124,7 +124,7 @@ void init_logDeviceAndVer(char *argument) {
regLog("[Pre-init] Entitlements availability:");
printEntitlementAvailability(@"com.apple.developer.kernel.extended-virtual-addressing");
printEntitlementAvailability(@"com.apple.developer.kernel.increased-memory-limit");
printEntitlementAvailability(@"com.apple.private.security.no-container");
printEntitlementAvailability(@"com.apple.private.security.no-sandbox");
printEntitlementAvailability(@"dynamic-codesigning");
}
@@ -341,7 +341,7 @@ int main(int argc, char * argv[]) {
init_migrateToPlist("java_args", "overrideargs.txt");
// If sandbox is disabled, W^X JIT can be enabled by PojavLauncher itself
if (getEntitlementValue(@"com.apple.private.security.no-container")) {
if (getEntitlementValue(@"com.apple.private.security.no-sandbox")) {
NSLog(@"[Pre-init] Sandbox is disabled, trying to enable JIT");
int pid;
int ret = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ);
-46
View File
@@ -9,52 +9,6 @@
BOOL getEntitlementValue(NSString *key);
@implementation UIWindow(ext)
// Simulate safe area on iPhones without notch
/*
- (UIEdgeInsets)safeAreaInsets {
return UIEdgeInsetsMake(0, 44, 21, 44);
}
*/
- (UIViewController *)visibleViewController {
UIViewController *current = self.rootViewController;
while (current.presentedViewController) {
if ([current.presentedViewController isKindOfClass:UIAlertController.class] || [current.presentedViewController isKindOfClass:NSClassFromString(@"UIInputWindowController")]) {
break;
}
current = current.presentedViewController;
}
if ([current isKindOfClass:UINavigationController.class]) {
return [(UINavigationController *)self.rootViewController visibleViewController];
} else {
return current;
}
}
@end
// This forces the navigation bar to keep its height (44dp) in landscape
@implementation UINavigationBar(forceFullHeightInLandscape)
- (BOOL)forceFullHeightInLandscape {
return UIScreen.mainScreen.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomPhone;
}
@end
UIWindow* currentWindow() {
id delegate = UIApplication.sharedApplication.delegate;
if (@available(iOS 13.0, *)) {
delegate = UIApplication.sharedApplication.connectedScenes.anyObject.delegate;
}
return [delegate window];
}
UIViewController* currentVC() {
return currentWindow().visibleViewController;
}
BOOL isJITEnabled() {
if (getEntitlementValue(@"dynamic-codesigning")) {
return YES;
+1 -1
View File
@@ -25,7 +25,7 @@ The [PojavLauncher Website](https://pojav.ml) has extensive documentation on how
Note: This is experimental, although game works smoothly, you should not set Render distance too much.
1. Setup the sideload app
- For iOS 14.0-15.5beta4 on compatible devices, [TrollStore](https://github.com/opa334/TrollStore) is recommended to keep PojavLauncher permanently signed and have JIT automatically enabled.
- For iOS 14.0-15.5beta4 on compatible devices, [TrollStore](https://github.com/opa334/TrollStore) is recommended to keep PojavLauncher permanently signed and have JIT enabled by itself.
- Otherwise, install [AltStore](https://altstore.io). Others will also work.
2. Download an IPA build of PojavLauncher in the Actions tab.
3. Open the downloaded IPA in the sideload app to install.
+1 -1
View File
@@ -18,7 +18,7 @@
<true/>
<!-- Disable sandbox so that PojavLauncher can enable JIT by itself -->
<key>com.apple.private.security.no-container</key>
<key>com.apple.private.security.no-sandbox</key>
<true/>
<!-- The following entitlements are required if sandbox is disabled -->