|
Pokered Save Editor 2
Pokemon Red & Blue save file editor - Qt 6 C++/QML
|
For the in-depth, code-grounded version of everything below, see the system map: ../systems/overview.md.
| Library | Header prefix | What it does |
|---|---|---|
| common | pse-common/ | Shared types (var8, var16), Random (wraps QRandomGenerator), Utility |
| db | pse-db/ | Game data — all 151 Pokemon, maps, items, moves, etc. Loaded from JSON assets |
| savefile | pse-savefile/ | Save file parsing, expansion into C++ objects, and flattening back |
| appcore | bridge/, mvc/, engine/ | Static library with the app's testable logic: the Bridge, the ~25 MVC list models, the image/tileset engine, Router, Settings. Extracted from the executable (2026-06-07, for unit-testability). |
| app | (executable) | Thin Qt/QML shell — main, boot, MainWindow, app.qrc — linking appcore. Bridge pattern: brg exposed to QML. |
Every DB class uses a static T* inst() singleton:
Critical: DB::inst() bootstraps everything. It calls loadAll(), indexAll(), deepLinkAll() in order. No DB singleton should be accessed before DB::inst() runs.
Do not call load() from DB constructors — this caused a static-init deadlock in Qt 6. See decisions/architecture.md.
Entry structs (e.g. MapDBEntry, MoveDBEntry, ItemDBEntry) have protected data. Always use public getters:
Check if (entry->getWidth() >= 0) — not if (entry->getWidth()) — since -1 means unset.
Qt 6 requires Q_PROPERTY pointer types to be either fully defined or declared with Q_DECLARE_OPAQUE_POINTER. We centralize these:
Qt 6 MOC requires complete types for Q_PROPERTY. db.h includes every sub-DB header directly so MOC can see full class definitions.
The app uses a Bridge object as the single point of contact between QML and C++. It's exposed to QML as brg. The access chain looks like:
For QML to traverse this chain, every QObject type in it must be a complete type at the MOC TU that declares the property — i.e. fully #included, NOT forward-declared and NOT Q_DECLARE_OPAQUE_POINTER'd (the opaque macro forces Qt to treat the pointer as a non-QObject, returning undefined in QML). qRegisterMetaType / qmlRegisterUncreatableType do not change this. Include only the branches QML actually traverses, to keep build times sane. See decisions/architecture.md → "QML Property-Chain Traversal" and reference/qt-patterns.md.
UI strings (QML qsTr() / C++ tr()) are translated via a Qt Linguist pipeline: per-locale catalogs in projects/app/translations/pse_<locale>.ts → .qm embedded at :/i18n by qt_add_translations, with a QTranslator installed in boot.cpp. Source language is en_US (English ships); untranslated strings fall back to the source. Covers UI chrome only — game-data names are out of scope. Full guide, gotchas, and "how to add a language": reference/i18n.md.