Skip to content

Commit

Permalink
[WIP] Add modpack installation
Browse files Browse the repository at this point in the history
Added Modrinth, Fabric/Quilt automated installation
  • Loading branch information
khanhduytran0 committed Feb 14, 2024
1 parent 42cb6a0 commit 4c075f6
Show file tree
Hide file tree
Showing 25 changed files with 682 additions and 76 deletions.
6 changes: 6 additions & 0 deletions Natives/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ add_executable(PojavLauncher

installer/FabricInstallViewController.m
installer/ForgeInstallViewController.m
installer/ModpackInstallViewController.m
installer/FabricUtils.m
installer/modpack/ModpackUtils.m
installer/modpack/ModpackAPI.m
installer/modpack/CurseForgeAPI.m
installer/modpack/ModrinthAPI.m

input/ControllerInput.m
input/GyroInput.m
Expand Down
73 changes: 55 additions & 18 deletions Natives/LauncherNavigationController.m
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ - (void)viewDidLoad
self.buttonInstall.layer.cornerRadius = 5;
self.buttonInstall.frame = CGRectMake(self.toolbar.frame.size.width * 0.8, 4, self.toolbar.frame.size.width * 0.2, self.toolbar.frame.size.height - 8);
self.buttonInstall.tintColor = UIColor.whiteColor;
self.buttonInstall.enabled = NO;
[self.buttonInstall addTarget:self action:@selector(performInstallOrShowDetails:) forControlEvents:UIControlEventPrimaryActionTriggered];
[targetToolbar addSubview:self.buttonInstall];

Expand All @@ -94,9 +95,11 @@ - (void)viewDidLoad
self.progressText.userInteractionEnabled = NO;
[targetToolbar addSubview:self.progressText];

self.buttonInstall.enabled = NO;

[self fetchRemoteVersionList];
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(receiveNotification:)
name:@"InstallModpack"
object:nil];

if ([BaseAuthenticator.current isKindOfClass:MicrosoftAuthenticator.class]) {
// Perform token refreshment on startup
Expand Down Expand Up @@ -230,6 +233,7 @@ - (void)setInteractionEnabled:(BOOL)enabled forDownloading:(BOOL)downloading {
self.buttonInstall.alpha = 1;
self.buttonInstall.enabled = YES;
}
UIApplication.sharedApplication.idleTimerDisabled = !enabled;
}

- (void)launchMinecraft:(UIButton *)sender {
Expand All @@ -251,7 +255,10 @@ - (void)launchMinecraft:(UIButton *)sender {
NSString *versionId = PLProfiles.current.profiles[self.versionTextField.text][@"lastVersionId"];
NSDictionary *object = [remoteVersionList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(id == %@)", versionId]].firstObject;
if (!object) {
object = [localVersionList filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(id == %@)", versionId]].firstObject;
object = @{
@"id": versionId,
@"type": @"custom"
};
}

self.task = [MinecraftResourceDownloadTask new];
Expand Down Expand Up @@ -290,20 +297,53 @@ - (void)performInstallOrShowDetails:(UIButton *)sender {
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == ProgressObserverContext) {
dispatch_async(dispatch_get_main_queue(), ^{
NSProgress *progress = object;
self.progressText.text = [NSString stringWithFormat:@"(%@) %@", progress.localizedAdditionalDescription, progress.localizedDescription];
if (progress.finished) {
self.progressViewMain.observedProgress = nil;
[self invokeAfterJITEnabled:^{
UIKit_launchMinecraftSurfaceVC(self.task.verMetadata);
}];
}
});
} else {
if (context != ProgressObserverContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

dispatch_async(dispatch_get_main_queue(), ^{
NSProgress *progress = object;
self.progressText.text = [NSString stringWithFormat:@"(%@) %@", progress.localizedAdditionalDescription, progress.localizedDescription];
if (!progress.finished) return;

self.progressViewMain.observedProgress = nil;
if (self.task.metadata) {
[self invokeAfterJITEnabled:^{
UIKit_launchMinecraftSurfaceVC(self.task.metadata);
}];
} else {
self.task = nil;
[self setInteractionEnabled:YES forDownloading:YES];
[self reloadProfileList];
}
});
}

- (void)receiveNotification:(NSNotification *)notification {
if (![notification.name isEqualToString:@"InstallModpack"]) {
return;
}
[self setInteractionEnabled:NO forDownloading:YES];
self.task = [MinecraftResourceDownloadTask new];
NSDictionary *userInfo = notification.userInfo;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__weak LauncherNavigationController *weakSelf = self;
self.task.handleError = ^{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf setInteractionEnabled:YES forDownloading:YES];
weakSelf.task = nil;
weakSelf.progressVC = nil;
});
};
[self.task downloadModpackFromAPI:notification.object detail:userInfo[@"detail"] atIndex:[userInfo[@"index"] unsignedLongValue]];
dispatch_async(dispatch_get_main_queue(), ^{
self.progressViewMain.observedProgress = self.task.progress;
[self.task.progress addObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionInitial
context:ProgressObserverContext];
});
});
}

- (void)invokeAfterJITEnabled:(void(^)(void))handler {
Expand Down Expand Up @@ -387,9 +427,6 @@ - (void)versionClosePicker {
}

#pragma mark - View controller UI mode
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeBottom;
}

- (BOOL)prefersHomeIndicatorAutoHidden {
return YES;
Expand Down
6 changes: 4 additions & 2 deletions Natives/LauncherProfileEditorViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,10 @@ - (void)changeVersionType:(UISegmentedControl *)sender {

self.versionList = newVersionList;
[self.versionPickerView reloadAllComponents];
[self.versionPickerView selectRow:self.versionSelectedAt inComponent:0 animated:NO];
[self pickerView:self.versionPickerView didSelectRow:self.versionSelectedAt inComponent:0];
if (self.versionSelectedAt != -1) {
[self.versionPickerView selectRow:self.versionSelectedAt inComponent:0 animated:NO];
[self pickerView:self.versionPickerView didSelectRow:self.versionSelectedAt inComponent:0];
}
}

@end
11 changes: 11 additions & 0 deletions Natives/LauncherProfilesViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "UIKit+hook.h"
#import "installer/FabricInstallViewController.h"
#import "installer/ForgeInstallViewController.h"
#import "installer/ModpackInstallViewController.h"
#import "ios_uikit_bridge.h"
#import "utils.h"

Expand Down Expand Up @@ -64,6 +65,11 @@ - (void)viewDidLoad
actionWithTitle:@"Forge" image:nil
identifier:@"forge" handler:^(UIAction *action) {
[self actionCreateForgeProfile];
}],
[UIAction
actionWithTitle:@"Modpack" image:nil
identifier:@"modpack" handler:^(UIAction *action) {
[self actionCreateModpackProfile];
}]
]];
self.createButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd menu:createMenu];
Expand Down Expand Up @@ -101,6 +107,11 @@ - (void)actionCreateForgeProfile {
[self presentNavigatedViewController:vc];
}

- (void)actionCreateModpackProfile {
ModpackInstallViewController *vc = [ModpackInstallViewController new];
[self presentNavigatedViewController:vc];
}

- (void)actionEditProfile:(NSDictionary *)profile {
LauncherProfileEditorViewController *vc = [LauncherProfileEditorViewController new];
vc.profile = profile.mutableCopy;
Expand Down
1 change: 0 additions & 1 deletion Natives/LauncherSplitViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ @implementation LauncherSplitViewController

- (void)viewDidLoad {
[super viewDidLoad];
UIApplication.sharedApplication.idleTimerDisabled = YES;
self.view.backgroundColor = UIColor.systemBackgroundColor;
if ([getPrefObject(@"control.control_safe_area") length] == 0) {
setPrefObject(@"control.control_safe_area", NSStringFromUIEdgeInsets(getDefaultSafeArea()));
Expand Down
9 changes: 8 additions & 1 deletion Natives/MinecraftResourceDownloadTask.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#import <UIKit/UIKit.h>

@class ModpackAPI;

@interface MinecraftResourceDownloadTask : NSObject
@property NSProgress* progress;
@property NSMutableArray *fileList, *progressList;
@property NSMutableDictionary* verMetadata;
@property NSMutableDictionary* metadata;
@property(nonatomic, copy) void(^handleError)(void);

- (NSURLSessionDownloadTask *)createDownloadTask:(NSString *)url sha:(NSString *)sha altName:(NSString *)altName toPath:(NSString *)path;
- (void)addDownloadTaskToProgress:(NSURLSessionDownloadTask *)task;
- (void)finishDownloadWithErrorString:(NSString *)error;

- (void)downloadVersion:(NSDictionary *)version;
- (void)downloadModpackFromAPI:(ModpackAPI *)api detail:(NSDictionary *)modDetail atIndex:(NSUInteger)selectedVersion;

@end
Loading

0 comments on commit 4c075f6

Please sign in to comment.