Addresses crash scenario where too many cards were being loaded in a game.

- Too many iterations that fill up the server's memory trying to (1) render the deck hash and (2) building up a string of the deck contents
This commit is contained in:
ZeldaZach
2024-04-28 22:14:24 -04:00
parent 0e97cc1712
commit eb712d25dc
4 changed files with 19 additions and 7 deletions

View File

@@ -334,12 +334,14 @@ void DeckViewScene::rebuildTree()
{ {
clearContents(); clearContents();
if (!deck) if (!deck) {
return; return;
}
unsigned int cardsRenderedAlready = 0;
InnerDecklistNode *listRoot = deck->getRoot(); InnerDecklistNode *listRoot = deck->getRoot();
for (int i = 0; i < listRoot->size(); i++) { for (const auto innerDecklistNode : *listRoot) {
InnerDecklistNode *currentZone = dynamic_cast<InnerDecklistNode *>(listRoot->at(i)); auto *currentZone = dynamic_cast<InnerDecklistNode *>(innerDecklistNode);
DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0); DeckViewCardContainer *container = cardContainers.value(currentZone->getName(), 0);
if (!container) { if (!container) {
@@ -349,12 +351,15 @@ void DeckViewScene::rebuildTree()
} }
for (int j = 0; j < currentZone->size(); j++) { for (int j = 0; j < currentZone->size(); j++) {
DecklistCardNode *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j)); auto *currentCard = dynamic_cast<DecklistCardNode *>(currentZone->at(j));
if (!currentCard) if (!currentCard)
continue; continue;
for (int k = 0; k < currentCard->getNumber(); ++k) { 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); container->addCard(newCard);
emit newCardAdded(newCard); emit newCardAdded(newCard);
} }

View File

@@ -104,6 +104,7 @@ signals:
void sideboardPlanChanged(); void sideboardPlanChanged();
private: private:
static constexpr unsigned int MAX_CARDS_TO_RENDER = 300;
bool locked; bool locked;
DeckList *deck; DeckList *deck;
QMap<QString, DeckViewCardContainer *> cardContainers; QMap<QString, DeckViewCardContainer *> cardContainers;

View File

@@ -804,13 +804,18 @@ void DeckList::updateDeckHash()
hashZones << DECK_ZONE_MAIN << DECK_ZONE_SIDE; // Zones in deck to be included in hashing process 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 optionalZones << DECK_ZONE_TOKENS; // Optional zones in deck not included in hashing process
for (int i = 0; i < root->size(); i++) { unsigned int cardsHashedAlready = 0;
auto *node = dynamic_cast<InnerDecklistNode *>(root->at(i)); for (auto innerDecklistNode : *root) {
auto *node = dynamic_cast<InnerDecklistNode *>(innerDecklistNode);
for (int j = 0; j < node->size(); j++) { for (int j = 0; j < node->size(); j++) {
if (hashZones.contains(node->getName())) // Mainboard or Sideboard if (hashZones.contains(node->getName())) // Mainboard or Sideboard
{ {
auto *card = dynamic_cast<DecklistCardNode *>(node->at(j)); auto *card = dynamic_cast<DecklistCardNode *>(node->at(j));
for (int k = 0; k < card->getNumber(); ++k) { 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()); cardList.append((node->getName() == DECK_ZONE_SIDE ? "SB:" : "") + card->getName().toLower());
} }
} }

View File

@@ -173,6 +173,7 @@ class DeckList : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
static constexpr unsigned int MAX_CARDS_TO_HASH = 100000;
QString name, comments; QString name, comments;
QString deckHash; QString deckHash;
QMap<QString, SideboardPlan *> sideboardPlans; QMap<QString, SideboardPlan *> sideboardPlans;