diff --git a/src/commands/upgrade_command.ts b/src/commands/update_command.ts similarity index 100% rename from src/commands/upgrade_command.ts rename to src/commands/update_command.ts diff --git a/src/mod-manager.ts b/src/mod-manager.ts index 8db2155..7e2ecb7 100644 --- a/src/mod-manager.ts +++ b/src/mod-manager.ts @@ -11,7 +11,7 @@ import {ListCommand} from "./commands/list_command.js"; import UninstallCommand from "./commands/uninstall_command.js"; import EssentialCommand from "./commands/essential_command.js"; import {readFileSync, unlinkSync} from "fs"; -import UpdateCommand from "./commands/upgrade_command.js"; +import UpdateCommand from "./commands/update_command.js"; import MigratePossibleCommand from "./commands/migrate_possible.js"; import MigrateCommand from "./commands/migrate_command.js"; import ModrinthSource from "./mods/sources/modrinth_source.js"; diff --git a/src/mods/mod.d.ts b/src/mods/mod.d.ts index cd9b7fc..23f66a9 100644 --- a/src/mods/mod.d.ts +++ b/src/mods/mod.d.ts @@ -7,6 +7,7 @@ declare global { version: string source: string, essential: boolean, + dependencies: Array } type Version = { diff --git a/src/mods/mods.ts b/src/mods/mods.ts index 9cdded3..0d611d6 100644 --- a/src/mods/mods.ts +++ b/src/mods/mods.ts @@ -91,7 +91,7 @@ export default class Mods { writeFileSync(ModManager.FilePaths.MOD_FILE_PATH, JSON.stringify(mods, null, 4)); } - private static isModInstalled(id: string): boolean { + public static isModInstalled(id: string): boolean { const modsWithId: Array = this.getTrackedMods().filter(mod => mod.id == id); return !Util.isArrayEmpty(modsWithId) } @@ -105,6 +105,16 @@ export default class Mods { // IF a matching mod is found, remove it if (modToUninstall != undefined) { this.silentUninstall(modToUninstall); + + for (let dependency of modToUninstall.dependencies) { + if (!this.isDependedOn(dependency)) { + const dependencyMod = this.findMod(dependency); + if (dependencyMod != undefined) { + this.silentUninstall(dependencyMod) + } + } + } + spinner.succeed(`${modToUninstall.name} successfully uninstalled!`) } else { spinner.error(`${mod} was not found.`) @@ -128,6 +138,10 @@ export default class Mods { const modToMark = this.findMod(mod); if (modToMark != undefined) { + for (let dependency of modToMark.dependencies) { + this.toggleEssential(dependency) + } + let mods = this.getTrackedMods(); // Remove mod from list mods = mods.filter(item => !Mods.areModsEqual(item, modToMark)); @@ -147,9 +161,15 @@ export default class Mods { } } + /** + * Finds the mod based on the provided id or name + * @param mod the id or mod name + * @return the found Mod, or undefined if no mod was found + */ private static findMod(mod: string): TrackedMod | undefined { - // Replace underscores with spaces + // Replace underscores and dashes with spaces mod = mod.replaceAll("_", " "); + mod = mod.replaceAll("-", " ") let mods: Array = this.getTrackedMods(); for (let modEle of mods) { @@ -272,8 +292,8 @@ export default class Mods { /** * Migrates to the provided version of minecraft - * @param version - * @param force + * @param version the Minecraft version to migrate to + * @param force true if this is a force migration, false otherwise */ static async migrate(version: string, force: boolean) { const mods = this.getTrackedMods(); @@ -322,4 +342,15 @@ export default class Mods { await MinecraftUtils.updateCurrentMinecraftVersion(version) PrintUtils.success(`Successfully migrated to ${version}`) } + + private static isDependedOn(dependency: string) { + const trackedMods = this.getTrackedMods(); + + for (let trackedMod of trackedMods) { + if (trackedMod.dependencies.includes(dependency)) { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/src/mods/sources/modrinth_source.ts b/src/mods/sources/modrinth_source.ts index 392f760..e529a83 100644 --- a/src/mods/sources/modrinth_source.ts +++ b/src/mods/sources/modrinth_source.ts @@ -96,9 +96,15 @@ export default class ModrinthSource implements ModSource { */ async install(version: Version, essential: boolean): Promise { try { + if (Mods.isModInstalled(version.modId)) { + return; + } + + const dependencies = []; if (!Util.isArrayEmpty(version.dependencies)) { for (let dependency of version.dependencies) { await this.install(dependency, essential); + dependencies.push(dependency.modId) } } FileDownloader.downloadMod(version) @@ -110,6 +116,7 @@ export default class ModrinthSource implements ModSource { version: version.versionNumber, source: this.getSourceName(), essential: essential, + dependencies: dependencies } Mods.trackMod(mod); @@ -246,7 +253,37 @@ export default class ModrinthSource implements ModSource { } const latestVersion = results[0]; - return this.getVersionFromId(latestVersion.id); + const dependencies = []; + if (!Util.isArrayEmpty(latestVersion.dependencies)) { + for (let dependency of latestVersion.dependencies) { + if (dependency.dependency_type === "required") { + const projectId = dependency.project_id; + const versionId = dependency.version_id; + + dependencies.push(await this.getDependency(projectId, versionId, mcVersion)) + } + } + } + + const latestFile = latestVersion.files[0]; + + return { + modId: latestVersion.project_id, + versionNumber: latestVersion.version_number, + fileName: latestFile.filename, + url: latestFile.url, + dependencies: dependencies + }; + } + + async getDependency(projectId: string | undefined, versionId: string | undefined, mcVersion: string): Promise { + if (projectId != undefined) { + return this.getLatestVersion(projectId, mcVersion) + } else if (versionId != undefined) { + return this.getVersionFromVersionId(versionId, projectId, mcVersion) + } else { + throw new Error("Dependency found with no project or version id") + } } /** @@ -285,9 +322,11 @@ export default class ModrinthSource implements ModSource { * ] * } * @param versionId the version id to transform into an object + * @param projectId the project id of this version + * @param mcVersion the Minecraft version we are downloading for * @return the Version object */ - async getVersionFromId(versionId: string): Promise { + async getVersionFromVersionId(versionId: string, projectId: string | undefined, mcVersion: string): Promise { const response = await axios.get(format(ModrinthSource.SINGLE_VERSION_URL, versionId)); const latestVersion = await response.data; @@ -296,7 +335,7 @@ export default class ModrinthSource implements ModSource { const dependencies = []; if (!Util.isArrayEmpty(latestVersion.dependencies)) { for (let dependency of latestVersion.dependencies) { - dependencies.push(await this.getVersionFromId(dependency.version_id)) + dependencies.push(await this.getDependency(projectId, dependency.version_id, mcVersion)) } }