diff --git a/cockatrice/src/deckview.cpp b/cockatrice/src/deckview.cpp index 252d655c3..4c1b83b34 100644 --- a/cockatrice/src/deckview.cpp +++ b/cockatrice/src/deckview.cpp @@ -334,12 +334,14 @@ void DeckViewScene::rebuildTree() { clearContents(); - if (!deck) + if (!deck) { return; + } + unsigned int cardsRenderedAlready = 0; InnerDecklistNode *listRoot = deck->getRoot(); - for (int i = 0; i < listRoot->size(); i++) { - InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); + for (const auto innerDecklistNode : *listRoot) { + auto *currentZone = dynamic_cast(innerDecklistNode); DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0); if (!container) { @@ -349,12 +351,15 @@ void DeckViewScene::rebuildTree() } for (int j = 0; j < currentZone->size(); j++) { - DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); + auto *currentCard = dynamic_cast(currentZone->at(j)); if (!currentCard) continue; for (int k = 0; k < currentCard->getNumber(); ++k) { - DeckViewCard *newCard = new DeckViewCard(currentCard->getName(), currentZone->getName(), container); + if (++cardsRenderedAlready >= MAX_CARDS_TO_RENDER) { + break; // We can't render anymore cards efficiently, evict early + } + auto *newCard = new DeckViewCard(currentCard->getName(), currentZone->getName(), container); container->addCard(newCard); emit newCardAdded(newCard); } diff --git a/cockatrice/src/deckview.h b/cockatrice/src/deckview.h index 8aab1dc25..1f5b7bdee 100644 --- a/cockatrice/src/deckview.h +++ b/cockatrice/src/deckview.h @@ -104,6 +104,7 @@ signals: void sideboardPlanChanged(); private: + static constexpr unsigned int MAX_CARDS_TO_RENDER = 300; bool locked; DeckList *deck; QMap cardContainers; diff --git a/common/decklist.cpp b/common/decklist.cpp index 1e118d22c..9620c8b7b 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -804,13 +804,18 @@ void DeckList::updateDeckHash() hashZones << DECK_ZONE_MAIN << DECK_ZONE_SIDE; // Zones in deck to be included in hashing process optionalZones << DECK_ZONE_TOKENS; // Optional zones in deck not included in hashing process - for (int i = 0; i < root->size(); i++) { - auto *node = dynamic_cast(root->at(i)); + unsigned int cardsHashedAlready = 0; + for (auto innerDecklistNode : *root) { + auto *node = dynamic_cast(innerDecklistNode); for (int j = 0; j < node->size(); j++) { if (hashZones.contains(node->getName())) // Mainboard or Sideboard { auto *card = dynamic_cast(node->at(j)); for (int k = 0; k < card->getNumber(); ++k) { + if (++cardsHashedAlready >= MAX_CARDS_TO_HASH) { + cardList.clear(); + break; // We can't efficiently calculate a hash with a larger number + } cardList.append((node->getName() == DECK_ZONE_SIDE ? "SB:" : "") + card->getName().toLower()); } } diff --git a/common/decklist.h b/common/decklist.h index bacba0ce6..6ded2d49a 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -173,6 +173,7 @@ class DeckList : public QObject { Q_OBJECT private: + static constexpr unsigned int MAX_CARDS_TO_HASH = 100000; QString name, comments; QString deckHash; QMap sideboardPlans;