void CMissionManager::CleanupModFolder(const idStr& name) { CModInfoPtr info = GetModInfo(name); if (info == NULL) { DM_LOG(LC_MAINMENU, LT_INFO)LOGSTRING("Cannot erase mission folder for mod %s, mission info not found\r", name.c_str()); return; } // Delete folder contents fs::path modPath = info->GetModFolderPath().c_str(); if (fs::exists(modPath)) { // Iterate over all files in the mod folder for (fs::directory_iterator i(modPath); i != fs::directory_iterator(); ++i) { if (boost::algorithm::to_lower_copy(fs::extension(*i)) == ".pk4") { DM_LOG(LC_MAINMENU, LT_INFO)LOGSTRING("Won't erase PK4 files %s\r", i->path().string().c_str()); continue; } if (i->path().filename() == cv_tdm_fm_desc_file.GetString() || i->path().filename() == cv_tdm_fm_notes_file.GetString() || i->path().filename() == cv_tdm_fm_splashimage_file.GetString()) { DM_LOG(LC_MAINMENU, LT_INFO)LOGSTRING("Won't erase meta data file %s\r", i->path().string().c_str()); continue; } DM_LOG(LC_MAINMENU, LT_INFO)LOGSTRING("Will erase recursively: %s\r", i->path().string().c_str()); fs::remove_all(*i); } } else { DM_LOG(LC_MAINMENU, LT_INFO)LOGSTRING("Cannot erase mod folder %s, directory not found\r", modPath.string().c_str()); return; } info->ClearModFolderSize(); }
void CMissionManager::OnMissionStart() { CModInfoPtr info = GetCurrentModInfo(); if (info == NULL) { DM_LOG(LC_MAINMENU, LT_ERROR)LOGSTRING("Could not find mission info for current mod.\r"); return; } time_t seconds; tm* timeInfo; seconds = time(NULL); timeInfo = localtime(&seconds); // Mark the current difficulty level as completed info->SetKeyValue("last_play_date", va("%d-%02d-%02d", timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday)); }
void CMissionManager::RefreshMetaDataForNewFoundMods() { // greebo: If we have new found mods, refresh the meta data of the corresponding MissionDB entries // otherwise we end up with empty display names after downloading a mod we had on the HDD before for (int i = 0; i < _newFoundMods.Num(); ++i) { CModInfoPtr info = GetModInfo(_newFoundMods[i]); if (info != NULL) { if (info->LoadMetaData()) { DM_LOG(LC_MAINMENU, LT_INFO)LOGSTRING("Successfully read meta data for newly found mod %s\r", _newFoundMods[i].c_str()); } else { DM_LOG(LC_MAINMENU, LT_DEBUG)LOGSTRING("Could not read meta data for newly found mod %s\r", _newFoundMods[i].c_str()); } } } }
void CMissionManager::OnMissionComplete() { CModInfoPtr info = GetCurrentModInfo(); if (info == NULL) { DM_LOG(LC_MAINMENU, LT_ERROR)LOGSTRING("Could not find mission info for current mod.\r"); return; } // Ensure that this was the last mission if in campaign mode, otherwise ignore this call if (CurrentModIsCampaign()) { if (_curMissionIndex == -1) { gameLocal.Error("Invalid mission index in OnMissionComplete()"); } if (_curMissionIndex < _mapSequence.Num() - 1) { // This is not yet the last mission in the campaign, ignore this call return; } } // Mark the current difficulty level as completed info->SetKeyValue(va("mission_completed_%d", gameLocal.m_DifficultyManager.GetDifficultyLevel()), "1"); idPlayer* player = gameLocal.GetLocalPlayer(); if (player != NULL) { int gold, jewelry, goods; int total = player->Inventory()->GetLoot(gold, jewelry, goods); info->SetKeyValue(va("mission_loot_collected_%d", gameLocal.m_DifficultyManager.GetDifficultyLevel()), idStr(total)); } }
void CDownloadMenu::ShowDownloadResult( idUserInterface *gui ) { // greebo: Let the mod list be refreshed // We need the information from darkmod.txt later down this road gameLocal.m_MissionManager->ReloadModList(); int successfulDownloads = 0; int failedDownloads = 0; const DownloadableModList &mods = gameLocal.m_MissionManager->GetDownloadableMods(); for( ActiveDownloads::iterator i = _downloads.begin(); i != _downloads.end(); ++i ) { CDownloadPtr download = gameLocal.m_DownloadManager->GetDownload( i->second.missionDownloadId ); if( download == NULL ) { continue; } if( i->first > mods.Num() ) { continue; } const DownloadableMod &mod = *mods[i->first]; switch( download->GetStatus() ) { case CDownload::NOT_STARTED_YET: gameLocal.Warning( "Some downloads haven't been processed?" ); break; case CDownload::FAILED: failedDownloads++; break; case CDownload::IN_PROGRESS: gameLocal.Warning( "Some downloads still in progress?" ); break; case CDownload::SUCCESS: { // gnartsch bool l10nPackDownloaded = false; // In case of success, check l10n download status if( i->second.l10nPackDownloadId != -1 ) { CDownloadPtr l10nDownload = gameLocal.m_DownloadManager->GetDownload( i->second.l10nPackDownloadId ); CDownload::DownloadStatus l10nStatus = l10nDownload->GetStatus(); if( l10nStatus == CDownload::NOT_STARTED_YET || l10nStatus == CDownload::IN_PROGRESS ) { gameLocal.Warning( "Localisation pack download not started or still in progress?" ); } else if( l10nStatus == CDownload::FAILED ) { gameLocal.Warning( "Failed to download localisation pack!" ); // Turn this download into a failed one failedDownloads++; } else if( l10nStatus == CDownload::SUCCESS ) { // both successfully downloaded successfulDownloads++; // gnartsch l10nPackDownloaded = true; } } else { // regular download without l10n ... or l10n download only (gnartsch) successfulDownloads++; // gnartsch: Consider Localization pack having been dealt with as well l10nPackDownloaded = true; } // Save the mission version into the MissionDB for later use CModInfoPtr missionInfo = gameLocal.m_MissionManager->GetModInfo( mod.modName ); missionInfo->SetKeyValue( "downloaded_version", idStr( mod.version ).c_str() ); // gnartsch: Mark l10n pack as present, so that the mission may disappear from the list of 'Available Downloads' missionInfo->isL10NpackInstalled = l10nPackDownloaded; } break; }; } gameLocal.Printf( "Successful downloads: %d\nFailed downloads: %d\n", successfulDownloads, failedDownloads ); // Display the popup box GuiMessage msg; msg.type = GuiMessage::MSG_OK; msg.okCmd = "close_msg_box;onDownloadCompleteConfirm"; msg.title = common->Translate( "#str_02142" ); // "Mission Download Result" msg.message = ""; if( successfulDownloads > 0 ) { msg.message += va( // "%d mission/missions successfully downloaded. You'll find it/them in the 'New Mission' page." GetPlural( successfulDownloads, common->Translate( "#str_02144" ), common->Translate( "#str_02145" ) ), successfulDownloads ); } if( failedDownloads > 0 ) { // "\n%d mission(s) couldn't be downloaded. Please check your disk space (or maybe some file is write protected) and try again." msg.message += va( common->Translate( "#str_02146" ), failedDownloads ); } gameLocal.AddMainMenuMessage( msg ); // Remove all downloads for( ActiveDownloads::iterator i = _downloads.begin(); i != _downloads.end(); ++i ) { gameLocal.m_DownloadManager->RemoveDownload( i->second.missionDownloadId ); if( i->second.l10nPackDownloadId != -1 ) { gameLocal.m_DownloadManager->RemoveDownload( i->second.l10nPackDownloadId ); } } _downloads.clear(); }
void CMissionManager::LoadModListFromXml(const XmlDocumentPtr& doc) { assert(doc != NULL); /* Example XML Snippet <mission id="11" title="Living Expenses" releaseDate="2010-01-02" size="5.9" author="Sonosuke"> <downloadLocation language="English" url="http://www.bloodgate.com/mirrors/tdm/pub/pk4/fms/living_expenses.pk4"/> <downloadLocation language="German" url="http://www.bloodgate.com/mirrors/tdm/pub/pk4/fms/living_expenses_de.pk4"/> </mission> */ pugi::xpath_node_set nodes = doc->select_nodes("//tdm/availableMissions//mission"); const char* fs_currentfm = cvarSystem->GetCVarString("fs_currentfm"); // Tels: #3419 - After game start the sequence is always the same, so set a random seed time_t seconds = time(NULL); gameLocal.random.SetSeed( static_cast<int>(seconds) ); for (pugi::xpath_node_set::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { pugi::xml_node node = i->node(); DownloadableMod mission; mission.title = node.attribute("title").value(); mission.id = node.attribute("id").as_int(); mission.sizeMB = node.attribute("size").as_float(); mission.author = node.attribute("author").value(); mission.releaseDate = node.attribute("releaseDate").value(); mission.type = idStr::Icmp(node.attribute("type").value(), "multi") == 0 ? DownloadableMod::Multi : DownloadableMod::Single; mission.modName = node.attribute("internalName").value(); // Tels #3294: We need to clean the server-side modName of things like uppercase letters, trailing ".pk4" etc. // Otherwise we get duplicated entries in the MissionDB like "broads.pk4" and "broads" or "VFAT1" and "vfat1": mission.modName.ToLower(); mission.modName.StripTrailingOnce(".pk4"); // Clean modName string from any weird characters int modNameLen = mission.modName.Length(); for (int i = 0; i < modNameLen; ++i) { if (idStr::CharIsAlpha(mission.modName[i]) || idStr::CharIsNumeric(mission.modName[i])) continue; mission.modName[i] = '_'; // replace non-ASCII keys with underscores } mission.version = node.attribute("version").as_int(); mission.isUpdate = false; mission.needsL10NpackDownload = false; // gnartsch if (idStr::Cmp(mission.modName.c_str(), fs_currentfm) == 0) { DM_LOG(LC_MAINMENU, LT_DEBUG)LOGSTRING("Removing currently installed mission %s from the list of downloadable missions.\r", fs_currentfm); continue; } bool missionExists = false; // Check if this mission is already downloaded for (int j = 0; j < _availableMods.Num(); ++j) { if (idStr::Icmp(_availableMods[j], mission.modName) == 0) { missionExists = true; break; } } if (missionExists) { // Check mod version, there might be an update available if (_missionDB->ModInfoExists(mission.modName)) { CModInfoPtr missionInfo = _missionDB->GetModInfo(mission.modName); idStr versionStr = missionInfo->GetKeyValue("downloaded_version", "1"); int existingVersion = atoi(versionStr.c_str()); if (existingVersion >= mission.version) { // gnartsch : Skip to next mission only in case the localization pack // for the current mission had been downloaded already as well if (missionInfo->isL10NpackInstalled) { continue; // Our version is up to date } } else { mission.isUpdate = true; } } } // gnartsch : Process mission download locations only if the mission itself is not // present or not up to date, otherwise skip to the localization pack if (!missionExists || mission.isUpdate) { // Mission download links pugi::xpath_node_set downloadLocations = node.select_nodes("downloadLocation"); for (pugi::xpath_node_set::const_iterator loc = downloadLocations.begin(); loc != downloadLocations.end(); ++loc) { pugi::xml_node locNode = loc->node(); // Only accept English downloadlinks if (idStr::Icmp(locNode.attribute("language").value(), "english") != 0) continue; // Tels: #3419: Randomize the order of download URLs by inserting at a random place (+2 to avoid the first URL always being placed last) mission.missionUrls.Insert(locNode.attribute("url").value(), gameLocal.random.RandomInt( mission.missionUrls.Num() + 2 ) ); } } // Localisation packs // gnartsch: Process only if mission is either present locally or at least a download link for the mission is available. if (missionExists || mission.missionUrls.Num() > 0) { pugi::xpath_node_set l10PackNodes = node.select_nodes("localisationPack"); for (pugi::xpath_node_set::const_iterator loc = l10PackNodes.begin(); loc != l10PackNodes.end(); ++loc) { pugi::xml_node locNode = loc->node(); // Tels: #3419: Randomize the order of l10n URLs by inserting at a random place (+2 to avoid the first URL always being placed last) mission.l10nPackUrls.Insert(locNode.attribute("url").value(), gameLocal.random.RandomInt( mission.l10nPackUrls.Num() + 2 ) ); // gnartsch: Found a localization pack url for download mission.needsL10NpackDownload = true; } } // Only add missions with valid locations // gnartsch: add the mission in case localization pack needs to be downloaded if (mission.missionUrls.Num() > 0 || mission.l10nPackUrls.Num() > 0) { // Copy-construct the local mission struct into the heap-allocated one _downloadableMods.Append(new DownloadableMod(mission)); } } SortDownloadableMods(); }