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

Commit

Permalink
auto dep install + fixed launcher check
Browse files Browse the repository at this point in the history
  • Loading branch information
North-West-Wind committed Apr 18, 2023
1 parent 3e5a491 commit 5ea74c4
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 44 deletions.
6 changes: 5 additions & 1 deletion src/ml/northwestwind/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

public class Config {
public static File directory, modpackDir, profileDir, exportDir, tempDir;
public static boolean acceptParentVersionMod, suppressUpdates, silentExceptions;
public static boolean acceptParentVersionMod, suppressUpdates, silentExceptions, disableOptional, alwaysInstallOptional;
public static long retries;

public static void run(String[] args) {
Expand Down Expand Up @@ -57,6 +57,8 @@ public static void load() {
acceptParentVersionMod = (boolean) json.getOrDefault("acceptParent", true);
suppressUpdates = (boolean) json.getOrDefault("suppressUpdates", false);
silentExceptions = (boolean) json.getOrDefault("silentExceptions", false);
disableOptional = (boolean) json.getOrDefault("disableOptional", false);
alwaysInstallOptional = (boolean) json.getOrDefault("alwaysInstallOptional", false);
retries = (long) json.getOrDefault("retries", 3L);
} catch (Exception e) {
if (!silentExceptions) e.printStackTrace();
Expand Down Expand Up @@ -105,6 +107,8 @@ public static void save() {
jo.put("suppressUpdates", suppressUpdates);
jo.put("retries", retries);
jo.put("silentExceptions", silentExceptions);
jo.put("disableOptional", disableOptional);
jo.put("alwaysInstallOptional", alwaysInstallOptional);
PrintWriter pw = new PrintWriter("cf.json");
pw.write(jo.toJSONString());

Expand Down
2 changes: 1 addition & 1 deletion src/ml/northwestwind/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

public class Constants {
public static final String CURSEFORGE_API = "https://northwestwind.ml/api/curseforge/mods/";
public static final String VERSION = "1.4.1";
public static final String VERSION = "1.5.0";
private static final String OS = System.getProperty("os.name").toLowerCase();
public static final boolean IS_WINDOWS = (OS.contains("win"));
public static final boolean IS_MAC = (OS.contains("mac"));
Expand Down
102 changes: 62 additions & 40 deletions src/ml/northwestwind/Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,67 @@ private static void delete(String[] names) {
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a(String.format("%d success, %d failed", folders.size() - failed.get(), failed.get())).reset());
}

private static void downloadMod(String arg, JSONObject config, File modsFolder, Map<String, String> mods, Map<String, String> modNames) {
try {
String[] modIds = arg.split("_");
String id = modIds[0], fileId = null;
if (modIds.length > 1) {
fileId = modIds[1];
if (!Utils.isInteger(fileId)) throw new NoSuchObjectException("Mod file ID is invalid: " + fileId);
}
if (!Utils.isInteger(id)) throw new NoSuchObjectException("Mod ID is invalid: " + id);
JSONObject json = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id));
if (((long) json.get("classId")) != 6)
throw new NoSuchObjectException("The ID " + id + " does not represent a mod.");
JSONObject bestFile;
if (fileId == null) {
JSONArray files = Utils.runRetry(() -> (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files"));
List f = (List) files.stream().filter(o -> Utils.checkVersion((JSONArray) ((JSONObject) o).get("gameVersions"), config)).collect(Collectors.toList());
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
if (f.size() < 1)
throw new InputMismatchException("No available file of " + id + " found for this profile.");
bestFile = (JSONObject) f.get(0);
} else {
String finalFileId = fileId;
bestFile = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files/" + finalFileId));
}
String fileName = (String) bestFile.get("fileName");
JSONArray dependencies = (JSONArray) bestFile.get("dependencies");
if (dependencies.size() > 0) {
for (Object dep : dependencies) {
JSONObject dependency = (JSONObject) dep;
long modId = (long) dependency.get("modId");
long relation = (long) dependency.get("relationType");
if (relation == 2) {
if (Config.disableOptional) continue;
if (!Config.alwaysInstallOptional) {
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Mod ").a(fileName).a(" has optional dependency ").a(Utils.getModSlug(Long.toString(modId))).a(". Do you want to install it? [y/n] "));
if (!Utils.readYesNo()) continue;
}
downloadMod(Long.toString(modId), config, modsFolder, mods, modNames);
} else if (relation == 3) {
System.out.print(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Mod ").a(fileName).a(" has optional dependency ").a(Utils.getModSlug(Long.toString(modId))).a(". Installing..."));
downloadMod(Long.toString(modId), config, modsFolder, mods, modNames);
}
}
}
String downloadUrl = (String) bestFile.get("downloadUrl");
if (downloadUrl == null) {
long parsed = (long) bestFile.get("id");
long first = parsed / 1000;
downloadUrl = String.format("https://edge.forgecdn.net/files/%d/%d/%s", first, parsed - first * 1000, fileName);
}
if (mods.containsKey(id)) {
File oldFile = new File(modsFolder.getAbsolutePath() + File.separator + modNames.get(id));
if (oldFile.exists() && oldFile.isFile()) oldFile.delete();
}
String loc = Utils.downloadFile(downloadUrl, modsFolder.getAbsolutePath(), fileName.replace(".jar", "_" + id + "_" + bestFile.get("id") + ".jar"));
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Downloaded " + loc));
} catch (Exception e) {
if (!Config.silentExceptions) e.printStackTrace();
}
}

private static void add(String[] ids) {
String profile = ids[0];
List<String> profiles = Config.loadProfiles();
Expand All @@ -217,46 +278,7 @@ private static void add(String[] ids) {
if (!modsFolder.exists() || !modsFolder.isDirectory()) modsFolder.mkdir();
Map<String, String> mods = Utils.getAllMods(modsFolder.getAbsolutePath());
Map<String, String> modNames = Utils.getAllModNames(modsFolder.getAbsolutePath());
for (String arg : Arrays.stream(ids).skip(1).toArray(String[]::new)) {
try {
String[] modIds = arg.split("_");
String id = modIds[0], fileId = null;
if (modIds.length > 1) {
fileId = modIds[1];
if (!Utils.isInteger(fileId)) throw new NoSuchObjectException("Mod file ID is invalid: " + fileId);
}
if (!Utils.isInteger(id)) throw new NoSuchObjectException("Mod ID is invalid: " + id);
JSONObject json = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id));
if (((long) json.get("classId")) != 6)
throw new NoSuchObjectException("The ID " + id + " does not represent a mod.");
JSONObject bestFile;
if (fileId == null) {
JSONArray files = Utils.runRetry(() -> (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files"));
List f = (List) files.stream().filter(o -> Utils.checkVersion((JSONArray) ((JSONObject) o).get("gameVersions"), config)).collect(Collectors.toList());
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
if (f.size() < 1)
throw new InputMismatchException("No available file of " + id + " found for this profile.");
bestFile = (JSONObject) f.get(0);
} else {
String finalFileId = fileId;
bestFile = Utils.runRetry(() -> (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files/" + finalFileId));
}
String downloadUrl = (String) bestFile.get("downloadUrl");
if (downloadUrl == null) {
long parsed = (long) bestFile.get("id");
long first = parsed / 1000;
downloadUrl = String.format("https://edge.forgecdn.net/files/%d/%d/%s", first, parsed - first * 1000, bestFile.get("fileName"));
}
if (mods.containsKey(id)) {
File oldFile = new File(modsFolder.getAbsolutePath() + File.separator + modNames.get(id));
if (oldFile.exists() && oldFile.isFile()) oldFile.delete();
}
String loc = Utils.downloadFile(downloadUrl, modsFolder.getAbsolutePath(), ((String) bestFile.get("fileName")).replace(".jar", "_" + id + "_" + bestFile.get("id") + ".jar"));
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Downloaded " + loc));
} catch (Exception e) {
if (!Config.silentExceptions) e.printStackTrace();
}
}
for (String arg : Arrays.stream(ids).skip(1).toArray(String[]::new)) downloadMod(arg, config, modsFolder, mods, modNames);
System.out.println(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Finished all mod downloads."));
}

Expand Down
9 changes: 7 additions & 2 deletions src/ml/northwestwind/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,12 @@ public static boolean checkVersion(JSONArray versions, JSONObject config) {
boolean launcherMatch = false, versionMatch = false;
int trueCount = 0;
for (String s : LAUNCHERS)
if (versions.contains(s)) {
if (versions.stream().filter(str -> ((String) str).equalsIgnoreCase(s)).findAny().isPresent()) {
trueCount++;
if (s.equalsIgnoreCase(launcher)) {
launcherMatch = true;
break;
}
trueCount++;
}
// Assume it is ok if no launcher is specified by the mod file
if (trueCount == 0) launcherMatch = true;
Expand Down Expand Up @@ -323,6 +323,11 @@ public static boolean readYesNo() {
return res.equalsIgnoreCase("y");
}

public static String getModSlug(String id) {
JSONObject json = (JSONObject) readJsonFromUrl(Constants.CURSEFORGE_API + id);
return (String) json.get("slug");
}

@FunctionalInterface
public interface SupplierWithException<T> {
T getWithException() throws Exception;
Expand Down
3 changes: 3 additions & 0 deletions update.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"1.5.0": {
"title": "Automated mod dependencies installation & Fixed launcher checking for profile add"
},
"1.4.1": {
"title": "Prevent crashing when no versions directory is found"
},
Expand Down

0 comments on commit 5ea74c4

Please sign in to comment.