diff --git a/primedev/mods/autodownload/moddownloader.cpp b/primedev/mods/autodownload/moddownloader.cpp index 2a8b3c6a9..da20b3d89 100644 --- a/primedev/mods/autodownload/moddownloader.cpp +++ b/primedev/mods/autodownload/moddownloader.cpp @@ -106,23 +106,23 @@ void ModDownloader::FetchModsListFromAPI() for (auto i = verifiedModsJson.MemberBegin(); i != verifiedModsJson.MemberEnd(); ++i) { // Format testing - if (!i->value.HasMember("Repository") || !i->value.HasMember("Versions")) + if (!i->value.HasMember("DependencyPrefix") || !i->value.HasMember("Versions")) { spdlog::warn("Verified mods manifesto format is unrecognized, skipping loading."); return; } std::string name = i->name.GetString(); - std::unordered_map modVersions; + std::string dependency = i->value["DependencyPrefix"].GetString(); + std::unordered_map modVersions; rapidjson::Value& versions = i->value["Versions"]; assert(versions.IsArray()); for (auto& attribute : versions.GetArray()) { assert(attribute.IsObject()); // Format testing - if (!attribute.HasMember("Version") || !attribute.HasMember("Checksum") || !attribute.HasMember("DownloadLink") || - !attribute.HasMember("Platform")) + if (!attribute.HasMember("Version") || !attribute.HasMember("Checksum")) { spdlog::warn("Verified mods manifesto format is unrecognized, skipping loading."); return; @@ -130,14 +130,10 @@ void ModDownloader::FetchModsListFromAPI() std::string version = attribute["Version"].GetString(); std::string checksum = attribute["Checksum"].GetString(); - std::string downloadLink = attribute["DownloadLink"].GetString(); - std::string platformValue = attribute["Platform"].GetString(); - VerifiedModPlatform platform = - platformValue.compare("thunderstore") == 0 ? VerifiedModPlatform::Thunderstore : VerifiedModPlatform::Unknown; - modVersions.insert({version, {.checksum = checksum, .downloadLink = downloadLink, .platform = platform}}); + modVersions.insert({version, {.checksum = checksum}}); } - VerifiedModDetails modConfig = {.versions = modVersions}; + VerifiedModDetails modConfig = {.dependencyPrefix = dependency, .versions = modVersions}; verifiedMods.insert({name, modConfig}); spdlog::info("==> Loaded configuration for mod \"" + name + "\""); } @@ -171,10 +167,13 @@ int ModDownloader::ModFetchingProgressCallback( return 0; } -std::optional ModDownloader::FetchModFromDistantStore(std::string_view modName, VerifiedModVersion version) +std::optional ModDownloader::FetchModFromDistantStore(std::string_view modName, std::string_view modVersion) { - std::string url = version.downloadLink; - std::string archiveName = fs::path(url).filename().generic_string(); + // Retrieve mod prefix from local mods list, or use mod name as mod prefix if bypass flag is set + std::string modPrefix = strstr(GetCommandLineA(), VERIFICATION_FLAG) ? modName.data() : verifiedMods[modName.data()].dependencyPrefix; + // Build archive distant URI + std::string archiveName = std::format("{}-{}.zip", modPrefix, modVersion.data()); + std::string url = STORE_URL + archiveName; spdlog::info(std::format("Fetching mod archive from {}", url)); // Download destination @@ -394,7 +393,7 @@ int GetModArchiveSize(unzFile file, unz_global_info64 info) return totalSize; } -void ModDownloader::ExtractMod(fs::path modPath, VerifiedModPlatform platform) +void ModDownloader::ExtractMod(fs::path modPath) { unzFile file; std::string name; @@ -432,14 +431,6 @@ void ModDownloader::ExtractMod(fs::path modPath, VerifiedModPlatform platform) modState.total = GetModArchiveSize(file, gi); modState.progress = 0; - // Right now, we only know how to extract Thunderstore mods - if (platform != VerifiedModPlatform::Thunderstore) - { - spdlog::error("Failed extracting mod from unknown platform (value: {}).", platform); - modState.state = UNKNOWN_PLATFORM; - return; - } - // Mod directory name (removing the ".zip" fom the archive name) name = modPath.filename().string(); name = name.substr(0, name.length() - 4); @@ -602,9 +593,11 @@ void ModDownloader::DownloadMod(std::string modName, std::string modVersion) fs::path archiveLocation; // Download mod archive - VerifiedModVersion fullVersion = verifiedMods[modName].versions[modVersion]; - std::string expectedHash = fullVersion.checksum; - std::optional fetchingResult = FetchModFromDistantStore(std::string_view(modName), fullVersion); + + std::string expectedHash = verifiedMods[modName].versions[modVersion].checksum; + std::optional fetchingResult = FetchModFromDistantStore(std::string_view(modName), std::string_view(modVersion)); + + if (!fetchingResult.has_value()) { spdlog::error("Something went wrong while fetching archive, aborting."); @@ -638,7 +631,20 @@ void ModDownloader::DownloadMod(std::string modName, std::string modVersion) } // Extract downloaded mod archive - ExtractMod(archiveLocation, fullVersion.platform); + ExtractMod(archiveLocation); + try + { + remove(archiveLocation); + } + catch (const std::exception& a) + { + spdlog::error("Error while removing downloaded archive: {}", a.what()); + } + + modState.state = DONE; + this->isDownloadingMod = false; + spdlog::info("Done downloading {}.", modName); + return; }); requestThread.detach(); diff --git a/primedev/mods/autodownload/moddownloader.h b/primedev/mods/autodownload/moddownloader.h index d1eb671cd..2dfa7925c 100644 --- a/primedev/mods/autodownload/moddownloader.h +++ b/primedev/mods/autodownload/moddownloader.h @@ -7,22 +7,18 @@ class ModDownloader private: const char* VERIFICATION_FLAG = "-disablemodverification"; const char* CUSTOM_MODS_URL_FLAG = "-customverifiedurl="; - const char* DEFAULT_MODS_LIST_URL = "https://raw.githubusercontent.com/R2Northstar/VerifiedMods/main/verified-mods.json"; + const char* STORE_URL = "https://gcdn.thunderstore.io/live/repository/packages/"; + const char* DEFAULT_MODS_LIST_URL = "https://gitee.com/R2NorthstarCN/VerifiedMods/raw/master/verified-mods.json"; char* modsListUrl; + - enum class VerifiedModPlatform - { - Unknown, - Thunderstore - }; struct VerifiedModVersion { std::string checksum; - std::string downloadLink; - VerifiedModPlatform platform; }; struct VerifiedModDetails { + std::string dependencyPrefix; std::unordered_map versions = {}; }; std::unordered_map verifiedMods = {}; @@ -52,7 +48,7 @@ class ModDownloader * @param modVersion version of the mod to be downloaded * @returns location of the downloaded archive */ - std::optional FetchModFromDistantStore(std::string_view modName, VerifiedModVersion modVersion); + std::optional FetchModFromDistantStore(std::string_view modName, std::string_view modVersion); /** * Tells if a mod archive has not been corrupted. @@ -72,13 +68,12 @@ class ModDownloader * Extracts a mod archive to the game folder. * * This extracts a downloaded mod archive from its original location to the - * current game profile; the install folder is defined by the platform parameter. + * current game profile, in the remote mods folder. * * @param modPath location of the downloaded archive - * @param platform origin of the downloaded archive * @returns nothing */ - void ExtractMod(fs::path modPath, VerifiedModPlatform platform); + void ExtractMod(fs::path modPath); public: ModDownloader(); @@ -141,8 +136,7 @@ class ModDownloader MOD_FETCHING_FAILED, MOD_CORRUPTED, // Downloaded archive checksum does not match verified hash NO_DISK_SPACE_AVAILABLE, - NOT_FOUND, // Mod is not currently being auto-downloaded - UNKNOWN_PLATFORM + NOT_FOUND // Mod is not currently being auto-downloaded }; struct MOD_STATE