mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-08 02:53:25 -08:00
Compare commits
1 commit
bdb9de0e6e
...
d1a7732c0f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1a7732c0f |
4 changed files with 27 additions and 125 deletions
|
|
@ -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<int, QString> serverPathById;
|
||||
QMap<QString, QString> 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<QString> 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());
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QSaveFile>
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -13,36 +13,12 @@ namespace
|
|||
{
|
||||
using ZoneCardKey = QPair<QString, QString>;
|
||||
|
||||
struct ZoneCardInfo
|
||||
{
|
||||
int count = 0;
|
||||
QString cardSetShortName;
|
||||
QString cardSetNumber;
|
||||
QString cardProviderId;
|
||||
};
|
||||
|
||||
QMap<ZoneCardKey, ZoneCardInfo> zoneCardInfos(const DeckList &deck)
|
||||
{
|
||||
QMap<ZoneCardKey, ZoneCardInfo> 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<ZoneCardKey, int> zoneCardCounts(const DeckList &deck)
|
||||
{
|
||||
QMap<ZoneCardKey, int> counts;
|
||||
const QMap<ZoneCardKey, ZoneCardInfo> 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<ZoneCardKey, int> oldCounts = zoneCardCounts(oldDeck);
|
||||
const QMap<ZoneCardKey, ZoneCardInfo> newInfos = zoneCardInfos(newDeck);
|
||||
const QMap<ZoneCardKey, int> newCounts = zoneCardCounts(newDeck);
|
||||
|
||||
QSet<ZoneCardKey> keys(oldCounts.keyBegin(), oldCounts.keyEnd());
|
||||
keys.unite(QSet<ZoneCardKey>(newInfos.keyBegin(), newInfos.keyEnd()));
|
||||
keys.unite(QSet<ZoneCardKey>(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<ZoneCardKey, int> counts = zoneCardCounts(baseDeck);
|
||||
QMap<ZoneCardKey, DeckCardChange> 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<ZoneCardKey, QList<DecklistCardNode *>> 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<DecklistCardNode *> 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<ZoneCardKey> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue