Support multiple <set> tags per card within the database

This will allow us to show off all different printings for cards that might appear multiple times in a set (alt arts, Secret Lairs, etc.)
This commit is contained in:
Zach Halpern 2024-11-25 01:23:00 -05:00 committed by ZeldaZach
parent 7ae1349ac8
commit db53066d89
No known key found for this signature in database
12 changed files with 159 additions and 152 deletions

View file

@ -32,20 +32,24 @@ PictureToLoad::PictureToLoad(CardInfoPtr _card)
: card(std::move(_card)), urlTemplates(SettingsCache::instance().downloads().getAllURLs()) : card(std::move(_card)), urlTemplates(SettingsCache::instance().downloads().getAllURLs())
{ {
if (card) { if (card) {
for (const auto &set : card->getSets()) { for (const auto &x : card->getSets()) {
sortedSets << set.getPtr(); for (const auto &set : x) {
sortedSets << set.getPtr();
}
} }
if (sortedSets.empty()) { if (sortedSets.empty()) {
sortedSets << CardSet::newInstance("", "", "", QDate()); sortedSets << CardSet::newInstance("", "", "", QDate());
} }
std::sort(sortedSets.begin(), sortedSets.end(), SetDownloadPriorityComparator()); std::sort(sortedSets.begin(), sortedSets.end(), SetDownloadPriorityComparator());
// If the pixmapCacheKey corresponds to a specific set, we have to try to load it first. // If the pixmapCacheKey corresponds to a specific set, we have to try to load it first.
for (const auto &set : card->getSets()) { for (const auto &x : card->getSets()) {
if (QLatin1String("card_") + card->getName() + QString("_") + QString(set.getProperty("uuid")) == for (const auto &set : x) {
card->getPixmapCacheKey()) { if (QLatin1String("card_") + card->getName() + QString("_") + QString(set.getProperty("uuid")) ==
long long setIndex = sortedSets.indexOf(set.getPtr()); card->getPixmapCacheKey()) {
CardSetPtr setForCardProviderID = sortedSets.takeAt(setIndex); long long setIndex = sortedSets.indexOf(set.getPtr());
sortedSets.prepend(setForCardProviderID); CardSetPtr setForCardProviderID = sortedSets.takeAt(setIndex);
sortedSets.prepend(setForCardProviderID);
}
} }
} }
// The first time called, nextSet will also populate the Urls for the first set. // The first time called, nextSet will also populate the Urls for the first set.

View file

@ -167,9 +167,11 @@ CardInfoPerSet PrintingSelector::getSetForUUID(const QString &uuid)
{ {
CardInfoPerSetMap cardInfoPerSets = selectedCard->getSets(); CardInfoPerSetMap cardInfoPerSets = selectedCard->getSets();
for (const auto &cardInfoPerSet : cardInfoPerSets) { for (const auto &x : cardInfoPerSets) {
if (cardInfoPerSet.getProperty("uuid") == uuid) { for (const auto &cardInfoPerSet : x) {
return cardInfoPerSet; if (cardInfoPerSet.getProperty("uuid") == uuid) {
return cardInfoPerSet;
}
} }
} }
@ -182,15 +184,18 @@ QList<CardInfoPerSet> PrintingSelector::prependPrintingsInDeck(const QList<CardI
QList<QPair<CardInfoPerSet, int>> countList; QList<QPair<CardInfoPerSet, int>> countList;
// Collect sets with their counts // Collect sets with their counts
for (const auto &cardInfoPerSet : cardInfoPerSets) { for (const auto &x : cardInfoPerSets) {
QModelIndex find_card = for (const auto &cardInfoPerSet : x) {
deckModel->findCard(selectedCard->getName(), DECK_ZONE_MAIN, cardInfoPerSet.getProperty("uuid")); QModelIndex find_card =
if (find_card.isValid()) { deckModel->findCard(selectedCard->getName(), DECK_ZONE_MAIN, cardInfoPerSet.getProperty("uuid"));
int count = if (find_card.isValid()) {
deckModel->data(find_card, Qt::DisplayRole).toInt(); // Ensure the count is treated as an integer int count =
if (count > 0) { deckModel->data(find_card, Qt::DisplayRole).toInt(); // Ensure the count is treated as an integer
countList.append(qMakePair(cardInfoPerSet, count)); if (count > 0) {
countList.append(qMakePair(cardInfoPerSet, count));
}
} }
break;
} }
} }
@ -226,8 +231,11 @@ QList<CardInfoPerSet> PrintingSelector::sortSets()
QList<CardSetPtr> sortedSets; QList<CardSetPtr> sortedSets;
for (const auto &set : cardInfoPerSets) { for (const auto &x : cardInfoPerSets) {
sortedSets << set.getPtr(); for (const auto &set : x) {
sortedSets << set.getPtr();
break;
}
} }
if (sortedSets.empty()) { if (sortedSets.empty()) {
@ -244,8 +252,11 @@ QList<CardInfoPerSet> PrintingSelector::sortSets()
// Reconstruct sorted list of CardInfoPerSet // Reconstruct sorted list of CardInfoPerSet
for (const auto &set : sortedSets) { for (const auto &set : sortedSets) {
for (auto it = cardInfoPerSets.begin(); it != cardInfoPerSets.end(); ++it) { for (auto it = cardInfoPerSets.begin(); it != cardInfoPerSets.end(); ++it) {
if (it.value().getPtr() == set) { for (const auto &x : it.value()) {
sortedCardInfoPerSets << it.value(); if (x.getPtr() == set) {
sortedCardInfoPerSets << it.value();
break;
}
} }
} }
} }

View file

@ -163,7 +163,7 @@ void DlgEditTokens::actAddToken()
QString setName = CardDatabase::TOKENS_SETNAME; QString setName = CardDatabase::TOKENS_SETNAME;
CardInfoPerSetMap sets; CardInfoPerSetMap sets;
sets.insert(setName, CardInfoPerSet(databaseModel->getDatabase()->getSet(setName))); sets[setName].append(CardInfoPerSet(databaseModel->getDatabase()->getSet(setName)));
CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(), CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(),
QList<CardRelation *>(), sets, false, -1, false); QList<CardRelation *>(), sets, false, -1, false);
card->setCardType("Token"); card->setCardType("Token");

View file

@ -266,8 +266,11 @@ CardInfoPtr CardInfo::newInstance(const QString &_name,
_sets, _cipt, _tableRow, _upsideDownArt)); _sets, _cipt, _tableRow, _upsideDownArt));
ptr->setSmartPointer(ptr); ptr->setSmartPointer(ptr);
for (const CardInfoPerSet &set : _sets) { for (const auto &x : _sets) {
set.getPtr()->append(ptr); for (const CardInfoPerSet &set : x) {
set.getPtr()->append(ptr);
break;
}
} }
return ptr; return ptr;
@ -288,7 +291,7 @@ QString CardInfo::getCorrectedName() const
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info) void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
{ {
_set->append(smartThis); _set->append(smartThis);
sets.insert(_set->getShortName(), _info); sets[_set->getShortName()].append(_info);
refreshCachedSetNames(); refreshCachedSetNames();
} }
@ -297,9 +300,12 @@ void CardInfo::refreshCachedSetNames()
{ {
QStringList setList; QStringList setList;
// update the cached list of set names // update the cached list of set names
for (const auto &set : sets) { for (const auto &x : sets) {
if (set.getPtr()->getEnabled()) { for (const auto &set : x) {
setList << set.getPtr()->getShortName(); if (set.getPtr()->getEnabled()) {
setList << set.getPtr()->getShortName();
}
break;
} }
} }
setsNames = setList.join(", "); setsNames = setList.join(", ");
@ -396,8 +402,10 @@ void CardDatabase::addCard(CardInfoPtr card)
// if card already exists just add the new set property // if card already exists just add the new set property
if (cards.contains(card->getName())) { if (cards.contains(card->getName())) {
CardInfoPtr sameCard = cards[card->getName()]; CardInfoPtr sameCard = cards[card->getName()];
for (const CardInfoPerSet &set : card->getSets()) { for (const auto &x : card->getSets()) {
sameCard->addToSet(set.getPtr(), set); for (const CardInfoPerSet &set : x) {
sameCard->addToSet(set.getPtr(), set);
}
} }
return; return;
} }
@ -456,12 +464,14 @@ CardInfoPtr CardDatabase::getCardByNameAndProviderId(const QString &cardName, co
return info; return info;
} }
for (const auto &set : info->getSets()) { for (const auto &x : info->getSets()) {
if (set.getProperty("uuid") == providerId) { for (const auto &set : x) {
CardInfoPtr cardFromSpecificSet = info->clone(); if (set.getProperty("uuid") == providerId) {
cardFromSpecificSet->setPixmapCacheKey(QLatin1String("card_") + QString(info->getName()) + QString("_") + CardInfoPtr cardFromSpecificSet = info->clone();
QString(set.getProperty("uuid"))); cardFromSpecificSet->setPixmapCacheKey(QLatin1String("card_") + QString(info->getName()) +
return cardFromSpecificSet; QString("_") + QString(set.getProperty("uuid")));
return cardFromSpecificSet;
}
} }
} }
return {}; return {};
@ -630,11 +640,13 @@ CardInfoPerSet CardDatabase::getPreferredSetForCard(const QString &cardName) con
CardInfoPerSet preferredCard; CardInfoPerSet preferredCard;
SetPriorityComparator comparator; SetPriorityComparator comparator;
for (auto &cardInfoForSet : setMap) { for (const auto &x : setMap) {
CardSetPtr currentSet = cardInfoForSet.getPtr(); for (auto &cardInfoForSet : x) {
if (!preferredSet || comparator(currentSet, preferredSet)) { CardSetPtr currentSet = cardInfoForSet.getPtr();
preferredSet = currentSet; if (!preferredSet || comparator(currentSet, preferredSet)) {
preferredCard = cardInfoForSet; preferredSet = currentSet;
preferredCard = cardInfoForSet;
}
} }
} }
@ -657,9 +669,11 @@ CardInfoPerSet CardDatabase::getSpecificSetForCard(const QString &cardName, cons
return CardInfoPerSet(nullptr); return CardInfoPerSet(nullptr);
} }
for (auto &cardInfoForSet : setMap) { for (const auto &x : setMap) {
if (cardInfoForSet.getProperty("uuid") == providerId) { for (auto &cardInfoForSet : x) {
return cardInfoForSet; if (cardInfoForSet.getProperty("uuid") == providerId) {
return cardInfoForSet;
}
} }
} }

View file

@ -23,7 +23,7 @@ class ICardDatabaseParser;
typedef QMap<QString, QString> QStringMap; typedef QMap<QString, QString> QStringMap;
typedef QSharedPointer<CardInfo> CardInfoPtr; typedef QSharedPointer<CardInfo> CardInfoPtr;
typedef QSharedPointer<CardSet> CardSetPtr; typedef QSharedPointer<CardSet> CardSetPtr;
typedef QMap<QString, CardInfoPerSet> CardInfoPerSetMap; typedef QMap<QString, QList<CardInfoPerSet>> CardInfoPerSetMap;
Q_DECLARE_METATYPE(CardInfoPtr) Q_DECLARE_METATYPE(CardInfoPtr)
@ -306,15 +306,36 @@ public:
{ {
if (!sets.contains(setName)) if (!sets.contains(setName))
return ""; return "";
return sets[setName].getProperty(propertyName);
}
void setSetProperty(const QString &setName, const QString &_name, const QString &_value)
{
if (!sets.contains(setName))
return;
sets[setName].setProperty(_name, _value); /*
emit cardInfoChanged(smartThis); for (const auto &x : card->getSets()) {
for (const auto &set : x) {
if (QLatin1String("card_") + card->getName() + QString("_") + QString(set.getProperty("uuid")) ==
card->getPixmapCacheKey()) {
long long setIndex = sortedSets.indexOf(set.getPtr());
CardSetPtr setForCardProviderID = sortedSets.takeAt(setIndex);
sortedSets.prepend(setForCardProviderID);
}
}
}
*/
for (const auto &set : sets[setName]) {
if (QLatin1String("card_") + this->getName() + QString("_") + QString(set.getProperty("uuid")) ==
this->getPixmapCacheKey()) {
return set.getProperty(propertyName);
}
}
return sets[setName][0].getProperty(propertyName);
}
void setSetProperty(const QString &, const QString &, const QString &)
{
// if (!sets.contains(setName))
// return;
//
// sets[setName].setProperty(_name, _value);
// emit cardInfoChanged(smartThis);
} }
// related cards // related cards

View file

@ -97,9 +97,11 @@ bool CardDatabaseModel::checkCardHasAtLeastOneEnabledSet(CardInfoPtr card)
if (!showOnlyCardsFromEnabledSets) if (!showOnlyCardsFromEnabledSets)
return true; return true;
for (const auto &set : card->getSets()) { for (const auto &x : card->getSets()) {
if (set.getPtr()->getEnabled()) for (const auto &set : x) {
return true; if (set.getPtr()->getEnabled())
return true;
}
} }
return false; return false;

View file

@ -221,7 +221,7 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
if (attrs.hasAttribute("rarity")) { if (attrs.hasAttribute("rarity")) {
setInfo.setProperty("rarity", attrs.value("rarity").toString()); setInfo.setProperty("rarity", attrs.value("rarity").toString());
} }
_sets.insert(setName, setInfo); _sets[setName].append(setInfo);
// related cards // related cards
} else if (xmlName == "related" || xmlName == "reverse-related") { } else if (xmlName == "related" || xmlName == "reverse-related") {
CardRelation::AttachType attach = CardRelation::DoesNotAttach; CardRelation::AttachType attach = CardRelation::DoesNotAttach;
@ -331,24 +331,26 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
// sets // sets
const CardInfoPerSetMap sets = info->getSets(); const CardInfoPerSetMap sets = info->getSets();
for (CardInfoPerSet set : sets) { for (const auto &x : sets) {
xml.writeStartElement("set"); for (CardInfoPerSet set : x) {
xml.writeAttribute("rarity", set.getProperty("rarity")); xml.writeStartElement("set");
xml.writeAttribute("muId", set.getProperty("muid")); xml.writeAttribute("rarity", set.getProperty("rarity"));
xml.writeAttribute("uuId", set.getProperty("uuid")); xml.writeAttribute("muId", set.getProperty("muid"));
xml.writeAttribute("uuId", set.getProperty("uuid"));
tmpString = set.getProperty("num"); tmpString = set.getProperty("num");
if (!tmpString.isEmpty()) { if (!tmpString.isEmpty()) {
xml.writeAttribute("num", tmpString); xml.writeAttribute("num", tmpString);
}
tmpString = set.getProperty("picurl");
if (!tmpString.isEmpty()) {
xml.writeAttribute("picURL", tmpString);
}
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
} }
tmpString = set.getProperty("picurl");
if (!tmpString.isEmpty()) {
xml.writeAttribute("picURL", tmpString);
}
xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement();
} }
// related cards // related cards

View file

@ -181,7 +181,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
attrName = "picurl"; attrName = "picurl";
setInfo.setProperty(attrName, attr.value().toString()); setInfo.setProperty(attrName, attr.value().toString());
} }
_sets.insert(setName, setInfo); _sets[setName].append(setInfo);
} }
// related cards // related cards
} else if (xmlName == "related" || xmlName == "reverse-related") { } else if (xmlName == "related" || xmlName == "reverse-related") {
@ -284,14 +284,16 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
xml.writeEndElement(); xml.writeEndElement();
// sets // sets
for (CardInfoPerSet set : info->getSets()) { for (const auto &x : info->getSets()) {
xml.writeStartElement("set"); for (CardInfoPerSet set : x) {
for (QString propName : set.getProperties()) { xml.writeStartElement("set");
xml.writeAttribute(propName, set.getProperty(propName)); for (QString propName : set.getProperties()) {
} xml.writeAttribute(propName, set.getProperty(propName));
}
xml.writeCharacters(set.getPtr()->getShortName()); xml.writeCharacters(set.getPtr()->getShortName());
xml.writeEndElement(); xml.writeEndElement();
}
} }
// related cards // related cards

View file

@ -109,9 +109,11 @@ static void setupParserRules()
search["RarityQuery"] = [](const peg::SemanticValues &sv) -> Filter { search["RarityQuery"] = [](const peg::SemanticValues &sv) -> Filter {
StringMatcher matcher = sv[0].get<StringMatcher>(); StringMatcher matcher = sv[0].get<StringMatcher>();
return [=](CardData x) -> bool { return [=](CardData x) -> bool {
for (const auto &set : x->getSets().values()) { for (const auto &y : x->getSets().values()) {
if (matcher(set.getProperty("rarity"))) for (const auto &set : y) {
return true; if (matcher(set.getProperty("rarity")))
return true;
}
} }
return false; return false;
}; };

View file

@ -203,11 +203,13 @@ bool FilterItem::acceptText(const CardInfoPtr info) const
bool FilterItem::acceptSet(const CardInfoPtr info) const bool FilterItem::acceptSet(const CardInfoPtr info) const
{ {
bool status = false; bool status = false;
for (const auto &set : info->getSets()) { for (const auto &x : info->getSets()) {
if (set.getPtr()->getShortName().compare(term, Qt::CaseInsensitive) == 0 || for (const auto &set : x) {
set.getPtr()->getLongName().compare(term, Qt::CaseInsensitive) == 0) { if (set.getPtr()->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
status = true; set.getPtr()->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
break; status = true;
break;
}
} }
} }
@ -336,9 +338,11 @@ bool FilterItem::acceptRarity(const CardInfoPtr info) const
} }
} }
for (const auto &set : info->getSets()) { for (const auto &x : info->getSets()) {
if (set.getProperty("rarity").compare(converted_term, Qt::CaseInsensitive) == 0) { for (const auto &set : x) {
return true; if (set.getProperty("rarity").compare(converted_term, Qt::CaseInsensitive) == 0) {
return true;
}
} }
} }
return false; return false;

View file

@ -176,7 +176,7 @@ CardInfoPtr OracleImporter::addCard(QString name,
// insert the card and its properties // insert the card and its properties
QList<CardRelation *> reverseRelatedCards; QList<CardRelation *> reverseRelatedCards;
CardInfoPerSetMap setsInfo; CardInfoPerSetMap setsInfo;
setsInfo.insert(setInfo.getPtr()->getShortName(), setInfo); setsInfo[setInfo.getPtr()->getShortName()].append(setInfo);
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards, CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards, reverseRelatedCards,
setsInfo, cipt, tableRow, upsideDown); setsInfo, cipt, tableRow, upsideDown);
@ -193,9 +193,7 @@ QString OracleImporter::getStringPropertyFromMap(const QVariantMap &card, const
return card.contains(propertyName) ? card.value(propertyName).toString() : QString(""); return card.contains(propertyName) ? card.value(propertyName).toString() : QString("");
} }
int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet, int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet, const QList<QVariant> &cardsList)
const QList<QVariant> &cardsList,
bool skipSpecialCards)
{ {
// mtgjson name => xml name // mtgjson name => xml name
static const QMap<QString, QString> cardProperties{ static const QMap<QString, QString> cardProperties{
@ -225,11 +223,6 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
for (const QVariant &cardVar : cardsList) { for (const QVariant &cardVar : cardsList) {
card = cardVar.toMap(); card = cardVar.toMap();
// skip alternatives
if (getStringPropertyFromMap(card, "isAlternative") == "true") {
continue;
}
/* Currently used layouts are: /* Currently used layouts are:
* augment, double_faced_token, flip, host, leveler, meld, normal, planar, * augment, double_faced_token, flip, host, leveler, meld, normal, planar,
* saga, scheme, split, token, transform, vanguard * saga, scheme, split, token, transform, vanguard
@ -286,42 +279,6 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
} }
QString numComponent{}; QString numComponent{};
if (skipSpecialCards) {
QString numProperty = setInfo.getProperty("num");
// skip promo cards if it's not the only print, cards with two faces are different cards
if (allNameProps.contains(faceName)) {
// check for alternative versions
if (layout != "normal")
continue;
// alternative versions have a letter in the end of num like abc
// note this will also catch p and s, those will get removed later anyway
QChar lastChar = numProperty.at(numProperty.size() - 1);
if (!lastChar.isLetter())
continue;
numComponent = " (" + QString(lastChar) + ")";
faceName += numComponent; // add to facename to make it unique
}
if (getStringPropertyFromMap(card, "isPromo") == "true") {
specialPromoCards.insert(faceName, cardVar);
continue;
}
bool skip = false;
// skip cards containing special stuff in the collectors number like promo cards
for (const QString &specialChar : specialNumChars) {
if (numProperty.contains(specialChar)) {
skip = true;
break;
}
}
if (skip) {
specialPromoCards.insert(faceName, cardVar);
continue;
} else {
allNameProps.append(faceName);
}
}
// special handling properties // special handling properties
colors = card.value("colors").toStringList().join(""); colors = card.value("colors").toStringList().join("");
@ -463,18 +420,6 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet,
numCards++; numCards++;
} }
// only add the unique promo cards that didn't already exist in the set
if (skipSpecialCards) {
QList<QVariant> nonDuplicatePromos;
for (auto cardIter = specialPromoCards.constBegin(); cardIter != specialPromoCards.constEnd(); ++cardIter) {
if (!allNameProps.contains(cardIter.key())) {
nonDuplicatePromos.append(cardIter.value());
}
}
if (!nonDuplicatePromos.isEmpty()) {
numCards += importCardsFromSet(currentSet, nonDuplicatePromos, false);
}
}
return numCards; return numCards;
} }

View file

@ -143,7 +143,7 @@ public:
bool readSetsFromByteArray(const QByteArray &data); bool readSetsFromByteArray(const QByteArray &data);
int startImport(); int startImport();
bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion); bool saveToFile(const QString &fileName, const QString &sourceUrl, const QString &sourceVersion);
int importCardsFromSet(const CardSetPtr &currentSet, const QList<QVariant> &cards, bool skipSpecialNums = true); int importCardsFromSet(const CardSetPtr &currentSet, const QList<QVariant> &cards);
QList<SetToDownload> &getSets() QList<SetToDownload> &getSets()
{ {
return allSets; return allSets;