@@ -39,8 +39,8 @@ - (void)viewDidLoad {
3939 @" metadata" : @" https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml"
4040 },
4141 @" NeoForge" : @{
42- @" installer" : @" https://maven.neoforged.net/net/neoforged/forge /%1$@ /forge -%1$@ -installer.jar" ,
43- @" metadata" : @" https://maven.neoforged.net/releases/net/neoforged/forge /maven-metadata.xml"
42+ @" installer" : @" https://maven.neoforged.net/releases/ net/neoforged/neoforge /%1$@ /neoforge -%1$@ -installer.jar" ,
43+ @" metadata" : @" https://maven.neoforged.net/releases/net/neoforged/neoforge /maven-metadata.xml"
4444 }
4545 };
4646 self.visibilityList = [NSMutableArray new ];
@@ -132,7 +132,23 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
132132 cell = [[UITableViewCell alloc ] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: @" cell" ];
133133 }
134134
135- cell.textLabel .text = self.forgeList [indexPath.section][indexPath.row];
135+ UISegmentedControl *segment = (id )self.navigationItem .titleView ;
136+ NSString *vendor = [segment titleForSegmentAtIndex: segment.selectedSegmentIndex];
137+ NSString *rawVersion = self.forgeList [indexPath.section][indexPath.row];
138+ if ([vendor isEqualToString: @" NeoForge" ]) {
139+ NSString *cleanVersion = [rawVersion stringByReplacingOccurrencesOfString: @" -beta" withString: @" " ];
140+ NSArray *components = [cleanVersion componentsSeparatedByString: @" ." ];
141+ if (components.count >= 2 ) {
142+ NSString *major = components[0 ];
143+ NSString *minor = components[1 ];
144+ NSString *gameVersion = [NSString stringWithFormat: @" 1.%@ .%@ " , major, minor];
145+ cell.textLabel .text = [NSString stringWithFormat: @" %@ -%@ " , gameVersion, rawVersion];
146+ } else {
147+ cell.textLabel .text = rawVersion;
148+ }
149+ } else {
150+ cell.textLabel .text = rawVersion;
151+ }
136152 return cell;
137153}
138154
@@ -148,7 +164,8 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
148164
149165 UISegmentedControl *segment = (id )self.navigationItem .titleView ;
150166 NSString *vendor = [segment titleForSegmentAtIndex: segment.selectedSegmentIndex];
151- NSString *jarURL = [NSString stringWithFormat: self .endpoints[vendor][@" installer" ], cell.textLabel.text];
167+ NSString *selectedRawVersion = self.forgeList [indexPath.section][indexPath.row];
168+ NSString *jarURL = [NSString stringWithFormat: self .endpoints[vendor][@" installer" ], selectedRawVersion];
152169 NSString *outPath = [NSTemporaryDirectory () stringByAppendingPathComponent: @" tmp.jar" ];
153170 NSDebugLog (@" [Forge Installer] Downloading %@ " , jarURL);
154171
@@ -185,24 +202,120 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
185202}
186203
187204- (void )addVersionToList : (NSString *)version {
188- if (![version containsString: @" -" ]) {
205+ // Get the current vendor to determine version format
206+ UISegmentedControl *segment = (id )self.navigationItem .titleView ;
207+ NSString *vendor = [segment titleForSegmentAtIndex: segment.selectedSegmentIndex];
208+
209+ NSString *gameVersion;
210+ if ([vendor isEqualToString: @" Forge" ]) {
211+ // Forge format: gameVersion-forgeVersion (e.g., "1.20.1-47.1.0")
212+ if (![version containsString: @" -" ]) {
213+ return ;
214+ }
215+ NSRange range = [version rangeOfString: @" -" ];
216+ gameVersion = [version substringToIndex: range.location];
217+ } else if ([vendor isEqualToString: @" NeoForge" ]) {
218+ // NeoForge format: major.minor.patch-beta (e.g., "20.2.3-beta")
219+ NSString *cleanVersion = [version stringByReplacingOccurrencesOfString: @" -beta" withString: @" " ];
220+ NSArray *components = [cleanVersion componentsSeparatedByString: @" ." ];
221+ if (components.count >= 2 ) {
222+ // Convert to full Minecraft version format (e.g., "20.2" -> "1.20.2")
223+ NSString *major = components[0 ];
224+ NSString *minor = components[1 ];
225+ gameVersion = [NSString stringWithFormat: @" 1.%@ .%@ " , major, minor];
226+ } else {
227+ gameVersion = version;
228+ }
229+ } else {
189230 return ;
190231 }
191- NSRange range = [version rangeOfString: @" -" ];
192- NSString *gameVersion = [version substringToIndex: range.location];
193- // NSString *forgeVersion = [version substringFromIndex:range.location + 1];
194- if (![self .versionList containsObject: gameVersion]) {
232+
233+ NSInteger gameVersionIndex = [self .versionList indexOfObject: gameVersion];
234+ if (gameVersionIndex == NSNotFound ) {
195235 [self .visibilityList addObject: @(NO )];
196236 [self .versionList addObject: gameVersion];
197237 [self .forgeList addObject: [NSMutableArray new ]];
238+ gameVersionIndex = self.versionList .count - 1 ;
198239 }
199- [self .forgeList.lastObject addObject: version];
240+ [self .forgeList[gameVersionIndex] addObject: version];
200241}
201242
202243#pragma mark NSXMLParser
203244
204245- (void )parserDidEndDocument : (NSXMLParser *)unused {
205246 dispatch_async (dispatch_get_main_queue (), ^{
247+ // Determine current vendor to apply proper sorting
248+ UISegmentedControl *segment = (id )self.navigationItem .titleView ;
249+ NSString *vendor = [segment titleForSegmentAtIndex: segment.selectedSegmentIndex];
250+
251+ NSMutableArray <NSNumber *> *indices = [NSMutableArray new ];
252+ for (NSInteger i = 0 ; i < self.versionList .count ; i++) {
253+ [indices addObject: @(i)];
254+ }
255+ [indices sortUsingComparator: ^NSComparisonResult (NSNumber *a, NSNumber *b) {
256+ NSString *va = self.versionList [a.integerValue];
257+ NSString *vb = self.versionList [b.integerValue];
258+ // Expect format "1.minor.patch"
259+ NSArray *pa = [va componentsSeparatedByString: @" ." ];
260+ NSArray *pb = [vb componentsSeparatedByString: @" ." ];
261+ NSInteger aMinor = pa.count > 1 ? [pa[1 ] integerValue ] : 0 ;
262+ NSInteger bMinor = pb.count > 1 ? [pb[1 ] integerValue ] : 0 ;
263+ if (aMinor != bMinor) return aMinor < bMinor ? NSOrderedDescending : NSOrderedAscending;
264+ NSInteger aPatch = pa.count > 2 ? [pa[2 ] integerValue ] : 0 ;
265+ NSInteger bPatch = pb.count > 2 ? [pb[2 ] integerValue ] : 0 ;
266+ if (aPatch != bPatch) return aPatch < bPatch ? NSOrderedDescending : NSOrderedAscending;
267+ return NSOrderedSame;
268+ }];
269+
270+ NSMutableArray *newVisibility = [NSMutableArray new ];
271+ NSMutableArray *newVersionList = [NSMutableArray new ];
272+ NSMutableArray *newForgeList = [NSMutableArray new ];
273+ for (NSNumber *idx in indices) {
274+ [newVisibility addObject: self .visibilityList[idx.integerValue]];
275+ [newVersionList addObject: self .versionList[idx.integerValue]];
276+ [newForgeList addObject: self .forgeList[idx.integerValue]];
277+ }
278+ self.visibilityList = newVisibility;
279+ self.versionList = newVersionList;
280+ self.forgeList = newForgeList;
281+
282+ for (NSMutableArray <NSString *> *versions in self.forgeList ) {
283+ [versions sortUsingComparator: ^NSComparisonResult (NSString *lhs, NSString *rhs) {
284+ if ([vendor isEqualToString: @" Forge" ]) {
285+ // Format: 1.x.y-A.B.C -> compare A, then B, then C (descending)
286+ NSRange dashL = [lhs rangeOfString: @" -" ];
287+ NSRange dashR = [rhs rangeOfString: @" -" ];
288+ NSString *lv = dashL.location != NSNotFound ? [lhs substringFromIndex: dashL.location + 1 ] : lhs;
289+ NSString *rv = dashR.location != NSNotFound ? [rhs substringFromIndex: dashR.location + 1 ] : rhs;
290+ NSArray *lp = [lv componentsSeparatedByString: @" ." ];
291+ NSArray *rp = [rv componentsSeparatedByString: @" ." ];
292+ NSInteger lA = lp.count > 0 ? [lp[0 ] integerValue ] : 0 ;
293+ NSInteger rA = rp.count > 0 ? [rp[0 ] integerValue ] : 0 ;
294+ if (lA != rA) return lA < rA ? NSOrderedDescending : NSOrderedAscending;
295+ NSInteger lB = lp.count > 1 ? [lp[1 ] integerValue ] : 0 ;
296+ NSInteger rB = rp.count > 1 ? [rp[1 ] integerValue ] : 0 ;
297+ if (lB != rB) return lB < rB ? NSOrderedDescending : NSOrderedAscending;
298+ NSInteger lC = lp.count > 2 ? [lp[2 ] integerValue ] : 0 ;
299+ NSInteger rC = rp.count > 2 ? [rp[2 ] integerValue ] : 0 ;
300+ if (lC != rC) return lC < rC ? NSOrderedDescending : NSOrderedAscending;
301+ return NSOrderedSame;
302+ } else {
303+ // NeoForge: X.Y.Z[-beta] where X.Y is stream; compare Z (build) descending; release before beta
304+ BOOL lBeta = [lhs containsString: @" -beta" ];
305+ BOOL rBeta = [rhs containsString: @" -beta" ];
306+ NSString *lClean = [lhs stringByReplacingOccurrencesOfString: @" -beta" withString: @" " ];
307+ NSString *rClean = [rhs stringByReplacingOccurrencesOfString: @" -beta" withString: @" " ];
308+ NSArray *lc = [lClean componentsSeparatedByString: @" ." ];
309+ NSArray *rc = [rClean componentsSeparatedByString: @" ." ];
310+ NSInteger lBuild = lc.count > 2 ? [lc[2 ] integerValue ] : 0 ;
311+ NSInteger rBuild = rc.count > 2 ? [rc[2 ] integerValue ] : 0 ;
312+ if (lBuild != rBuild) return lBuild < rBuild ? NSOrderedDescending : NSOrderedAscending;
313+ if (lBeta != rBeta) return lBeta ? NSOrderedDescending : NSOrderedAscending; // release first
314+ return NSOrderedSame;
315+ }
316+ }];
317+ }
318+
206319 [self switchToReadyState ];
207320 [self .tableView reloadData ];
208321 });
0 commit comments