Skip to content
This repository was archived by the owner on Sep 9, 2023. It is now read-only.

Commit d75bcfa

Browse files
Multi instance
1 parent 86672ed commit d75bcfa

8 files changed

Lines changed: 212 additions & 150 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Written in Java. Designed for all platform and portable use.
1414
- `config` Configure the program.
1515
- `directory <path>` Set the working directory of the program.
1616
- `modpack` Commands for modpack.
17-
- `install <ID>` Install modpack(s). The ID parameter is the ID of the modpack found on CurseForge.
17+
- `install <ID> [FileID]` Install modpack(s). The ID parameter is the ID of the modpack found on CurseForge. FileID is the ID of the modpack zip file on CurseForge. Omit to install the latest version.
1818
- `delete <ID|Slug>` Delete modpack(s). The ID/slug parameter is the ID/slug of the modpack.
1919
- `list` List all installed modpacks.
2020
- `profile` Commands for custom profile.

src/ml/northwestwind/Config.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public static void run(String[] args) {
2020
Utils.invalid();
2121
return;
2222
}
23-
if (args[1].equalsIgnoreCase("directory")) setDirectory(Arrays.stream(args).skip(2).collect(Collectors.joining(" ")));
23+
if (args[1].equalsIgnoreCase("directory"))
24+
setDirectory(Arrays.stream(args).skip(2).collect(Collectors.joining(" ")));
2425
else Utils.invalid();
2526
}
2627

@@ -56,7 +57,7 @@ public static void load() {
5657
acceptParentVersionMod = (boolean) json.getOrDefault("acceptParent", true);
5758
suppressUpdates = (boolean) json.getOrDefault("suppressUpdates", false);
5859
retries = (long) json.getOrDefault("retries", 3L);
59-
} catch(Exception e) {
60+
} catch (Exception e) {
6061
e.printStackTrace();
6162
}
6263
}
@@ -74,8 +75,14 @@ public static Map<Integer, String> loadModpacks() {
7475
for (File file : files) {
7576
if (file.isFile()) continue;
7677
String[] splitted = file.getName().split("_");
77-
String id = Utils.getLast(Arrays.asList(splitted));
78-
if (!Utils.isInteger(id)) continue;
78+
String fileId = Utils.getLast(Arrays.asList(splitted));
79+
if (!Utils.isInteger(fileId)) continue;
80+
String[] splitted1 = Arrays.stream(Arrays.copyOf(splitted, splitted.length - 1)).toArray(String[]::new);
81+
String id = Utils.getLast(Arrays.asList(splitted1));
82+
if (!Utils.isInteger(id)) {
83+
id = fileId;
84+
fileId = null;
85+
}
7986
String slug = Arrays.stream(Arrays.copyOf(splitted, splitted.length - 1)).collect(Collectors.joining("_"));
8087
map.put(Integer.parseInt(id), slug);
8188
}

src/ml/northwestwind/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
public class Constants {
44
public static final String CURSEFORGE_API = "https://addons-ecs.forgesvc.net/api/v2/addon/";
5-
public static final String VERSION = "1.2.6";
5+
public static final String VERSION = "1.2.7";
66
private static final String OS = System.getProperty("os.name").toLowerCase();
77
public static final boolean IS_WINDOWS = (OS.contains("win"));
88
public static final boolean IS_MAC = (OS.contains("mac"));

src/ml/northwestwind/Main.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ public static void main(String[] args) {
3535
private static void printHelp() {
3636
System.out.println(ansi().fg(YELLOW).a(
3737
" ________ ________ ________ ___ ___ \n" +
38-
"|\\ ____\\|\\ _____\\ |\\ ____\\|\\ \\ |\\ \\ \n" +
39-
"\\ \\ \\___|\\ \\ \\__/ \\ \\ \\___|\\ \\ \\ \\ \\ \\ \n" +
40-
" \\ \\ \\ \\ \\ __\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \n" +
41-
" \\ \\ \\____\\ \\ \\_| \\ \\ \\____\\ \\ \\____\\ \\ \\ \n" +
42-
" \\ \\_______\\ \\__\\ \\ \\_______\\ \\_______\\ \\__\\\n" +
43-
" \\|_______|\\|__| \\|_______|\\|_______|\\|__|"
38+
"|\\ ____\\|\\ _____\\ |\\ ____\\|\\ \\ |\\ \\ \n" +
39+
"\\ \\ \\___|\\ \\ \\__/ \\ \\ \\___|\\ \\ \\ \\ \\ \\ \n" +
40+
" \\ \\ \\ \\ \\ __\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \n" +
41+
" \\ \\ \\____\\ \\ \\_| \\ \\ \\____\\ \\ \\____\\ \\ \\ \n" +
42+
" \\ \\_______\\ \\__\\ \\ \\_______\\ \\_______\\ \\__\\\n" +
43+
" \\|_______|\\|__| \\|_______|\\|_______|\\|__|"
4444
).reset());
4545
System.out.println(ansi().fg(GREEN).a("Made by NorthWestWind").reset());
4646
System.out.println();

src/ml/northwestwind/Modpack.java

Lines changed: 112 additions & 78 deletions
Large diffs are not rendered by default.

src/ml/northwestwind/Profile.java

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -113,32 +113,32 @@ private static void edit(String profile) {
113113
String nName = null, nMcVer = null, nModVer = null, nLauncher = null;
114114
Scanner scanner = new Scanner(System.in);
115115
System.out.println(Ansi.ansi().fg(Ansi.Color.CYAN).a("Editing profile " + profile));
116-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Name ("+name+"): ").reset());
116+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Name (" + name + "): ").reset());
117117
while (nName == null) {
118118
String received = scanner.nextLine();
119119
if (received.isEmpty() && name.isEmpty()) {
120-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Name cannot be empty. Name ("+name+"): ").reset());
120+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Name cannot be empty. Name (" + name + "): ").reset());
121121
} else nName = received.isEmpty() ? name : received;
122122
}
123-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Minecraft version ("+mcVer+"): ").reset());
123+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Minecraft version (" + mcVer + "): ").reset());
124124
while (nMcVer == null) {
125125
String received = scanner.nextLine();
126126
if (((received.isEmpty() || !Utils.isMCVersionValid(received)) && mcVer.isEmpty())) {
127-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("The version is invalid. Minecraft version ("+mcVer+"): ").reset());
127+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("The version is invalid. Minecraft version (" + mcVer + "): ").reset());
128128
} else nMcVer = received.isEmpty() ? mcVer : received;
129129
}
130-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Mod launcher [forge/fabric] ("+launcher+"): ").reset());
130+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Mod launcher [forge/fabric] (" + launcher + "): ").reset());
131131
while (nLauncher == null) {
132132
String received = scanner.nextLine().toLowerCase();
133133
if (((received.isEmpty() || (!received.equals("forge") && !received.equals("fabric"))) && launcher.isEmpty())) {
134-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("The launcher is invalid. Mod launcher [forge/fabric] ("+launcher+"): ").reset());
134+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("The launcher is invalid. Mod launcher [forge/fabric] (" + launcher + "): ").reset());
135135
} else nLauncher = received.isEmpty() ? launcher : received;
136136
}
137-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Mod launcher version ("+modVer+"): ").reset());
137+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Mod launcher version (" + modVer + "): ").reset());
138138
while (nModVer == null) {
139139
String received = scanner.nextLine();
140140
if (received.isEmpty() && modVer.isEmpty()) {
141-
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("The launcher version is invalid. Mod launcher version ("+modVer+"): ").reset());
141+
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("The launcher version is invalid. Mod launcher version (" + modVer + "): ").reset());
142142
} else nModVer = received.isEmpty() ? modVer : received;
143143
}
144144
json.put("name", nName);
@@ -219,16 +219,19 @@ private static void add(String[] ids) {
219219
Map<Integer, Map.Entry<Integer, String>> mods = Config.loadMods(profile);
220220
for (String id : Arrays.stream(ids).skip(1).toArray(String[]::new)) {
221221
try {
222-
if (!Utils.isInteger(id)) throw new NoSuchObjectException("Mod ID is invalid: "+id);
222+
if (!Utils.isInteger(id)) throw new NoSuchObjectException("Mod ID is invalid: " + id);
223223
JSONObject json = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id));
224-
if (((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6) throw new NoSuchObjectException("The ID "+id+" does not represent a mod.");
224+
if (((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6)
225+
throw new NoSuchObjectException("The ID " + id + " does not represent a mod.");
225226
JSONArray files = Utils.runRetry(() -> (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files"));
226227
List f = (List) files.stream().filter(o -> Utils.checkVersion((JSONArray) ((JSONObject) o).get("gameVersion"), config)).collect(Collectors.toList());
227228
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
228-
if (f.size() < 1) throw new InputMismatchException("No available file of " + id + " found for this profile.");
229+
if (f.size() < 1)
230+
throw new InputMismatchException("No available file of " + id + " found for this profile.");
229231
JSONObject bestFile = (JSONObject) f.get(0);
230232
String downloadUrl = (String) bestFile.get("downloadUrl");
231-
if (mods.containsKey(Integer.parseInt(id))) new File(modsFolder.getPath() + File.separator + mods.get(Integer.parseInt(id)).getValue() + "_" + id + "_" + mods.get(Integer.parseInt(id)).getKey() + ".jar").delete();
233+
if (mods.containsKey(Integer.parseInt(id)))
234+
new File(modsFolder.getPath() + File.separator + mods.get(Integer.parseInt(id)).getValue() + "_" + id + "_" + mods.get(Integer.parseInt(id)).getKey() + ".jar").delete();
232235
String loc = Utils.downloadFile(downloadUrl, modsFolder.getPath(), ((String) bestFile.get("fileName")).replace(".jar", "_" + id + "_" + bestFile.get("id") + ".jar"));
233236
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Downloaded " + loc));
234237
} catch (Exception e) {
@@ -257,11 +260,12 @@ private static void remove(String[] ids) {
257260
name = file + "_" + id + "_" + entry.getKey();
258261
modName = file;
259262
} else {
260-
for (Map.Entry<Integer, Map.Entry<Integer, String>> entry : mods.entrySet()) if (entry.getValue().getValue().equalsIgnoreCase(id)) {
261-
name = entry.getValue().getValue() + "_" + entry.getKey() + "_" + entry.getValue().getKey();
262-
modName = entry.getValue().getValue();
263-
break;
264-
}
263+
for (Map.Entry<Integer, Map.Entry<Integer, String>> entry : mods.entrySet())
264+
if (entry.getValue().getValue().equalsIgnoreCase(id)) {
265+
name = entry.getValue().getValue() + "_" + entry.getKey() + "_" + entry.getValue().getKey();
266+
modName = entry.getValue().getValue();
267+
break;
268+
}
265269
if (name == null) throw new NoSuchObjectException("Cannot find mod with name " + id);
266270
}
267271
files.put(name + ".jar", modName);
@@ -440,7 +444,8 @@ private static void update(String[] args) {
440444
for (Map.Entry<Integer, Map.Entry<Integer, String>> entry : mods.entrySet()) {
441445
try {
442446
JSONObject json = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + entry.getKey()));
443-
if (((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6) throw new NoSuchObjectException("The ID "+entry.getKey()+" does not represent a mod.");
447+
if (((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6)
448+
throw new NoSuchObjectException("The ID " + entry.getKey() + " does not represent a mod.");
444449
JSONArray files = Utils.runRetry(() -> (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + entry.getKey() + "/files"));
445450
List f = (List) files.stream().filter(o -> Utils.checkVersion((JSONArray) ((JSONObject) o).get("gameVersion"), config)).collect(Collectors.toList());
446451
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
@@ -457,7 +462,8 @@ private static void update(String[] args) {
457462
}
458463
try {
459464
PrintWriter pw = new PrintWriter(profileConfig.getParent() + File.separator + "mod_updates.txt");
460-
for (Map.Entry<Integer, String> entry : updatables.entrySet()) pw.println(entry.getValue() + " = " + entry.getKey());
465+
for (Map.Entry<Integer, String> entry : updatables.entrySet())
466+
pw.println(entry.getValue() + " = " + entry.getKey());
461467
pw.println();
462468
pw.println("You can update these mods of a profile with the following command: ");
463469
String cmd = "curseforge profile update " + profile + " " + updatables.keySet().stream().map(String::valueOf).collect(Collectors.joining(" "));
@@ -472,19 +478,22 @@ private static void update(String[] args) {
472478

473479
for (String id : Arrays.stream(args).skip(1).toArray(String[]::new)) {
474480
try {
475-
if (!Utils.isInteger(id)) throw new NoSuchObjectException("Mod ID is invalid: "+id);
481+
if (!Utils.isInteger(id)) throw new NoSuchObjectException("Mod ID is invalid: " + id);
476482
JSONObject json = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id));
477-
if (((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6) throw new NoSuchObjectException("The ID "+id+" does not represent a mod.");
483+
if (((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6)
484+
throw new NoSuchObjectException("The ID " + id + " does not represent a mod.");
478485
JSONArray files = Utils.runRetry(() -> (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files"));
479486
List f = (List) files.stream().filter(o -> Utils.checkVersion((JSONArray) ((JSONObject) o).get("gameVersion"), config)).collect(Collectors.toList());
480487
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
481-
if (f.size() < 1) throw new InputMismatchException("No available file of " + id + " found for this profile.");
488+
if (f.size() < 1)
489+
throw new InputMismatchException("No available file of " + id + " found for this profile.");
482490
JSONObject bestFile = (JSONObject) f.get(0);
483491
Map.Entry<Integer, String> entry = mods.get(Integer.parseInt(id));
484492
if (((long) bestFile.get("id")) > entry.getKey()) {
485493
System.out.println(Ansi.ansi().fg(Ansi.Color.YELLOW).a(entry.getValue()).reset().a(" | ").fg(Ansi.Color.MAGENTA).a(entry.getKey()));
486494
String downloadUrl = ((String) bestFile.get("downloadUrl")).replaceFirst("edge", "media");
487-
if (mods.containsKey(Integer.parseInt(id))) new File(profileConfig.getParent() + File.separator + "mods" + File.separator + entry.getValue() + "_" + id + "_" + entry.getKey() + ".jar").delete();
495+
if (mods.containsKey(Integer.parseInt(id)))
496+
new File(profileConfig.getParent() + File.separator + "mods" + File.separator + entry.getValue() + "_" + id + "_" + entry.getKey() + ".jar").delete();
488497
String loc = Utils.downloadFile(downloadUrl, profileConfig.getParent() + File.separator + "mods", ((String) bestFile.get("fileName")).replace(".jar", "_" + id + "_" + bestFile.get("id") + ".jar"));
489498
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Downloaded " + loc));
490499
}
@@ -512,10 +521,12 @@ private static boolean importProf(String[] paths, boolean silent, boolean toCD)
512521
if (!zipped.exists()) throw new FileNotFoundException("The file " + path + " does not exist");
513522
if (zipped.isFile()) {
514523
FileUtils.copyFileToDirectory(zipped, Config.tempDir);
515-
if (!Utils.unzip(Config.tempDir.getPath() + File.separator + zipped.getName())) throw new FileSystemException("Failed to extract modpack content of "+path);
524+
if (!Utils.unzip(Config.tempDir.getPath() + File.separator + zipped.getName()))
525+
throw new FileSystemException("Failed to extract modpack content of " + path);
516526
} else FileUtils.copyDirectoryToDirectory(zipped, Config.tempDir);
517527
File manifest = new File(Config.tempDir.getPath() + File.separator + "manifest.json");
518-
if (!manifest.exists() || !manifest.isFile()) throw new FileNotFoundException("Modpack is missing manifest. Cannot convert to profile.");
528+
if (!manifest.exists() || !manifest.isFile())
529+
throw new FileNotFoundException("Modpack is missing manifest. Cannot convert to profile.");
519530
Modpack.copyFromOverride(Config.tempDir.getPath(), (String) ((JSONObject) parser.parse(new FileReader(manifest))).get("overrides"));
520531
Modpack.downloadMods(Config.tempDir.getPath());
521532
JSONObject json = (JSONObject) parser.parse(new FileReader(manifest));
@@ -558,7 +569,8 @@ private static boolean importProf(String[] paths, boolean silent, boolean toCD)
558569
}
559570
try {
560571
if (Config.tempDir.exists() && Config.tempDir.isDirectory()) FileUtils.deleteDirectory(Config.tempDir);
561-
} catch (Exception ignored) { }
572+
} catch (Exception ignored) {
573+
}
562574
}
563575
return imported;
564576
}
@@ -567,7 +579,8 @@ public static boolean findAndImport() {
567579
try {
568580
File currentDir = new File(".");
569581
return importProf(currentDir.list((dir, name) -> name.endsWith(".zip")), true, true);
570-
} catch (Exception ignored) { }
582+
} catch (Exception ignored) {
583+
}
571584
return false;
572585
}
573586

@@ -581,13 +594,13 @@ public static void printHelp(String prefix) {
581594
System.out.println(prefix + "\t\targ [folders|files]: Folders or files to put in overrides.");
582595
System.out.println(prefix + "\tadd: Add a mod to the profile.");
583596
System.out.println(prefix + "\t\targ <profile>: Name of the profile to target.");
584-
System.out.println(prefix + "\t\targ <ID>: The ID of the mod.");
597+
System.out.println(prefix + "\t\targ <ID>: The ID of the mod. Can be multiple IDs or slugs.");
585598
System.out.println(prefix + "\tremove: Remove a mod from the profile.");
586599
System.out.println(prefix + "\t\targ <profile>: Name of the profile to target.");
587-
System.out.println(prefix + "\t\targ <ID>: The ID of the mod.");
600+
System.out.println(prefix + "\t\targ <ID>: The ID of the mod. Can be multiple IDs or slugs.");
588601
System.out.println(prefix + "\tupdate: Update mods in the profile.");
589602
System.out.println(prefix + "\t\targ <profile>: Name of the profile to target.");
590-
System.out.println(prefix + "\t\targ [ID]: The ID of mods. Omit to check for updates.");
603+
System.out.println(prefix + "\t\targ [ID]: The ID of mods. Omit to check for updates. Can be multiple IDs or slugs.");
591604
System.out.println(prefix + "\timport: Import a downloaded modpack.");
592605
System.out.println(prefix + "\t\targ <path>: Path to the zip or directory.");
593606
}

0 commit comments

Comments
 (0)