mirror of
https://github.com/R2Northstar/NorthstarLauncher
synced 2026-08-23 20:26:04 -04:00
feat: Add ModWorkshop support to MAD (#873)
* feat: add ModWorkshop support for MAD
This commit is contained in:
parent
f5bd7c9b95
commit
c0ed69f795
3 changed files with 77 additions and 14 deletions
|
|
@ -129,8 +129,7 @@ void ModDownloader::FetchModsListFromAPI()
|
|||
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;
|
||||
VerifiedModPlatform platform = resolvePlatform(platformValue);
|
||||
modVersions.insert({version, {.checksum = checksum, .downloadLink = downloadLink, .platform = platform}});
|
||||
}
|
||||
|
||||
|
|
@ -176,13 +175,28 @@ int ModDownloader::ModFetchingProgressCallback(
|
|||
return 0;
|
||||
}
|
||||
|
||||
std::string ModDownloader::GetModArchiveName(std::string url)
|
||||
{
|
||||
std::string name = fs::path(url).filename().generic_string();
|
||||
std::string::size_type charIndex = name.find("?");
|
||||
|
||||
// Thunderstore format
|
||||
if (std::string::npos == charIndex)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
// ModWorkshop format (removing the "?filename=" part)
|
||||
return name.substr(charIndex + 10);
|
||||
}
|
||||
|
||||
std::tuple<fs::path, bool> ModDownloader::FetchModFromDistantStore(std::string_view modName, VerifiedModVersion version)
|
||||
{
|
||||
std::string url = version.downloadLink;
|
||||
std::string archiveName = fs::path(url).filename().generic_string();
|
||||
spdlog::info(std::format("Fetching mod archive from {}", url));
|
||||
|
||||
// Download destination
|
||||
spdlog::info(std::format("Fetching mod archive from {}", url));
|
||||
std::string archiveName = ModDownloader::GetModArchiveName(url);
|
||||
std::filesystem::path downloadPath = std::filesystem::temp_directory_path() / archiveName;
|
||||
spdlog::info(std::format("Downloading archive to {}", downloadPath.generic_string()));
|
||||
|
||||
|
|
@ -436,10 +450,10 @@ void ModDownloader::ExtractMod(fs::path modPath, fs::path destinationPath, Verif
|
|||
modState.total = GetModArchiveSize(file, gi);
|
||||
modState.progress = 0;
|
||||
|
||||
// Right now, we only know how to extract Thunderstore mods
|
||||
if (platform != VerifiedModPlatform::Thunderstore)
|
||||
// We don't know how to extract mods from unknown platforms
|
||||
if (platform == VerifiedModPlatform::Unknown)
|
||||
{
|
||||
spdlog::error("Failed extracting mod from unknown platform (value: {}).", platform);
|
||||
spdlog::error("Failed extracting mod from unknown platform.");
|
||||
modState.state = UNKNOWN_PLATFORM;
|
||||
return;
|
||||
}
|
||||
|
|
@ -658,10 +672,19 @@ void ModDownloader::DownloadMod(std::string modName, std::string modVersion)
|
|||
return;
|
||||
}
|
||||
|
||||
// Mod directory name (removing the ".zip" fom the archive name)
|
||||
name = archiveLocation.filename().string();
|
||||
name = name.substr(0, name.length() - 4);
|
||||
modDirectory = GetRemoteModFolderPath() / name;
|
||||
// Mod directory name
|
||||
/// Don't use archive name as destination with ModWorkshop
|
||||
if (fullVersion.platform == VerifiedModPlatform::ModWorkshop)
|
||||
{
|
||||
modDirectory = GetRemoteModFolderPath();
|
||||
}
|
||||
else
|
||||
/// Removes the ".zip" fom the archive name and use it as parent directory
|
||||
{
|
||||
name = archiveLocation.filename().string();
|
||||
name = name.substr(0, name.length() - 4);
|
||||
modDirectory = GetRemoteModFolderPath() / name;
|
||||
}
|
||||
|
||||
// Extract downloaded mod archive
|
||||
ExtractMod(archiveLocation, modDirectory, fullVersion.platform);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,21 @@ private:
|
|||
enum class VerifiedModPlatform
|
||||
{
|
||||
Unknown,
|
||||
ModWorkshop,
|
||||
Thunderstore
|
||||
};
|
||||
VerifiedModPlatform resolvePlatform(std::string input)
|
||||
{
|
||||
if (input.compare("thunderstore") == 0)
|
||||
{
|
||||
return VerifiedModPlatform::Thunderstore;
|
||||
}
|
||||
if (input.compare("modworkshop") == 0)
|
||||
{
|
||||
return VerifiedModPlatform::ModWorkshop;
|
||||
}
|
||||
return VerifiedModPlatform::Unknown;
|
||||
}
|
||||
struct VerifiedModVersion
|
||||
{
|
||||
std::string checksum;
|
||||
|
|
@ -78,6 +91,22 @@ private:
|
|||
*/
|
||||
void ExtractMod(fs::path modPath, fs::path destinationPath, VerifiedModPlatform platform);
|
||||
|
||||
/**
|
||||
* Retrieves archive name from input URL.
|
||||
*
|
||||
* Thunderstore and ModWorkshop do not format their URLs the same way:
|
||||
* - Thunderstore: https://gcdn.thunderstore.io/live/repository/packages/Nyami11-mp_brick-1.0.2.zip
|
||||
* - ModWorkshop:
|
||||
* https://storage.modworkshop.net/mods/files/46563_156759_CSio1Cd3QVXYRZLd1h6iNu0IPuuaY9ePKGceQD31.zip?filename=em4v.zip
|
||||
*
|
||||
* This takes those differences into account and returns an archive name for
|
||||
* both types of URLs.
|
||||
*
|
||||
* @param url URL from which to extract archive file name
|
||||
* @returns name of the archive to be downloaded
|
||||
*/
|
||||
std::string GetModArchiveName(std::string url);
|
||||
|
||||
public:
|
||||
ModDownloader();
|
||||
|
||||
|
|
|
|||
|
|
@ -448,19 +448,30 @@ void ModManager::SearchFilesystemForMods()
|
|||
std::filesystem::directory_iterator remoteModsDir = fs::directory_iterator(GetRemoteModFolderPath());
|
||||
std::filesystem::directory_iterator thunderstoreModsDir = fs::directory_iterator(GetThunderstoreModFolderPath());
|
||||
|
||||
for (fs::directory_entry dir : classicModsDir)
|
||||
if (fs::exists(dir.path() / "mod.json"))
|
||||
modDirs.push_back(dir.path());
|
||||
for (fs::directory_iterator dirIterator : {classicModsDir, remoteModsDir})
|
||||
for (fs::directory_entry dir : dirIterator)
|
||||
if (fs::exists(dir.path() / "mod.json"))
|
||||
modDirs.push_back(dir.path());
|
||||
|
||||
// Special case for Thunderstore and remote mods directories
|
||||
// Set up regex for `AUTHOR-MOD-VERSION` pattern
|
||||
std::regex pattern(R"(.*\\([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)-(\d+\.\d+\.\d+))");
|
||||
|
||||
// Reset directory iterator
|
||||
remoteModsDir = fs::directory_iterator(GetRemoteModFolderPath());
|
||||
|
||||
for (fs::directory_iterator dirIterator : {thunderstoreModsDir, remoteModsDir})
|
||||
{
|
||||
for (fs::directory_entry dir : dirIterator)
|
||||
{
|
||||
fs::path modsDir = dir.path() / "mods"; // Check for mods folder in the Thunderstore mod
|
||||
|
||||
// Do not register ModWorkshop mods twice
|
||||
if (std::find(modDirs.begin(), modDirs.end(), dir.path()) != modDirs.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use regex to match `AUTHOR-MOD-VERSION` pattern
|
||||
if (!std::regex_match(dir.path().string(), pattern))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue