diff --git a/cockatrice/src/interface/deck_sync/deck_sync_manager.cpp b/cockatrice/src/interface/deck_sync/deck_sync_manager.cpp index eb4987ba9..e32beada8 100644 --- a/cockatrice/src/interface/deck_sync/deck_sync_manager.cpp +++ b/cockatrice/src/interface/deck_sync/deck_sync_manager.cpp @@ -135,9 +135,6 @@ void DeckSyncManager::collectServerFiles(const ServerInfo_DeckStorage_Folder &fo { for (const auto &item : folder.items()) { const QString name = QString::fromStdString(item.name()); - if (name.isEmpty() || name == "." || name == ".." || name.contains('/') || name.contains('\\')) { - continue; - } if (item.has_folder()) { const QString path = prefix.isEmpty() ? name : prefix + "/" + name; dirs.insert(path); @@ -176,37 +173,8 @@ void DeckSyncManager::onListFinished(const Response &response, const CommandCont sidecar.load(); const qint64 nowSecs = QDateTime::currentDateTime().toSecsSinceEpoch(); - QMap serverPathById; - QMap serverPathByGuid; - for (auto sit = serverFiles.begin(); sit != serverFiles.end(); ++sit) { - serverPathById.insert(sit.value().id, sit.key()); - if (!sit.value().guid.isEmpty()) { - serverPathByGuid.insert(sit.value().guid, sit.key()); - } - } - QSet matchedServerPaths; - for (auto it = localFiles.begin(); it != localFiles.end(); ++it) { - const DeckSyncRecord sidecarRecord = sidecar.get(it.key()); - QString serverPath; - if (sidecarRecord.remoteId != -1 && serverPathById.contains(sidecarRecord.remoteId)) { - serverPath = serverPathById.value(sidecarRecord.remoteId); - } else if (!sidecarRecord.guid.isEmpty() && serverPathByGuid.contains(sidecarRecord.guid)) { - serverPath = serverPathByGuid.value(sidecarRecord.guid); - } else { - serverPath = serverPathFor(it.key()); - if (!serverFiles.contains(serverPath)) { - UploadOp op; - op.relativePath = it.key(); - op.serverPath = serverPath; - op.deckId = -1; - op.guid = sidecar.contains(it.key()) && !sidecar.get(it.key()).guid.isEmpty() - ? sidecar.get(it.key()).guid - : QUuid::createUuid().toString(QUuid::WithoutBraces); - pendingUploads.append(op); - continue; - } - } + const QString serverPath = serverPathFor(it.key()); auto serverIt = serverFiles.find(serverPath); if (serverIt == serverFiles.end()) { UploadOp op; @@ -219,7 +187,6 @@ void DeckSyncManager::onListFinished(const Response &response, const CommandCont pendingUploads.append(op); continue; } - matchedServerPaths.insert(serverIt.key()); if (it.value().hash == serverIt.value().hash) { DeckSyncRecord record = sidecar.get(it.key()); if (record.guid.isEmpty()) { @@ -255,9 +222,6 @@ void DeckSyncManager::onListFinished(const Response &response, const CommandCont } for (auto it = serverFiles.begin(); it != serverFiles.end(); ++it) { - if (matchedServerPaths.contains(it.key())) { - continue; - } const QString wantedPath = it.key().endsWith(".cod", Qt::CaseInsensitive) ? it.key() : it.key() + ".cod"; if (localFiles.contains(wantedPath) || QFileInfo(deckPath + "/" + wantedPath).exists()) { continue; @@ -491,13 +455,7 @@ void DeckSyncManager::onDownloadFinished(const Response &response, return; } - const QString cleanDeckPath = QDir::cleanPath(deckPath); - const QString absolutePath = QDir::cleanPath(deckPath + "/" + relativePath); - if (absolutePath != cleanDeckPath && !absolutePath.startsWith(cleanDeckPath + "/")) { - ++skippedCount; - processNext(); - return; - } + const QString absolutePath = deckPath + "/" + relativePath; if (localFiles.contains(relativePath)) { const QString backupPath = absolutePath + BACKUP_SUFFIX + QString::number(QDateTime::currentDateTime().toSecsSinceEpoch()); diff --git a/cockatrice/src/interface/deck_sync/deck_sync_sidecar.cpp b/cockatrice/src/interface/deck_sync/deck_sync_sidecar.cpp index 2e3a5ba49..861149464 100644 --- a/cockatrice/src/interface/deck_sync/deck_sync_sidecar.cpp +++ b/cockatrice/src/interface/deck_sync/deck_sync_sidecar.cpp @@ -5,7 +5,6 @@ #include #include #include -#include namespace { @@ -65,12 +64,12 @@ bool DeckSyncSidecar::save() const root.insert("records", records); QDir().mkpath(QFileInfo(filePath).absolutePath()); - QSaveFile file(filePath); - if (!file.open(QIODevice::WriteOnly)) { + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { return false; } file.write(QJsonDocument(root).toJson(QJsonDocument::Compact)); - return file.commit(); + return true; } bool DeckSyncSidecar::contains(const QString &relativePath) const diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.cpp index b918dd9ee..31a6b622b 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.cpp @@ -13,36 +13,12 @@ namespace { using ZoneCardKey = QPair; -struct ZoneCardInfo -{ - int count = 0; - QString cardSetShortName; - QString cardSetNumber; - QString cardProviderId; -}; - -QMap zoneCardInfos(const DeckList &deck) -{ - QMap infos; - deck.forEachCard([&infos](InnerDecklistNode *zone, DecklistCardNode *card) { - ZoneCardInfo &info = infos[{zone->getName(), card->getName()}]; - if (info.count == 0) { - info.cardSetShortName = card->getCardSetShortName(); - info.cardSetNumber = card->getCardCollectorNumber(); - info.cardProviderId = card->getCardProviderId(); - } - info.count += card->getNumber(); - }); - return infos; -} - QMap zoneCardCounts(const DeckList &deck) { QMap counts; - const QMap infos = zoneCardInfos(deck); - for (auto it = infos.begin(); it != infos.end(); ++it) { - counts.insert(it.key(), it.value().count); - } + deck.forEachCard([&counts](InnerDecklistNode *zone, DecklistCardNode *card) { + counts[{zone->getName(), card->getName()}] += card->getNumber(); + }); return counts; } @@ -58,25 +34,17 @@ bool changeLessThan(const DeckCardChange &a, const DeckCardChange &b) DeckDiffResult DeckDiff::diff(const DeckList &oldDeck, const DeckList &newDeck) { const QMap oldCounts = zoneCardCounts(oldDeck); - const QMap newInfos = zoneCardInfos(newDeck); + const QMap newCounts = zoneCardCounts(newDeck); QSet keys(oldCounts.keyBegin(), oldCounts.keyEnd()); - keys.unite(QSet(newInfos.keyBegin(), newInfos.keyEnd())); + keys.unite(QSet(newCounts.keyBegin(), newCounts.keyEnd())); DeckDiffResult result; for (const ZoneCardKey &key : keys) { const int oldCount = oldCounts.value(key, 0); - const ZoneCardInfo newInfo = newInfos.value(key, ZoneCardInfo()); - if (oldCount != newInfo.count) { - DeckCardChange change; - change.zone = key.first; - change.cardName = key.second; - change.oldCount = oldCount; - change.newCount = newInfo.count; - change.cardSetShortName = newInfo.cardSetShortName; - change.cardSetNumber = newInfo.cardSetNumber; - change.cardProviderId = newInfo.cardProviderId; - result.changes.append(change); + const int newCount = newCounts.value(key, 0); + if (oldCount != newCount) { + result.changes.append({key.first, key.second, oldCount, newCount}); } } std::sort(result.changes.begin(), result.changes.end(), changeLessThan); @@ -101,41 +69,21 @@ DeckList DeckDiff::merge(const DeckList &baseDeck, const DeckDiffResult &localChanges, const DeckDiffResult &remoteChanges) { QMap counts = zoneCardCounts(baseDeck); - QMap printings; for (const DeckCardChange &change : localChanges.changes) { counts[{change.zone, change.cardName}] = change.newCount; - printings[{change.zone, change.cardName}] = change; } for (const DeckCardChange &change : remoteChanges.changes) { counts[{change.zone, change.cardName}] = change.newCount; - printings[{change.zone, change.cardName}] = change; } - DeckList merged = baseDeck; - QMap> nodesByKey; - merged.forEachCard([&nodesByKey](InnerDecklistNode *zone, DecklistCardNode *card) { - nodesByKey[{zone->getName(), card->getName()}].append(card); - }); - - for (auto it = counts.begin(); it != counts.end(); ++it) { - const ZoneCardKey &key = it.key(); - const int target = qMax(0, it.value()); - QList nodes = nodesByKey.value(key); - if (target == 0) { - for (DecklistCardNode *node : nodes) { - merged.getTree()->deleteNode(node); - } - } else if (nodes.isEmpty()) { - const DeckCardChange printing = printings.value(key); - merged.getTree()->addCard(printing.cardName, target, printing.zone, -1, printing.cardSetShortName, - printing.cardSetNumber, printing.cardProviderId, true); - } else { - nodes.first()->setNumber(target); - for (int i = 1; i < nodes.size(); ++i) { - merged.getTree()->deleteNode(nodes.at(i)); - } + DeckList merged(baseDeck.getMetadata(), DecklistNodeTree(), baseDeck.getSideboardPlans()); + QList keys = counts.keys(); + std::sort(keys.begin(), keys.end()); + for (const ZoneCardKey &key : keys) { + const int count = qMax(0, counts.value(key)); + for (int i = 0; i < count; ++i) { + merged.addCard(key.second, key.first); } } - merged.refreshDeckHash(); return merged; } diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.h index 563b54b70..2b4fb8732 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_diff.h @@ -14,13 +14,10 @@ class DeckList; /** @brief A single card-count change within one zone. */ struct DeckCardChange { - QString zone; ///< Zone name, e.g. "main". - QString cardName; ///< Card name. - int oldCount = 0; ///< Copies in the old deck. - int newCount = 0; ///< Copies in the new deck. - QString cardSetShortName; ///< Printing set carried from the new side, empty when unchanged. - QString cardSetNumber; ///< Printing collector number carried from the new side. - QString cardProviderId; ///< Printing provider id carried from the new side. + QString zone; ///< Zone name, e.g. "main". + QString cardName; ///< Card name. + int oldCount = 0; ///< Copies in the old deck. + int newCount = 0; ///< Copies in the new deck. /** @brief Copies added (positive) or removed (negative). */ [[nodiscard]] int delta() const { @@ -43,9 +40,9 @@ struct DeckDiffResult * @class DeckDiff * @brief Pure card-count diff and three-way merge for deck sync. * - * Compares card names and copy counts per zone only; a merged deck keeps - * base printings for existing cards and carries the changed side's printing - * for newly added cards. + * Compares card names and copy counts per zone only; printing information + * (set, collector number, provider) is not tracked, so a merged deck keeps + * base printings with merged counts. */ class DeckDiff {