Cockatrice/libcockatrice_settings/libcockatrice/settings/card_database_settings.cpp
BruebachL 205e1ecebf
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
[CardDB] Keep parse-time set filtering and bust the cache on enablement changes (#7448)
The parsers keep dropping printings for disabled sets so that disabling a
set hides them everywhere, not just in deck editor search. The cached parse
output therefore depends on enablement, which the source hash did not cover:
the first parse froze whatever enablement state existed at that moment and
later toggles hit the stale cache.

- Fold a parser schema version and the sorted enabled set names into the
  binary cache source hash so toggling a set or enabling newly discovered
  sets (including custom ones) forces a re-parse on the next load.
- Harden the legacy set migration to only write keys that exist so missing
  legacy values can no longer clobber cardDatabase.ini and silently disable
  sets on upgrade.
- Make CardDatabase::reloadCardDatabasesAndNotify() bypass the binary cache
  so an explicit reload always re-reads the files on disk, even when their
  size/mtime hash still matches.
- Cover cache invalidation end to end: sandboxed loads assert that disabling
  a set, adding a custom database and enabling a fresh set each rewrite the
  cache, that a no-op load keeps it, and that an explicit reload picks up
  edits the source hash cannot see.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-10-09 06:09:18 +02:00

125 lines
No EOL
3.6 KiB
C++

#include "card_database_settings.h"
#include "libcockatrice/interfaces/interface_card_set_priority_controller.h"
#include "libcockatrice/settings/settings_manager.h"
#include <QList>
#include <QMutexLocker>
#include <QSettings>
#include <QStringList>
#include <QVariant>
#include <functional>
class QObject;
CardDatabaseSettings::CardDatabaseSettings(const QString &settingPath, QObject *parent)
: SettingsManager(settingPath + "cardDatabase.ini", QString(), QString(), parent)
{
}
void CardDatabaseSettings::setSortKey(QString shortName, unsigned int sortKey)
{
setValue(sortKey, "sortKey", "sets", shortName);
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
setOptionsCache[shortName].sortKey = sortKey;
}
void CardDatabaseSettings::setEnabled(QString shortName, bool enabled)
{
setValue(enabled, "enabled", "sets", shortName);
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
setOptionsCache[shortName].enabled = enabled;
}
void CardDatabaseSettings::setIsKnown(QString shortName, bool isknown)
{
setValue(isknown, "isKnown", "sets", shortName);
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
setOptionsCache[shortName].isKnown = isknown;
}
void CardDatabaseSettings::ensureSetOptionsLoaded() const
{
if (setOptionsLoaded) {
return;
}
QSettings settings(getSettings());
settings.beginGroup("sets");
const QStringList groups = settings.childGroups();
for (const QString &group : groups) {
settings.beginGroup(group);
SetOptions &o = setOptionsCache[group];
o.sortKey = settings.value("sortKey", 0).toUInt();
o.enabled = settings.value("enabled", true).toBool();
o.isKnown = settings.value("isKnown", true).toBool();
settings.endGroup();
}
setOptionsLoaded = true;
}
unsigned int CardDatabaseSettings::getSortKey(QString shortName) const
{
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
return setOptionsCache.value(shortName).sortKey;
}
bool CardDatabaseSettings::isEnabled(QString shortName) const
{
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
return setOptionsCache.value(shortName).enabled;
}
bool CardDatabaseSettings::isKnown(QString shortName) const
{
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
return setOptionsCache.value(shortName).isKnown;
}
ICardSetPriorityController::SetOptions CardDatabaseSettings::getSetOptions(QString shortName) const
{
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
return setOptionsCache.value(shortName);
}
QStringList CardDatabaseSettings::getEnabledSetNames() const
{
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
QStringList names;
for (auto it = setOptionsCache.constBegin(); it != setOptionsCache.constEnd(); ++it) {
if (it.value().enabled) {
names << it.key();
}
}
names.sort();
return names;
}
void CardDatabaseSettings::saveSets(const QVector<ICardSetPriorityController::SetSaveData> &data)
{
batchWrite([&](QSettings &s) {
s.beginGroup("sets");
for (const auto &entry : data) {
s.beginGroup(entry.shortName);
s.setValue("sortKey", entry.sortKey);
s.setValue("enabled", entry.enabled);
s.endGroup();
}
s.endGroup();
});
QMutexLocker lock(&setOptionsMutex);
ensureSetOptionsLoaded();
for (const auto &entry : data) {
SetOptions &o = setOptionsCache[entry.shortName];
o.sortKey = entry.sortKey;
o.enabled = entry.enabled;
}
}