Path: blob/main/Natives/MinecraftResourceUtils.m
589 views
#include <CommonCrypto/CommonDigest.h>12#import "authenticator/BaseAuthenticator.h"3#import "LauncherNavigationController.h"4#import "LauncherPreferences.h"5#import "MinecraftResourceUtils.h"6#import "ios_uikit_bridge.h"7#import "utils.h"89@implementation MinecraftResourceUtils1011// Handle inheritsFrom12+ (void)processVersion:(NSMutableDictionary *)json inheritsFrom:(NSMutableDictionary *)inheritsFrom {13[self insertSafety:inheritsFrom from:json arr:@[14@"assetIndex", @"assets", @"id",15@"inheritsFrom",16@"mainClass", @"minecraftArguments",17@"optifineLib", @"releaseTime", @"time", @"type"18]];19inheritsFrom[@"arguments"] = json[@"arguments"];2021for (NSMutableDictionary *lib in json[@"libraries"]) {22NSString *libName = [lib[@"name"] substringToIndex:[lib[@"name"] rangeOfString:@":" options:NSBackwardsSearch].location];23int i;24for (i = 0; i < [inheritsFrom[@"libraries"] count]; i++) {25NSMutableDictionary *libAdded = inheritsFrom[@"libraries"][i];26NSString *libAddedName = [libAdded[@"name"] substringToIndex:[libAdded[@"name"] rangeOfString:@":" options:NSBackwardsSearch].location];2728if ([libAdded[@"name"] hasPrefix:libName]) {29inheritsFrom[@"libraries"][i] = lib;30i = -1;31break;32}33}3435if (i != -1) {36[inheritsFrom[@"libraries"] addObject:lib];37}38}3940//inheritsFrom[@"inheritsFrom"] = nil;41}4243+ (void)insertSafety:(NSMutableDictionary *)targetVer from:(NSDictionary *)fromVer arr:(NSArray *)arr {44for (NSString *key in arr) {45if (([fromVer[key] isKindOfClass:NSString.class] && [fromVer[key] length] > 0) || targetVer[key] == nil) {46targetVer[key] = fromVer[key];47} else {48NSLog(@"[MCDL] insertSafety: how to insert %@?", key);49}50}51}5253+ (NSInteger)numberOfArgsToSkipForArg:(NSString *)arg {54if (![arg isKindOfClass:NSString.class]) {55// Skip non-string arg56return 1;57} else if ([arg hasPrefix:@"-cp"]) {58// Skip "-cp <classpath>"59return 2;60} else if ([arg hasPrefix:@"-Djava.library.path="]) {61return 1;62} else if ([arg hasPrefix:@"-XX:HeapDumpPath"]) {63return 1;64} else {65return 0;66}67}6869+ (void)tweakVersionJson:(NSMutableDictionary *)json {70// Exclude some libraries71for (NSMutableDictionary *library in json[@"libraries"]) {72library[@"skip"] = @(73// Exclude platform-dependant libraries74library[@"downloads"][@"classifiers"] != nil ||75library[@"natives"] != nil ||76// Exclude LWJGL libraries77[library[@"name"] hasPrefix:@"org.lwjgl"]78);7980NSString *versionStr = [library[@"name"] componentsSeparatedByString:@":"][2];81NSArray<NSString *> *version = [versionStr componentsSeparatedByString:@"."];82if ([library[@"name"] hasPrefix:@"net.java.dev.jna:jna:"]) {83// Special handling for LabyMod 1.8.9 and Forge 1.12.2(?)84// we have libjnidispatch 5.13.0 in Frameworks directory85uint32_t bundledVer = 5 << 16 | 13 << 8 | 0;86uint32_t requiredVer = (char)version[0].intValue << 16 | (char)version[1].intValue << 8 | (char)version[2].intValue;87if (requiredVer > bundledVer) {88NSLog(@"[MCDL] Warning: JNA version required by %@ is %@ > 5.13.0, skipping JNA replacement.", json[@"id"], versionStr);89continue;90}91library[@"name"] = @"net.java.dev.jna:jna:5.13.0";92library[@"downloads"][@"artifact"][@"path"] = @"net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar";93library[@"downloads"][@"artifact"][@"url"] = @"https://repo1.maven.org/maven2/net/java/dev/jna/jna/5.13.0/jna-5.13.0.jar";94library[@"downloads"][@"artifact"][@"sha1"] = @"1200e7ebeedbe0d10062093f32925a912020e747";95} else if ([library[@"name"] hasPrefix:@"org.ow2.asm:asm-all:"]) {96// Early versions of the ASM library get repalced with 5.0.4 because Pojav's LWJGL is compiled for97// Java 8, which is not supported by old ASM versions. Mod loaders like Forge, which depend on this98// library, often include lwjgl in their class transformations, which causes errors with old ASM versions.99if(version[0].intValue >= 5) continue;100library[@"name"] = @"org.ow2.asm:asm-all:5.0.4";101library[@"downloads"][@"artifact"][@"path"] = @"org/ow2/asm/asm-all/5.0.4/asm-all-5.0.4.jar";102library[@"downloads"][@"artifact"][@"sha1"] = @"e6244859997b3d4237a552669279780876228909";103library[@"downloads"][@"artifact"][@"url"] = @"https://repo1.maven.org/maven2/org/ow2/asm/asm-all/5.0.4/asm-all-5.0.4.jar";104}105}106107// Add the client as a library108NSMutableDictionary *client = [[NSMutableDictionary alloc] init];109client[@"downloads"] = [[NSMutableDictionary alloc] init];110if (json[@"downloads"][@"client"] == nil) {111client[@"downloads"][@"artifact"] = [[NSMutableDictionary alloc] init];112client[@"skip"] = @YES;113} else {114client[@"downloads"][@"artifact"] = json[@"downloads"][@"client"];115}116client[@"downloads"][@"artifact"][@"path"] = [NSString stringWithFormat:@"../versions/%1$@/%[email protected]", json[@"id"]];117client[@"name"] = [NSString stringWithFormat:@"%@.jar", json[@"id"]];118[json[@"libraries"] addObject:client];119120// Parse Forge 1.17+ additional JVM Arguments121if (json[@"inheritsFrom"] == nil || json[@"arguments"][@"jvm"] == nil) {122return;123}124json[@"arguments"][@"jvm_processed"] = [[NSMutableArray alloc] init];125NSDictionary *varArgMap = @{126@"${classpath_separator}": @":",127@"${library_directory}": [NSString stringWithFormat:@"%s/libraries", getenv("POJAV_GAME_DIR")],128@"${version_name}": json[@"id"]129};130int argsToSkip = 0;131for (NSString *arg in json[@"arguments"][@"jvm"]) {132if (argsToSkip == 0) {133argsToSkip = [self numberOfArgsToSkipForArg:arg];134}135if (argsToSkip == 0) {136NSString *argStr = arg;137for (NSString *key in varArgMap.allKeys) {138argStr = [argStr stringByReplacingOccurrencesOfString:key withString:varArgMap[key]];139}140[json[@"arguments"][@"jvm_processed"] addObject:argStr];141} else {142argsToSkip--;143}144}145}146147+ (NSObject *)findVersion:(NSString *)version inList:(NSArray *)list {148return [list filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(id == %@)", version]].firstObject;149}150151+ (NSObject *)findNearestVersion:(NSObject *)version expectedType:(int)type {152if (type != TYPE_RELEASE && type != TYPE_SNAPSHOT) {153// Only support finding for releases and snapshot for now154return nil;155}156157if ([version isKindOfClass:NSString.class]){158// Find in inheritsFrom159NSDictionary *versionDict = parseJSONFromFile([NSString stringWithFormat:@"%1$s/versions/%2$@/%[email protected]", getenv("POJAV_GAME_DIR"), version]);160NSAssert(versionDict != nil, @"version should not be null");161if (versionDict[@"inheritsFrom"] == nil) {162// How then?163return nil;164}165NSObject *inheritsFrom = [self findVersion:versionDict[@"inheritsFrom"] inList:remoteVersionList];166if (type == TYPE_RELEASE) {167return inheritsFrom;168} else if (type == TYPE_SNAPSHOT) {169return [self findNearestVersion:inheritsFrom expectedType:type];170}171}172173NSString *versionType = [version valueForKey:@"type"];174int index = [remoteVersionList indexOfObject:(NSDictionary *)version];175if ([versionType isEqualToString:@"release"] && type == TYPE_SNAPSHOT) {176// Returns the (possible) latest snapshot for the version177NSDictionary *result = remoteVersionList[index + 1];178// Sometimes, a release is followed with another release (1.16->1.16.1), go lower in this case179if ([result[@"type"] isEqualToString:@"release"]) {180return [self findNearestVersion:result expectedType:type];181}182return result;183} else if ([versionType isEqualToString:@"snapshot"] && type == TYPE_RELEASE) {184while (remoteVersionList.count > abs(index)) {185// In case the snapshot has yet attached to a release, perform a reverse find186NSDictionary *result = remoteVersionList[abs(index)];187// Returns the corresponding release for the snapshot, or latest release if none found188if ([result[@"type"] isEqualToString:@"release"]) {189return result;190}191// Continue to decrement, later abs() it192index--;193}194}195196// No idea on handling everything else197return nil;198}199200@end201202203