Architecture¶
nnnotes reads the game's files in layers: settings and sources at the bottom, file formats and Unity objects above
them, the game's content above those, then the pipeline, the products and the command line. Each layer is one
subpackage of nnnotes and imports only the layers below it.
Layers¶
| Layer | Subpackage | What it holds |
|---|---|---|
| Command line | nnnotes.cli |
one module per command group; parses options, reads the configuration, prints summaries and --json reports |
| Products | nnnotes.site, nnnotes.musicdata |
the ournotes-player site (charts, models, stories, indexes); the music data file and its deck statistics |
| Pipeline | nnnotes.pipeline |
stages, task descriptions and results, the content-addressed store, plans, layouts, the catalog versions, the views of the master data |
| Content | nnnotes.content |
the game's subjects as exports: ADV episodes and stories, lives and scores, spots, rooms, the UI library |
| Unity objects | nnnotes.unity |
bundle reading, the typetree exporter, the player data, Live2D prefabs, text styles and TextMesh Pro fonts |
| File formats | nnnotes.formats |
formats read from bytes: CRI ACB/AWB and HCA, USM movies, CRI Lips data, shaders, motions |
| Sources | nnnotes.source |
the configuration, the APK, Addressables catalogs and bundles, the game API, master data, languages, Session |
| Core | nnnotes.core |
the one JSON writer and the process caches |
The order is a contract: the layers contract of import-linter in
pyproject.toml fails the build when a module imports a layer above its own, and nnnotes.site and
nnnotes.musicdata do not import each other. No library module imports nnnotes.cli: the commands parse options
and print, and the work they run is in the library modules below them.
Sources and the Session¶
Every setting comes from the configuration (sources and precedence).
nnnotes.source.session.Session turns one configuration into the data sources a command needs: the catalog of a
region, its decoded master data and the master data version it serves, the APK, the bundle and master data keys and
the store root. It reads a setting when it is first needed and raises a ConfigError naming the setting when it is missing or wrong;
the command line turns that error into exit status 2.
The catalog (nnnotes.source.catalog.Catalog) resolves an addressable key to its bundle and the bundle's
dependency closure, takes a bundle from the APK when the APK has it and from the CDN otherwise, and keeps fetched and
decrypted bundles in the cache directory.
Two ways to export¶
- One subject.
export episode,export story,export live,export live2d,export spot,export room,export shader,export audio,export ui,site buildandmusic-dataread what one subject needs through the Session and write their output directory directly (Export stories and lives). - Every asset.
export assetssplits the work into stages (stages). A task is one stage applied to one subject (a bundle, a content id, a view); its key covers exactly what its output depends on: the stage and converter versions, the input contents and the options (contracts). Results and their files are stored once by content hash in the store, and the output directory is laid out from the store. A second run finds every unchanged result in the store and only lays out what changed;store plansays what would run and why (asset export).
Both ways use the same readers below the pipeline layer, so a texture, shader, mesh or audio stream is converted by one implementation whichever command asks for it.
Outputs¶
Every JSON file is written by one writer (nnnotes.core.jsonio), which fixes the encoding, the line endings and the
number format; determinism explains what makes the outputs reproducible. Command reports and the
documents of the asset export have JSON Schemas shipped in nnnotes.schemas (JSON schemas).