Localization wiring now runs end to end: the oracle importer collects
foreignData for the configured language and the client renders it.
- [Oracle] Import localized names and rules texts for the selected cardLang
- single-face cards store their foreignData name and full text
- multi-face (split/adventure/aftermath/prepare) cards collect the joined
name once and join each face's translated text with the same separator
as the English merge; an incomplete translation falls back to English;
the joined text follows the same highest-priority-set policy as the
single-face path and is only collected when localization is enabled
- the wizard switching languages re-imports the card database
- [Client] Display localized card info throughout the client
- card info text/picture widgets and the game board re-render on language
change
- pictures resolve cardLang art through Scryfall's named endpoint using the
localized name, falling back to id-based art when no match exists
- deck editor keeps canonical English names as card identity (EditRole)
while showing localized names (DisplayRole), so decks and wire names
stay stable
- [Card] Add CardLocalization-backed name/text lookup and cards.xml v4
localization elements with a bounded-size translation cache
- [Tests] Cover oracle foreignData import (incl. multi-face joins, priority
and fallback paths), XML v4 localization parsing, deck model localized
display and the language-aware settings default
Existing installations need to re-run Oracle to see translations: localized
data only lands in cards.xml when the Oracle app is started with the
preferred language selected — launch the separate "Oracle" program that
ships with Cockatrice, pick the language in the wizard and let it re-import
the card database.
The client's database cache (cards.xml.cache) is invalidated by the cache
format bump and the source-hash checks, but a cache written before the
re-import can still hold English-only entries (the hash uses file size and
mtime, so a same-size/same-timestamp rewrite may be served as-is); delete
cards.xml.cache and relaunch if no localized names/texts show up after
re-importing.
* [Oracle/Client] Report card database download progress
Card database updates ran invisibly: MTGJSON parsing spun an indeterminate
bar on the UI thread and the set import blocked the window, while the
onboarding wizard spawned `oracle -b` with no progress to show at all.
- Add byte-level scan progress to `RawJson::scanSetRanges` via an optional
callback, throttled to ~100 reports per scan.
- Emit `OracleImporter::dataReadProgress` during the scan and import sets on a
worker thread, driving the wizard's progress bar per set.
- With `-b`, write machine-readable `PROGRESS <stage> <done> <total>` lines to
stdout for the download/scan/import stages; stderr keeps the log output.
- Parse the oracle stdout in `MainWindow` and forward it to the onboarding
wizard, giving the card database step a determinate bar with stage-specific
status text.
- Guard the async workers against the wizard being closed mid-run.
- Add Google Test coverage for scan progress reporting.
* [Oracle/Client] Harden oracle progress workers and quit prompt
Address review feedback on the download-progress change: decompress and read
sets files off the UI thread, cancel the load/import workers before the
wizard can tear down the importer, and show an 'Extracting file...' status
plus a clean 100% tail so the poll never looks stuck. Quitting Cockatrice
while a card database update runs now asks for confirmation.
* Show 100% for 500ms on complete.
* Disable buttons on set import until done.
* Clean up progress bar.
* Drop wrapper around lambda
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Oracle] Parse sets lazily to slash importer peak memory
- Add a raw JSON scanner that splits the document into per-set byte ranges
without materializing the JSON tree
- Keep only the raw document bytes and parse one set at a time in startImport
- Take readSetsFromByteArray by value so the wizard's buffer is moved, not copied
- Clear the retained raw data in releaseSetData()/clear()
- Cover the scanner and lazy parsing with tests
Took 2 minutes
* [Oracle] Fix nesting-depth cap, tolerate unescaped control chars, lazy-parse review fixes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Oracle] Add RAM usage benchmarks for the oracle importer
- Measure process peak/current RSS via procfs (Linux) or getrusage (macOS)
- Add a synthetic-scale RAM benchmark and an opt-in real AllPrintings
run gated by COCKATRICE_ORACLE_RAM_BENCHMARK=1
- Mirror the wizard's magic-byte handling to decompress .xz/.zip payloads
- Wire optional ZLIB/LibLZMA into the benchmark target and raise its timeout
Took 2 minutes
* [Oracle/Tests] Measure parse against post-fixture baseline; assert release empties sets
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Oracle] Add oracle importer tests and fix set parsing details
- Add oracle_importer_test and oracle_importer_benchmark_test targets
- Preserve the first printing's legalities when an existing card is reused
- Concatenate split-card coloridentity and sort/dedupe card colors
- Use a raw string for the Basic Land format regex
- Pre-allocate the card hash and micro-optimize string handling
Took 2 minutes
* [Oracle/Tests] Pin cmc coercion in CI run; scope the reserve pass
The #7214 coercion assertion lived only in oracle_importer_benchmark_test,
which gets no add_test and so never runs under ctest. Add NumericManaValueCoercedToCmc
and LegacyConvertedManaCostCoercedToCmc to oracle_importer_test (a CI-ran
binary): manaValue/convertedManaCost are JSON numbers in AllPrintings, and
QJsonValue::toString() would drop them to an empty cmc without the
#7214 coercion fix.
Wrap the distinct-name reserve pass in a bare block so the ~35k name
QStrings are handed back before the memory-heavy import loop starts.
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* fix(cmake): guard filter_string_test behind WITH_ORACLE or WITH_CLIENT. filter_string_test links against libcockatrice_filters, which is only built when WITH_ORACLE or WITH_CLIENT is enabled. Without this guard, test-only builds fail at configure time because the target doesn't exist. The guard condition mirrors the one in the root CMakeLists.txt that controls whether libcockatrice_filters is built.
* fix(cmake): centralize TEST_QT_MODULES in FindQtRuntime.cmake Each test CMakeLists.txt was independently defining TEST_QT_MODULES with its own subset of Qt modules. This duplicated knowledge that already lives in FindQtRuntime.cmake (which handles module discovery for all other targets: SERVATRICE, COCKATRICE, ORACLE). Consolidate into a single definition using the union of all test requirements (Concurrent Network Svg Widgets), matching the existing pattern for application-target modules. This ensures test-only builds (-DTEST=ON without application targets) discover all necessary Qt components.
* fix(cmake): guard libcockatrice_network behind application targets. libcockatrice_network is only needed by the client, server, and oracle targets. Other application-specific libraries (settings, models, filters) already have similar guards. This was an oversight that caused test-only builds to fail when network dependencies weren't available.