diff --git a/Mods/vcmi/config/vcmi/chinese.json b/Mods/vcmi/config/vcmi/chinese.json index 666b2168b..a62b3a606 100644 --- a/Mods/vcmi/config/vcmi/chinese.json +++ b/Mods/vcmi/config/vcmi/chinese.json @@ -30,9 +30,9 @@ "vcmi.capitalColors.6" : "褐色", "vcmi.capitalColors.7" : "粉色", - "vcmi.server.errors.existingProcess" : "一个VCMI进程已经在运行,启动新进程前请结束它。", - "vcmi.server.errors.modsIncompatibility" : "需要加载的MOD列表:", - "vcmi.server.confirmReconnect" : "您想要重连上一个会话么?", + "vcmi.server.errors.existingProcess" : "一个VCMI进程已经在运行,启动新进程前请结束它。", + "vcmi.server.errors.modsToEnable" : "{需要加载的MOD列表}", + "vcmi.server.confirmReconnect" : "您想要重连上一个会话么?", "vcmi.settingsMainWindow.generalTab.hover" : "常规", "vcmi.settingsMainWindow.generalTab.help" : "切换到“常规”选项卡 - 设置游戏客户端呈现", diff --git a/Mods/vcmi/config/vcmi/czech.json b/Mods/vcmi/config/vcmi/czech.json index dcbb8ccaf..04aa13f30 100644 --- a/Mods/vcmi/config/vcmi/czech.json +++ b/Mods/vcmi/config/vcmi/czech.json @@ -48,9 +48,9 @@ "vcmi.lobby.filename" : "Název souboru", "vcmi.lobby.creationDate" : "Datum vytvoření", - "vcmi.server.errors.existingProcess" : "Již běží jiný server VCMI. Prosím, ukončete ho před startem nové hry.", - "vcmi.server.errors.modsIncompatibility" : "Následující modifikace jsou nutné pro načtení hry:", - "vcmi.server.confirmReconnect" : "Chcete se připojit k poslední relaci?", + "vcmi.server.errors.existingProcess" : "Již běží jiný server VCMI. Prosím, ukončete ho před startem nové hry.", + "vcmi.server.errors.modsToEnable" : "{Následující modifikace jsou nutné pro načtení hry}", + "vcmi.server.confirmReconnect" : "Chcete se připojit k poslední relaci?", "vcmi.settingsMainWindow.generalTab.hover" : "Obecné", "vcmi.settingsMainWindow.generalTab.help" : "Přepne na kartu obecných nastavení, která obsahuje nastavení související s obecným chováním klienta hry", diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index cc95f3e30..5e2279dfe 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -53,9 +53,10 @@ "vcmi.lobby.filename" : "Filename", "vcmi.lobby.creationDate" : "Creation date", - "vcmi.server.errors.existingProcess" : "Another VCMI server process is running. Please terminate it before starting a new game.", - "vcmi.server.errors.modsIncompatibility" : "The following mods are required to load the game:", - "vcmi.server.confirmReconnect" : "Do you want to reconnect to the last session?", + "vcmi.server.errors.existingProcess" : "Another VCMI server process is running. Please terminate it before starting a new game.", + "vcmi.server.errors.modsToEnable" : "{Following mods are required}", + "vcmi.server.errors.modsToDisable" : "{Following mods must be disabled}", + "vcmi.server.confirmReconnect" : "Do you want to reconnect to the last session?", "vcmi.settingsMainWindow.generalTab.hover" : "General", "vcmi.settingsMainWindow.generalTab.help" : "Switches to General Options tab, which contains settings related to general game client behavior.", diff --git a/Mods/vcmi/config/vcmi/french.json b/Mods/vcmi/config/vcmi/french.json index 5d3e0a532..69112035d 100644 --- a/Mods/vcmi/config/vcmi/french.json +++ b/Mods/vcmi/config/vcmi/french.json @@ -38,9 +38,9 @@ "vcmi.mainMenu.joinTCP" : "Rejoindre TCP/IP jeu", "vcmi.mainMenu.playerName" : "Joueur", - "vcmi.server.errors.existingProcess" : "Un autre processus de serveur VCMI est en cours d'exécution. Veuillez l'arrêter' avant de démarrer un nouveau jeu.", - "vcmi.server.errors.modsIncompatibility" : "Les mods suivants sont nécessaires pour charger le jeu :", - "vcmi.server.confirmReconnect" : "Voulez-vous vous reconnecter à la dernière session ?", + "vcmi.server.errors.existingProcess" : "Un autre processus de serveur VCMI est en cours d'exécution. Veuillez l'arrêter' avant de démarrer un nouveau jeu.", + "vcmi.server.errors.modsToEnable" : "{Les mods suivants sont nécessaires pour charger le jeu}", + "vcmi.server.confirmReconnect" : "Voulez-vous vous reconnecter à la dernière session ?", "vcmi.settingsMainWindow.generalTab.hover" : "Général", "vcmi.settingsMainWindow.generalTab.help" : "Passe à l'onglet Options générales, qui contient des paramètres liés au comportement général du client de jeu", diff --git a/Mods/vcmi/config/vcmi/german.json b/Mods/vcmi/config/vcmi/german.json index 926501565..fe6f63828 100644 --- a/Mods/vcmi/config/vcmi/german.json +++ b/Mods/vcmi/config/vcmi/german.json @@ -52,9 +52,9 @@ "vcmi.lobby.filename" : "Dateiname", "vcmi.lobby.creationDate" : "Erstellungsdatum", - "vcmi.server.errors.existingProcess" : "Es läuft ein weiterer vcmiserver-Prozess, bitte beendet diesen zuerst", - "vcmi.server.errors.modsIncompatibility" : "Erforderliche Mods um das Spiel zu laden:", - "vcmi.server.confirmReconnect" : "Mit der letzten Sitzung verbinden?", + "vcmi.server.errors.existingProcess" : "Es läuft ein weiterer vcmiserver-Prozess, bitte beendet diesen zuerst", + "vcmi.server.errors.modsToEnable" : "{Erforderliche Mods um das Spiel zu laden}", + "vcmi.server.confirmReconnect" : "Mit der letzten Sitzung verbinden?", "vcmi.settingsMainWindow.generalTab.hover" : "Allgemein", "vcmi.settingsMainWindow.generalTab.help" : "Wechselt zur Registerkarte Allgemeine Optionen, die Einstellungen zum allgemeinen Verhalten des Spielclients enthält.", diff --git a/Mods/vcmi/config/vcmi/polish.json b/Mods/vcmi/config/vcmi/polish.json index f382a9578..af4eac0c6 100644 --- a/Mods/vcmi/config/vcmi/polish.json +++ b/Mods/vcmi/config/vcmi/polish.json @@ -47,9 +47,9 @@ "vcmi.lobby.filename" : "Nazwa pliku", "vcmi.lobby.creationDate" : "Data utworzenia", - "vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej", - "vcmi.server.errors.modsIncompatibility" : "Następujące mody są wymagane do wczytania gry:", - "vcmi.server.confirmReconnect" : "Połączyć ponownie z ostatnią sesją?", + "vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej", + "vcmi.server.errors.modsToEnable" : "{Następujące mody są wymagane do wczytania gry}", + "vcmi.server.confirmReconnect" : "Połączyć ponownie z ostatnią sesją?", "vcmi.settingsMainWindow.generalTab.hover" : "Ogólne", "vcmi.settingsMainWindow.generalTab.help" : "Przełącza do zakładki opcji ogólnych, która zawiera ustawienia związane z ogólnym działaniem gry", diff --git a/Mods/vcmi/config/vcmi/russian.json b/Mods/vcmi/config/vcmi/russian.json index 51d13ac0d..63d1a2d48 100644 --- a/Mods/vcmi/config/vcmi/russian.json +++ b/Mods/vcmi/config/vcmi/russian.json @@ -21,9 +21,9 @@ "vcmi.adventureMap.moveCostDetails" : "Очки движения - Стоимость: %TURNS ходов + %POINTS очков, Останется: %REMAINING очков", "vcmi.adventureMap.moveCostDetailsNoTurns" : "Очки движения - Стоимость: %POINTS очков, Останется: %REMAINING очков", - "vcmi.server.errors.existingProcess" : "Запущен другой процесс vcmiserver, сначала завершите его.", - "vcmi.server.errors.modsIncompatibility" : "Требуемые моды для загрузки игры:", - "vcmi.server.confirmReconnect" : "Подключиться к предыдущей сессии?", + "vcmi.server.errors.existingProcess" : "Запущен другой процесс vcmiserver, сначала завершите его.", + "vcmi.server.errors.modsToEnable" : "{Требуемые моды для загрузки игры}", + "vcmi.server.confirmReconnect" : "Подключиться к предыдущей сессии?", "vcmi.settingsMainWindow.generalTab.hover" : "Общее", "vcmi.settingsMainWindow.generalTab.help" : "Переключиться на вкладку \"Общее\", содержащее общие настройки клиента игры", diff --git a/Mods/vcmi/config/vcmi/spanish.json b/Mods/vcmi/config/vcmi/spanish.json index ffc43609b..e18986ebc 100644 --- a/Mods/vcmi/config/vcmi/spanish.json +++ b/Mods/vcmi/config/vcmi/spanish.json @@ -30,9 +30,9 @@ "vcmi.capitalColors.6" : "Turquesa", "vcmi.capitalColors.7" : "Rosa", - "vcmi.server.errors.existingProcess" : "Otro proceso de vcmiserver está en ejecución, por favor termínalo primero", - "vcmi.server.errors.modsIncompatibility" : "Mods necesarios para cargar el juego:", - "vcmi.server.confirmReconnect" : "¿Conectar a la última sesión?", + "vcmi.server.errors.existingProcess" : "Otro proceso de vcmiserver está en ejecución, por favor termínalo primero", + "vcmi.server.errors.modsToEnable" : "{Mods necesarios para cargar el juego}", + "vcmi.server.confirmReconnect" : "¿Conectar a la última sesión?", "vcmi.settingsMainWindow.generalTab.hover" : "General", "vcmi.settingsMainWindow.generalTab.help" : "Cambiar a la pestaña de opciones generales, que contiene ajustes relacionados con el comportamiento general del juego", diff --git a/Mods/vcmi/config/vcmi/ukrainian.json b/Mods/vcmi/config/vcmi/ukrainian.json index 78f16b9d4..315a837ad 100644 --- a/Mods/vcmi/config/vcmi/ukrainian.json +++ b/Mods/vcmi/config/vcmi/ukrainian.json @@ -48,9 +48,9 @@ "vcmi.lobby.filename" : "Назва файлу", "vcmi.lobby.creationDate" : "Дата створення", - "vcmi.server.errors.existingProcess" : "Працює інший процес vcmiserver, будь ласка, спочатку завершіть його", - "vcmi.server.errors.modsIncompatibility" : "Потрібні модифікації для завантаження гри:", - "vcmi.server.confirmReconnect" : "Підключитися до минулої сесії?", + "vcmi.server.errors.existingProcess" : "Працює інший процес vcmiserver, будь ласка, спочатку завершіть його", + "vcmi.server.errors.modsToEnable" : "{Потрібні модифікації для завантаження гри}", + "vcmi.server.confirmReconnect" : "Підключитися до минулої сесії?", "vcmi.settingsMainWindow.generalTab.hover" : "Загальні", "vcmi.settingsMainWindow.generalTab.help" : "Перемикає на вкладку загальних параметрів, яка містить налаштування, пов'язані із загальною поведінкою ігрового клієнта", diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index 5f7097f81..3a0943f01 100644 --- a/client/CServerHandler.cpp +++ b/client/CServerHandler.cpp @@ -552,10 +552,17 @@ bool CServerHandler::validateGameStart(bool allowOnlyAI) const catch(ModIncompatibility & e) { logGlobal->warn("Incompatibility exception during start scenario: %s", e.what()); - - auto errorMsg = CGI->generaltexth->translate("vcmi.server.errors.modsIncompatibility") + '\n'; - errorMsg += e.what(); - + std::string errorMsg; + if(!e.whatMissing().empty()) + { + errorMsg += VLC->generaltexth->translate("vcmi.server.errors.modsToEnable") + '\n'; + errorMsg += e.whatMissing(); + } + if(!e.whatExcessive().empty()) + { + errorMsg += VLC->generaltexth->translate("vcmi.server.errors.modsToDisable") + '\n'; + errorMsg += e.whatExcessive(); + } showServerError(errorMsg); return false; } diff --git a/client/lobby/CLobbyScreen.cpp b/client/lobby/CLobbyScreen.cpp index dba561388..f2256f91f 100644 --- a/client/lobby/CLobbyScreen.cpp +++ b/client/lobby/CLobbyScreen.cpp @@ -29,7 +29,6 @@ #include "../../lib/CGeneralTextHandler.h" #include "../../lib/campaign/CampaignHandler.h" #include "../../lib/mapping/CMapInfo.h" -#include "../../lib/modding/ModIncompatibility.h" #include "../../lib/rmg/CMapGenOptions.h" CLobbyScreen::CLobbyScreen(ESelectionScreen screenType) diff --git a/lib/StartInfo.cpp b/lib/StartInfo.cpp index c8100987a..f3abd2d92 100644 --- a/lib/StartInfo.cpp +++ b/lib/StartInfo.cpp @@ -74,12 +74,12 @@ void LobbyInfo::verifyStateBeforeStart(bool ignoreNoHuman) const throw std::domain_error(VLC->generaltexth->translate("core.genrltxt.529")); auto missingMods = CMapService::verifyMapHeaderMods(*mi->mapHeader); - ModIncompatibility::ModList modList; + ModIncompatibility::ModListWithVersion modList; for(const auto & m : missingMods) modList.push_back({m.second.name, m.second.version.toString()}); if(!modList.empty()) - throw ModIncompatibility(std::move(modList)); + throw ModIncompatibility(modList); //there must be at least one human player before game can be started std::map::const_iterator i; diff --git a/lib/modding/CModHandler.cpp b/lib/modding/CModHandler.cpp index 553c41d98..f872bc642 100644 --- a/lib/modding/CModHandler.cpp +++ b/lib/modding/CModHandler.cpp @@ -481,6 +481,10 @@ void CModHandler::trySetActiveMods(const std::vector newActiveMods, missingMods, excessiveMods; + ModIncompatibility::ModListWithVersion missingModsResult; + ModIncompatibility::ModList excessiveModsResult; + for(const auto & m : activeMods) { if(searchVerificationInfo(m)) @@ -488,11 +492,11 @@ void CModHandler::trySetActiveMods(const std::vector newActiveMods, missingMods; - ModIncompatibility::ModList missingModsResult; for(const auto & infoPair : modList) { @@ -539,9 +543,17 @@ void CModHandler::trySetActiveMods(const std::vectorname, vInfo->version.toString()}); } } + for(auto & m : excessiveMods) + { + auto & vInfo = getModInfo(m).getVerificationInfo(); + assert(vInfo.parent != m); + if(!vInfo.parent.empty() && vstd::contains(excessiveMods, vInfo.parent)) + continue; + excessiveModsResult.push_back(vInfo.name); + } - if(!missingModsResult.empty()) - throw ModIncompatibility(std::move(missingModsResult)); + if(!missingModsResult.empty() || !excessiveModsResult.empty()) + throw ModIncompatibility(missingModsResult, excessiveModsResult); //TODO: support actual enabling of these mods for(auto & m : newActiveMods) diff --git a/lib/modding/ModIncompatibility.h b/lib/modding/ModIncompatibility.h index ee7e2e2c4..199e4098e 100644 --- a/lib/modding/ModIncompatibility.h +++ b/lib/modding/ModIncompatibility.h @@ -14,29 +14,44 @@ VCMI_LIB_NAMESPACE_BEGIN class DLL_LINKAGE ModIncompatibility: public std::exception { public: - using StringPair = std::pair; - using ModList = std::list; + using ModListWithVersion = std::vector>; + using ModList = std::vector; - ModIncompatibility(ModList && _missingMods): - missingMods(std::move(_missingMods)) + ModIncompatibility(const ModListWithVersion & _missingMods) { std::ostringstream _ss; - for(const auto & m : missingMods) + for(const auto & m : _missingMods) _ss << m.first << ' ' << m.second << std::endl; - message = _ss.str(); + messageMissingMods = _ss.str(); } - + + ModIncompatibility(const ModListWithVersion & _missingMods, ModList & _excessiveMods) + : ModIncompatibility(_missingMods) + { + std::ostringstream _ss; + for(const auto & m : _excessiveMods) + _ss << m << std::endl; + messageExcessiveMods = _ss.str(); + } + const char * what() const noexcept override { - return message.c_str(); + static const std::string w("Mod incompatibility exception"); + return w.c_str(); + } + + const std::string & whatMissing() const noexcept + { + return messageMissingMods; + } + + const std::string & whatExcessive() const noexcept + { + return messageExcessiveMods; } private: - //list of mods required to load the game - // first: mod name - // second: mod version - const ModList missingMods; - std::string message; + std::string messageMissingMods, messageExcessiveMods; }; VCMI_LIB_NAMESPACE_END diff --git a/mapeditor/mainwindow.cpp b/mapeditor/mainwindow.cpp index 3d23b923f..8242ee5ec 100644 --- a/mapeditor/mainwindow.cpp +++ b/mapeditor/mainwindow.cpp @@ -336,19 +336,20 @@ bool MainWindow::openMap(const QString & filenameSelect) if(auto header = mapService.loadMapHeader(resId)) { auto missingMods = CMapService::verifyMapHeaderMods(*header); - ModIncompatibility::ModList modList; + ModIncompatibility::ModListWithVersion modList; for(const auto & m : missingMods) modList.push_back({m.second.name, m.second.version.toString()}); if(!modList.empty()) - throw ModIncompatibility(std::move(modList)); + throw ModIncompatibility(modList); controller.setMap(mapService.loadMap(resId)); } } catch(const ModIncompatibility & e) { - QMessageBox::warning(this, "Mods requiered", e.what()); + assert(e.whatExcessive().empty()); + QMessageBox::warning(this, "Mods are requiered", QString::fromStdString(e.whatMissing())); return false; } catch(const std::exception & e) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 3c525b416..ad792ce12 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1765,8 +1765,17 @@ bool CGameHandler::load(const std::string & filename) catch(const ModIncompatibility & e) { logGlobal->error("Failed to load game: %s", e.what()); - auto errorMsg = VLC->generaltexth->translate("vcmi.server.errors.modsIncompatibility") + '\n'; - errorMsg += e.what(); + std::string errorMsg; + if(!e.whatMissing().empty()) + { + errorMsg += VLC->generaltexth->translate("vcmi.server.errors.modsToEnable") + '\n'; + errorMsg += e.whatMissing(); + } + if(!e.whatExcessive().empty()) + { + errorMsg += VLC->generaltexth->translate("vcmi.server.errors.modsToDisable") + '\n'; + errorMsg += e.whatExcessive(); + } lobby->announceMessage(errorMsg); return false; }