* Feat: external runtime manager Currently missing: mmap hook * we're past this ui todo * feat: Bypass Library Validation (untested) This bypass works because of JIT enabled, so the process can patch anything loaded in the memory. Unsigned dylib works with JIT too. * Fix `could not get real path` on iOS 14.x iOS 15+ is untested, it may need patching in dyld instead of libSystem * Make redirectFunction syscall-friendly Replaced builtin_mprotect and vm_protect with a simple syscall to _kernelrpc_mach_vm_protect_trap * Add dyld hook back for iOS 15+, auto symlink xawt lib * Cleanup Tools.java:showError+comments Use System.exit(1) to drop to Game Exited screen instead of presenting alert dialog on exception handled. * Patch both to bypass codesigning at best * Proper way of ignoring SIGBUS during patch Turns out other background thread might also be calling inside dirty page, so let's SIG_IGN them all until page permission is back to RX. * Feat(install jar): auto detect java version Rename Default version to Preferred version to match the behavior or Install .jar detection: only override if selected version > required version. Add UnzipKit just to check jar file Refactor(showDialog): remove viewController parameter, now use its own ViewController to present. * Feat: update LWJGL to 3.3.1 (tinygl4angle) add alias for GL_KHR_debug functions Include nanovg for OneConfig mod Move all LWJGLX classes to lwjgl3 repo Set org.lwjgl.util.NoChecks=true to improve performance * Fix: Forge 1.20 crashes (wrong artifact path) Now use json-provided artifact path instead of generating one Make lwjgl fat jar again * Fix: handle null library artifact * Fix: fatal glfw callback cleanup * Build: fix copying LWJGL libraries * Perf: set default settings * Fix: incorrect SolClient useStackQueue check * Feat: builtin runtime installer Refactor parts of LauncherNavigationController.m Workaround(LogView): disable animation on update to mitigate overload * Fix: random game directory failures This is caused by having current working directory unchanged after re-making symlink. * Fixes: TL-style artifact, update arc_dns_injector Change pojavInit names * Fix: 1.13+ isUseStackQueueCall check * Build: update liblwjgl.dylib in attempt to fix ffi_closure_alloc * Fix and improvements to the logger - Dynamically get stdout/stderr fileno instead of fixed value - Improve file migration logging - Improve dyld bypass logging * Fix(pickers): file permission issue --------- Co-authored-by: Duy Tran Khanh <[email protected]>
230 lines
9.4 KiB
Objective-C
230 lines
9.4 KiB
Objective-C
#import "SurfaceViewController.h"
|
|
#import "utils.h"
|
|
|
|
static BOOL fatalErrorOccurred;
|
|
|
|
extern UIWindow* currentWindow();
|
|
|
|
@interface LogDelegate : NSObject
|
|
@end
|
|
|
|
@interface LogDelegate()<UITableViewDataSource, UITableViewDelegate>
|
|
@end
|
|
|
|
static NSMutableArray* logLines;
|
|
|
|
@implementation LogDelegate
|
|
|
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
|
return logLines.count;
|
|
}
|
|
|
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
|
|
|
|
if (cell == nil) {
|
|
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
|
|
cell.backgroundColor = UIColor.clearColor;
|
|
//cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
cell.textLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:16];
|
|
cell.textLabel.textColor = UIColor.whiteColor;
|
|
}
|
|
cell.textLabel.text = logLines[indexPath.row];
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
|
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
|
|
|
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
|
NSString *line = cell.textLabel.text;
|
|
if (line.length == 0 || [line isEqualToString:@"\n"]) {
|
|
return;
|
|
}
|
|
|
|
SurfaceViewController *vc = (id)currentWindow().rootViewController;
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:line preferredStyle:UIAlertControllerStyleActionSheet];
|
|
alert.popoverPresentationController.sourceView = cell;
|
|
alert.popoverPresentationController.sourceRect = cell.bounds;
|
|
UIAlertAction *share = [UIAlertAction actionWithTitle:localize(localize(@"Share", nil), nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
|
UIView *navigationBar = vc.logOutputView.subviews[1];
|
|
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[line] applicationActivities:nil];
|
|
activityVC.popoverPresentationController.sourceView = navigationBar;
|
|
activityVC.popoverPresentationController.sourceRect = navigationBar.bounds;
|
|
[vc presentViewController:activityVC animated:YES completion:nil];
|
|
}];
|
|
UIAlertAction *cancel = [UIAlertAction actionWithTitle:localize(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil];
|
|
[alert addAction:share];
|
|
[alert addAction:cancel];
|
|
[vc presentViewController:alert animated:YES completion:nil];
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation SurfaceViewController(LogView)
|
|
|
|
static LogDelegate* logDelegate;
|
|
static int logCharPerLine;
|
|
|
|
- (void)initCategory_LogView {
|
|
logLines = NSMutableArray.new;
|
|
logCharPerLine = self.view.frame.size.width / 10;
|
|
|
|
self.logOutputView = [[UIView alloc] initWithFrame:CGRectOffset(self.view.frame, 0, self.view.frame.size.height)];
|
|
self.logOutputView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
|
|
self.logOutputView.hidden = YES;
|
|
|
|
UINavigationItem *navigationItem = [[UINavigationItem alloc] init];
|
|
navigationItem.rightBarButtonItems = @[
|
|
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
|
|
target:self action:@selector(actionToggleLogOutput)],
|
|
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
|
|
target:self action:@selector(actionClearLogOutput)]
|
|
];
|
|
UINavigationBar* navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
|
|
navigationBar.items = @[navigationItem];
|
|
navigationBar.topItem.title = localize(@"game.menu.log_output", nil);
|
|
[navigationBar sizeToFit];
|
|
navigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
|
|
|
self.logTableView = [[UITableView alloc] initWithFrame:self.view.frame];
|
|
logDelegate = [[LogDelegate alloc] init];
|
|
//self.logTableView.allowsSelection = NO;
|
|
self.logTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
|
self.logTableView.backgroundColor = UIColor.clearColor;
|
|
self.logTableView.contentInset = UIEdgeInsetsMake(navigationBar.frame.size.height, 0, 0, 0);
|
|
self.logTableView.dataSource = logDelegate;
|
|
self.logTableView.delegate = logDelegate;
|
|
self.logTableView.layoutMargins = UIEdgeInsetsZero;
|
|
self.logTableView.rowHeight = 20;
|
|
self.logTableView.separatorInset = UIEdgeInsetsZero;
|
|
self.logTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
|
[self.logOutputView addSubview:self.logTableView];
|
|
[self.logOutputView addSubview:navigationBar];
|
|
[self.rootView addSubview:self.logOutputView];
|
|
|
|
canAppendToLog = YES;
|
|
[self actionStartStopLogOutput];
|
|
}
|
|
|
|
- (void)actionClearLogOutput {
|
|
[logLines removeAllObjects];
|
|
[self.logTableView reloadData];
|
|
}
|
|
|
|
- (void)actionShareLatestlog {
|
|
UINavigationBar *navigationBar = self.logOutputView.subviews[1];
|
|
NSString *latestlogPath = [NSString stringWithFormat:@"file://%s/latestlog.txt", getenv("POJAV_HOME")];
|
|
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[@"latestlog.txt",
|
|
[NSURL URLWithString:latestlogPath]] applicationActivities:nil];
|
|
activityVC.popoverPresentationController.sourceView = navigationBar;
|
|
activityVC.popoverPresentationController.sourceRect = navigationBar.bounds;
|
|
[self presentViewController:activityVC animated:YES completion:nil];
|
|
}
|
|
|
|
- (void)actionStartStopLogOutput {
|
|
canAppendToLog = !canAppendToLog;
|
|
UINavigationItem* item = ((UINavigationBar *)self.logOutputView.subviews[1]).items[0];
|
|
item.leftBarButtonItem =
|
|
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:
|
|
canAppendToLog ? UIBarButtonSystemItemPause : UIBarButtonSystemItemPlay
|
|
target:self action:@selector(actionStartStopLogOutput)];
|
|
}
|
|
|
|
- (void)actionToggleLogOutput {
|
|
if (fatalErrorOccurred) {
|
|
[self performSelector:@selector(actionForceClose)];
|
|
return;
|
|
}
|
|
|
|
UIViewAnimationOptions opt = self.logOutputView.hidden ? UIViewAnimationOptionCurveEaseOut : UIViewAnimationOptionCurveEaseIn;
|
|
[UIView transitionWithView:self.logOutputView duration:0.4 options:UIViewAnimationOptionCurveEaseOut animations:^(void){
|
|
CGRect frame = self.logOutputView.frame;
|
|
frame.origin.y = self.logOutputView.hidden ? 0 : frame.size.height;
|
|
self.logOutputView.hidden = NO;
|
|
self.logOutputView.frame = frame;
|
|
} completion: ^(BOOL finished) {
|
|
self.logOutputView.hidden = self.logOutputView.frame.origin.y != 0;
|
|
}];
|
|
}
|
|
|
|
+ (void)_appendToLog:(NSString *)line {
|
|
if (line.length == 0) {
|
|
return;
|
|
}
|
|
|
|
SurfaceViewController *instance = (id)currentWindow().rootViewController;
|
|
|
|
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:logLines.count inSection:0];
|
|
[logLines addObject:line];
|
|
UIView.animationsEnabled = NO;
|
|
[instance.logTableView beginUpdates];
|
|
[instance.logTableView
|
|
insertRowsAtIndexPaths:@[indexPath]
|
|
withRowAnimation:UITableViewRowAnimationNone];
|
|
[instance.logTableView endUpdates];
|
|
UIView.animationsEnabled = YES;
|
|
|
|
[instance.logTableView
|
|
scrollToRowAtIndexPath:indexPath
|
|
atScrollPosition:UITableViewScrollPositionBottom animated:NO];
|
|
}
|
|
|
|
+ (void)appendToLog:(NSString *)string {
|
|
dispatch_async(dispatch_get_main_queue(), ^(void){
|
|
NSArray *lines = [string componentsSeparatedByCharactersInSet:
|
|
NSCharacterSet.newlineCharacterSet];
|
|
for (NSString *line in lines) {
|
|
[self _appendToLog:line];
|
|
}
|
|
});
|
|
}
|
|
|
|
+ (void)handleExitCode:(int)code {
|
|
dispatch_async(dispatch_get_main_queue(), ^(void){
|
|
SurfaceViewController *instance = (id)currentWindow().rootViewController;
|
|
|
|
if (instance.logOutputView.hidden) {
|
|
[instance actionToggleLogOutput];
|
|
}
|
|
// Cleanup navigation bar
|
|
UINavigationBar *navigationBar = instance.logOutputView.subviews[1];
|
|
navigationBar.topItem.title = [NSString stringWithFormat:
|
|
localize(@"game.title.exit_code", nil), code];
|
|
navigationBar.items[0].leftBarButtonItem = [[UIBarButtonItem alloc]
|
|
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
|
|
target:instance action:@selector(actionShareLatestlog)];
|
|
UIBarButtonItem *exitItem = navigationBar.items[0].rightBarButtonItems[0];
|
|
navigationBar.items[0].rightBarButtonItems = nil;
|
|
navigationBar.items[0].rightBarButtonItem = exitItem;
|
|
|
|
if (canAppendToLog) {
|
|
canAppendToLog = NO;
|
|
fatalErrorOccurred = YES;
|
|
return;
|
|
}
|
|
[instance actionClearLogOutput];
|
|
[self _appendToLog:@"... (latestlog.txt)"];
|
|
NSString *latestlogPath = [NSString stringWithFormat:@"%s/latestlog.txt", getenv("POJAV_HOME")];
|
|
NSString *linesStr = [NSString stringWithContentsOfFile:latestlogPath
|
|
encoding:NSUTF8StringEncoding error:nil];
|
|
NSArray *lines = [linesStr componentsSeparatedByCharactersInSet:
|
|
NSCharacterSet.newlineCharacterSet];
|
|
|
|
// Print last 100 lines from latestlog.txt
|
|
for (int i = MAX(lines.count-100, 0); i < lines.count; i++) {
|
|
[self _appendToLog:lines[i]];
|
|
}
|
|
|
|
fatalErrorOccurred = YES;
|
|
});
|
|
}
|
|
|
|
- (void)viewWillTransitionToSize_LogView:(CGRect)frame {
|
|
self.logOutputView.frame = frame;
|
|
}
|
|
|
|
@end
|