From b0c66ae69b08ceb2469f4c6842fdc3d70f97cdc4 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 13 Dec 2024 17:24:48 +0000 Subject: [PATCH 1/4] Completely erase old cache on mod repo checkout This allows to remove any outdated data that might be present: - mods removed from repository - mods that came from no longer used repository - fields that were removed from mod.json's --- launcher/modManager/cmodlistview_moc.cpp | 17 +++++++++++------ launcher/modManager/cmodlistview_moc.h | 1 + launcher/modManager/modstatecontroller.cpp | 4 ++-- launcher/modManager/modstatecontroller.h | 2 +- launcher/modManager/modstatemodel.cpp | 6 ++---- launcher/modManager/modstatemodel.h | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/launcher/modManager/cmodlistview_moc.cpp b/launcher/modManager/cmodlistview_moc.cpp index b5c222088..79d774b22 100644 --- a/launcher/modManager/cmodlistview_moc.cpp +++ b/launcher/modManager/cmodlistview_moc.cpp @@ -43,7 +43,7 @@ void CModListView::setupModModel() modStateModel = std::make_shared(); if (!cachedRepositoryData.isNull()) - modStateModel->appendRepositories(cachedRepositoryData); + modStateModel->setRepositoryData(cachedRepositoryData); modModel = new ModStateItemModel(modStateModel, this); manager = std::make_unique(modStateModel); @@ -151,6 +151,8 @@ void CModListView::reload() void CModListView::loadRepositories() { + accumulatedRepositoryData.clear(); + QStringList repositories; if (settings["launcher"]["defaultRepositoryEnabled"].Bool()) @@ -731,7 +733,7 @@ void CModListView::installFiles(QStringList files) QStringList maps; QStringList images; QStringList exe; - JsonNode repository; + bool repositoryFilesEnqueued = false; // TODO: some better way to separate zip's with mods and downloaded repository files for(QString filename : files) @@ -754,9 +756,12 @@ void CModListView::installFiles(QStringList files) auto modNameLower = boost::algorithm::to_lower_copy(modName); auto modJsonUrl = modJson["mod"]; if(!modJsonUrl.isNull()) + { downloadFile(QString::fromStdString(modName + ".json"), QString::fromStdString(modJsonUrl.String()), tr("mods repository index")); + repositoryFilesEnqueued = true; + } - repository[modNameLower] = modJson; + accumulatedRepositoryData[modNameLower] = modJson; } } else @@ -764,16 +769,16 @@ void CModListView::installFiles(QStringList files) // This is json of a single mod. Extract name of mod and add it to repo auto modName = QFileInfo(filename).baseName().toStdString(); auto modNameLower = boost::algorithm::to_lower_copy(modName); - repository[modNameLower] = repoData; + accumulatedRepositoryData[modNameLower] = repoData; } } else if(filename.endsWith(".png", Qt::CaseInsensitive)) images.push_back(filename); } - if (!repository.isNull()) + if (!accumulatedRepositoryData.isNull() && !repositoryFilesEnqueued) { - manager->appendRepositories(repository); + manager->setRepositoryData(accumulatedRepositoryData); modModel->reloadRepositories(); static const QString repositoryCachePath = CLauncherDirs::downloadsPath() + "/repositoryCache.json"; diff --git a/launcher/modManager/cmodlistview_moc.h b/launcher/modManager/cmodlistview_moc.h index 8c2edd40a..6dbd198ce 100644 --- a/launcher/modManager/cmodlistview_moc.h +++ b/launcher/modManager/cmodlistview_moc.h @@ -36,6 +36,7 @@ class CModListView : public QWidget ModStateItemModel * modModel; CModFilterModel * filterModel; CDownloadManager * dlManager; + JsonNode accumulatedRepositoryData; QStringList enqueuedModDownloads; diff --git a/launcher/modManager/modstatecontroller.cpp b/launcher/modManager/modstatecontroller.cpp index bbfb2e75b..718f9841a 100644 --- a/launcher/modManager/modstatecontroller.cpp +++ b/launcher/modManager/modstatecontroller.cpp @@ -72,9 +72,9 @@ ModStateController::ModStateController(std::shared_ptr modList) ModStateController::~ModStateController() = default; -void ModStateController::appendRepositories(const JsonNode & repomap) +void ModStateController::setRepositoryData(const JsonNode & repomap) { - modList->appendRepositories(repomap); + modList->setRepositoryData(repomap); } bool ModStateController::addError(QString modname, QString message) diff --git a/launcher/modManager/modstatecontroller.h b/launcher/modManager/modstatecontroller.h index 57cfc53e6..9ee087feb 100644 --- a/launcher/modManager/modstatecontroller.h +++ b/launcher/modManager/modstatecontroller.h @@ -37,7 +37,7 @@ public: ModStateController(std::shared_ptr modList); ~ModStateController(); - void appendRepositories(const JsonNode & repositoriesList); + void setRepositoryData(const JsonNode & repositoriesList); QStringList getErrors(); diff --git a/launcher/modManager/modstatemodel.cpp b/launcher/modManager/modstatemodel.cpp index 9bcfa2863..aaaa037ce 100644 --- a/launcher/modManager/modstatemodel.cpp +++ b/launcher/modManager/modstatemodel.cpp @@ -11,7 +11,6 @@ #include "modstatemodel.h" #include "../../lib/filesystem/Filesystem.h" -#include "../../lib/json/JsonUtils.h" #include "../../lib/modding/ModManager.h" ModStateModel::ModStateModel() @@ -22,10 +21,9 @@ ModStateModel::ModStateModel() ModStateModel::~ModStateModel() = default; -void ModStateModel::appendRepositories(const JsonNode & repositoriesList) +void ModStateModel::setRepositoryData(const JsonNode & repositoriesList) { - JsonUtils::mergeCopy(*repositoryData, repositoriesList); - + *repositoryData = repositoriesList; modManager = std::make_unique(*repositoryData); } diff --git a/launcher/modManager/modstatemodel.h b/launcher/modManager/modstatemodel.h index 168da5dfe..e15433dc7 100644 --- a/launcher/modManager/modstatemodel.h +++ b/launcher/modManager/modstatemodel.h @@ -27,7 +27,7 @@ public: ModStateModel(); ~ModStateModel(); - void appendRepositories(const JsonNode & repositoriesList); + void setRepositoryData(const JsonNode & repositoriesList); void reloadLocalState(); const JsonNode & getRepositoryData() const; From 92b49370edae8ba01bb5b65fa2df89f2a419da88 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 13 Dec 2024 17:27:14 +0000 Subject: [PATCH 2/4] Remove not used window title from Start Game tab --- launcher/startGame/StartGameTab.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/startGame/StartGameTab.ui b/launcher/startGame/StartGameTab.ui index 6822cf4c2..dd2d06e49 100644 --- a/launcher/startGame/StartGameTab.ui +++ b/launcher/startGame/StartGameTab.ui @@ -11,7 +11,7 @@ - Form + From 64db89711effefa8dcb21620e0230e44f58792a4 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 14 Dec 2024 14:33:58 +0000 Subject: [PATCH 3/4] Retranslate start game tab on language change --- launcher/startGame/StartGameTab.cpp | 8 ++++++++ launcher/startGame/StartGameTab.h | 1 + 2 files changed, 9 insertions(+) diff --git a/launcher/startGame/StartGameTab.cpp b/launcher/startGame/StartGameTab.cpp index 8e947d124..0f1926a57 100644 --- a/launcher/startGame/StartGameTab.cpp +++ b/launcher/startGame/StartGameTab.cpp @@ -20,6 +20,14 @@ #include "../../lib/filesystem/Filesystem.h" #include "../../lib/VCMIDirs.h" +void StartGameTab::changeEvent(QEvent *event) +{ + if(event->type() == QEvent::LanguageChange) + ui->retranslateUi(this); + + QWidget::changeEvent(event); +} + StartGameTab::StartGameTab(QWidget * parent) : QWidget(parent) , ui(new Ui::StartGameTab) diff --git a/launcher/startGame/StartGameTab.h b/launcher/startGame/StartGameTab.h index 9f165278c..d66e449b5 100644 --- a/launcher/startGame/StartGameTab.h +++ b/launcher/startGame/StartGameTab.h @@ -39,6 +39,7 @@ class StartGameTab : public QWidget void refreshPresets(); void refreshGameData(); + void changeEvent(QEvent *event) override; public: explicit StartGameTab(QWidget * parent = nullptr); ~StartGameTab(); From bb7cf3ffbfff68a7ef3bf70a966fdd4a7fd71318 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 14 Dec 2024 14:39:09 +0000 Subject: [PATCH 4/4] Use existing callback method instead of custom one in AI --- AI/BattleAI/BattleEvaluator.cpp | 64 ++------------------------- AI/BattleAI/BattleEvaluator.h | 1 - AI/BattleAI/BattleExchangeVariant.cpp | 5 +-- 3 files changed, 5 insertions(+), 65 deletions(-) diff --git a/AI/BattleAI/BattleEvaluator.cpp b/AI/BattleAI/BattleEvaluator.cpp index a9f32affd..af2220b7d 100644 --- a/AI/BattleAI/BattleEvaluator.cpp +++ b/AI/BattleAI/BattleEvaluator.cpp @@ -119,50 +119,6 @@ std::vector BattleEvaluator::getBrokenWallMoatHexes() const return result; } -std::vector BattleEvaluator::getCastleHexes() -{ - std::vector result; - - // Loop through all wall parts - - std::vector wallHexes; - wallHexes.push_back(50); - wallHexes.push_back(183); - wallHexes.push_back(182); - wallHexes.push_back(130); - wallHexes.push_back(78); - wallHexes.push_back(29); - wallHexes.push_back(12); - wallHexes.push_back(97); - wallHexes.push_back(45); - wallHexes.push_back(62); - wallHexes.push_back(112); - wallHexes.push_back(147); - wallHexes.push_back(165); - - for (BattleHex wallHex : wallHexes) { - // Get the starting x-coordinate of the wall hex - int startX = wallHex.getX(); - - // Initialize current hex with the wall hex - BattleHex currentHex = wallHex; - while (currentHex.isValid()) { - // Check if the x-coordinate has wrapped (smaller than the starting x) - if (currentHex.getX() < startX) { - break; - } - - // Add the hex to the result - result.push_back(currentHex); - - // Move to the next hex to the right - currentHex = currentHex.cloneInDirection(BattleHex::RIGHT, false); - } - } - - return result; -} - bool BattleEvaluator::hasWorkingTowers() const { bool keepIntact = cb->getBattle(battleID)->battleGetWallState(EWallPart::KEEP) != EWallState::NONE && cb->getBattle(battleID)->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED; @@ -221,11 +177,6 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack) && !stack->canShoot() && hasWorkingTowers() && !enemyMellee.empty(); - std::vector castleHexes = getCastleHexes(); - for (auto hex : castleHexes) - { - logAi->trace("Castlehex ID: %d Y: %d X: %d", hex, hex.getY(), hex.getX()); - } if(targets->possibleAttacks.empty() && bestSpellcast.has_value()) { @@ -292,10 +243,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack) return BattleAction::makeDefend(stack); } - bool isTargetOutsideFort = std::none_of(castleHexes.begin(), castleHexes.end(), - [&](const BattleHex& hex) { - return hex == bestAttack.from; - }); + bool isTargetOutsideFort = !hb->battleIsInsideWalls(bestAttack.from); bool siegeDefense = stack->unitSide() == BattleSide::DEFENDER && !bestAttack.attack.shooting && hasWorkingTowers() @@ -424,14 +372,8 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector if (siegeDefense) { vstd::erase_if(avHexes, [&](const BattleHex& hex) { - std::vector castleHexes = getCastleHexes(); - - bool isOutsideWall = std::none_of(castleHexes.begin(), castleHexes.end(), - [&](const BattleHex& checkhex) { - return checkhex == hex; - }); - return isOutsideWall; - }); + return !cb->getBattle(battleID)->battleIsInsideWalls(hex); + }); } if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked diff --git a/AI/BattleAI/BattleEvaluator.h b/AI/BattleAI/BattleEvaluator.h index 7385a0809..4c4bb1e5b 100644 --- a/AI/BattleAI/BattleEvaluator.h +++ b/AI/BattleAI/BattleEvaluator.h @@ -53,7 +53,6 @@ public: std::optional findBestCreatureSpell(const CStack * stack); BattleAction goTowardsNearest(const CStack * stack, std::vector hexes, const PotentialTargets & targets); std::vector getBrokenWallMoatHexes() const; - static std::vector getCastleHexes(); bool hasWorkingTowers() const; void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only void print(const std::string & text) const; diff --git a/AI/BattleAI/BattleExchangeVariant.cpp b/AI/BattleAI/BattleExchangeVariant.cpp index 357df8f70..c4675afc0 100644 --- a/AI/BattleAI/BattleExchangeVariant.cpp +++ b/AI/BattleAI/BattleExchangeVariant.cpp @@ -218,7 +218,6 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget( bool siegeDefense) { EvaluationResult result(targets.bestAction()); - std::vector castleHexes = BattleEvaluator::getCastleHexes(); if(!activeStack->waited() && !activeStack->acquireState()->hadMorale) { @@ -234,7 +233,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget( for(auto & ap : targets.possibleAttacks) { - if (siegeDefense && std::find(castleHexes.begin(), castleHexes.end(), ap.from) == castleHexes.end()) + if (siegeDefense && !hb->battleIsInsideWalls(ap.from)) continue; float score = evaluateExchange(ap, 0, targets, damageCache, hbWaited); @@ -269,7 +268,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget( for(auto & ap : targets.possibleAttacks) { - if (siegeDefense && std::find(castleHexes.begin(), castleHexes.end(), ap.from) == castleHexes.end()) + if (siegeDefense && !hb->battleIsInsideWalls(ap.from)) continue; float score = evaluateExchange(ap, 0, targets, damageCache, hb);