nnnotes 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nnnotes-0.1.2 → nnnotes-0.1.3}/PKG-INFO +26 -21
- nnnotes-0.1.2/src/nnnotes.egg-info/PKG-INFO → nnnotes-0.1.3/README.en.md +6 -32
- {nnnotes-0.1.2 → nnnotes-0.1.3}/pyproject.toml +10 -10
- nnnotes-0.1.3/rust/Cargo.lock +215 -0
- nnnotes-0.1.3/rust/Cargo.toml +23 -0
- nnnotes-0.1.3/rust/build.rs +33 -0
- nnnotes-0.1.3/rust/rustfmt.toml +2 -0
- nnnotes-0.1.3/rust/src/lib.rs +116 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/__init__.py +1 -1
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/addressables.py +56 -10
- nnnotes-0.1.3/src/nnnotes/apkset.py +103 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/catalog.py +70 -20
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/catalogdb.py +17 -10
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/cli.py +111 -23
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/cli_assets.py +67 -36
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/config.py +42 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/configfile.py +12 -3
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/cri.py +2 -1
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/crikey.py +4 -3
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/crilips.py +2 -1
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/cristages.py +8 -3
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/deckdata.py +74 -74
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/gameapi.py +19 -7
- nnnotes-0.1.3/src/nnnotes/jp.py +294 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/liveaudio.py +2 -2
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/master.py +31 -5
- nnnotes-0.1.3/src/nnnotes/musicdata.py +1144 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/nnnotes.example.toml +15 -2
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/player.py +7 -2
- nnnotes-0.1.3/src/nnnotes/replaydata.py +101 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/storysite.py +2 -0
- nnnotes-0.1.3/src/nnnotes/ui.py +310 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/web.py +23 -3
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/webmodel.py +1 -1
- nnnotes-0.1.2/README.en.md +0 -191
- nnnotes-0.1.2/README.md +0 -144
- nnnotes-0.1.2/setup.cfg +0 -4
- nnnotes-0.1.2/src/nnnotes.egg-info/SOURCES.txt +0 -143
- nnnotes-0.1.2/src/nnnotes.egg-info/dependency_links.txt +0 -1
- nnnotes-0.1.2/src/nnnotes.egg-info/entry_points.txt +0 -2
- nnnotes-0.1.2/src/nnnotes.egg-info/requires.txt +0 -16
- nnnotes-0.1.2/src/nnnotes.egg-info/top_level.txt +0 -1
- nnnotes-0.1.2/tests/test_advvideo.py +0 -522
- nnnotes-0.1.2/tests/test_atom_eval.py +0 -231
- nnnotes-0.1.2/tests/test_atoms_mesh.py +0 -357
- nnnotes-0.1.2/tests/test_atoms_sprite.py +0 -235
- nnnotes-0.1.2/tests/test_atoms_texture.py +0 -272
- nnnotes-0.1.2/tests/test_blob_memo.py +0 -101
- nnnotes-0.1.2/tests/test_cache.py +0 -107
- nnnotes-0.1.2/tests/test_catalog.py +0 -206
- nnnotes-0.1.2/tests/test_catalog_lazy.py +0 -194
- nnnotes-0.1.2/tests/test_catalogdb.py +0 -320
- nnnotes-0.1.2/tests/test_census.py +0 -211
- nnnotes-0.1.2/tests/test_cli.py +0 -373
- nnnotes-0.1.2/tests/test_cli_assets.py +0 -1007
- nnnotes-0.1.2/tests/test_compress.py +0 -67
- nnnotes-0.1.2/tests/test_config.py +0 -193
- nnnotes-0.1.2/tests/test_configfile.py +0 -203
- nnnotes-0.1.2/tests/test_contract.py +0 -240
- nnnotes-0.1.2/tests/test_crilips.py +0 -199
- nnnotes-0.1.2/tests/test_cristages.py +0 -554
- nnnotes-0.1.2/tests/test_deckdata.py +0 -461
- nnnotes-0.1.2/tests/test_gameapi.py +0 -393
- nnnotes-0.1.2/tests/test_goldens.py +0 -125
- nnnotes-0.1.2/tests/test_jsonio.py +0 -45
- nnnotes-0.1.2/tests/test_layout.py +0 -363
- nnnotes-0.1.2/tests/test_link.py +0 -279
- nnnotes-0.1.2/tests/test_live_options.py +0 -298
- nnnotes-0.1.2/tests/test_live_options_web.py +0 -166
- nnnotes-0.1.2/tests/test_master.py +0 -132
- nnnotes-0.1.2/tests/test_mesh_texture_guards.py +0 -94
- nnnotes-0.1.2/tests/test_modelstages.py +0 -422
- nnnotes-0.1.2/tests/test_objexport.py +0 -1016
- nnnotes-0.1.2/tests/test_orchestrate.py +0 -305
- nnnotes-0.1.2/tests/test_pipeline.py +0 -163
- nnnotes-0.1.2/tests/test_plan.py +0 -149
- nnnotes-0.1.2/tests/test_player.py +0 -140
- nnnotes-0.1.2/tests/test_readsets.py +0 -442
- nnnotes-0.1.2/tests/test_regions.py +0 -246
- nnnotes-0.1.2/tests/test_repo.py +0 -50
- nnnotes-0.1.2/tests/test_room.py +0 -392
- nnnotes-0.1.2/tests/test_sniff.py +0 -137
- nnnotes-0.1.2/tests/test_speed_exact.py +0 -534
- nnnotes-0.1.2/tests/test_spot.py +0 -159
- nnnotes-0.1.2/tests/test_stages.py +0 -274
- nnnotes-0.1.2/tests/test_store.py +0 -181
- nnnotes-0.1.2/tests/test_story_closure.py +0 -137
- nnnotes-0.1.2/tests/test_story_fonts.py +0 -842
- nnnotes-0.1.2/tests/test_story_host.py +0 -512
- nnnotes-0.1.2/tests/test_story_kinds.py +0 -100
- nnnotes-0.1.2/tests/test_story_site.py +0 -663
- nnnotes-0.1.2/tests/test_story_ui.py +0 -551
- nnnotes-0.1.2/tests/test_textstyle.py +0 -253
- nnnotes-0.1.2/tests/test_typetrees.py +0 -382
- nnnotes-0.1.2/tests/test_views.py +0 -749
- nnnotes-0.1.2/tests/test_voices.py +0 -756
- nnnotes-0.1.2/tests/test_voices_story.py +0 -541
- nnnotes-0.1.2/tests/test_web.py +0 -277
- nnnotes-0.1.2/tests/test_webmodel.py +0 -716
- {nnnotes-0.1.2 → nnnotes-0.1.3}/LICENSE +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/__main__.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/acb.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/adv.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/advcommand.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/advmedia.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/advscene.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/advui.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/advvideo.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/__init__.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/astc.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/gltf.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/mesh.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/png.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/reader.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/sniff.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/sprite.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/atoms/texture.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/cache.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/census.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/compress.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/contract.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/export.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/jsonio.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/languages.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/layout.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/link.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/live.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/live2d.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/livenotes.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/liveoptions.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/livescene.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/liveui.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/modelstages.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/motion.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/objexport.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/orchestrate.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/plan.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/room.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/score.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/shader.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/spot.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/stages.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/store.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/story.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/storyfonts.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/storyhost.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/storyvoices.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/textstyle.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/tmpfont.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/typetrees/6000.3.12f1.json +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/unity.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/viewrules.json +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/views.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/voices.py +0 -0
- {nnnotes-0.1.2 → nnnotes-0.1.3}/src/nnnotes/webaudio.py +0 -0
|
@@ -1,36 +1,39 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nnnotes
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary: Offline data toolkit for BanG Dream! Our Notes game files: catalogs, bundles, master data, stories, Live2D, audio and live charts
|
|
5
|
-
Author: MetaMiku, emptysekai
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/MetaSekaiLab/nnnotes
|
|
8
|
-
Project-URL: Source, https://github.com/MetaSekaiLab/nnnotes
|
|
9
|
-
Project-URL: Issues, https://github.com/MetaSekaiLab/nnnotes/issues
|
|
3
|
+
Version: 0.1.3
|
|
10
4
|
Classifier: Programming Language :: Python :: 3
|
|
11
5
|
Classifier: Operating System :: OS Independent
|
|
12
6
|
Classifier: Topic :: Multimedia
|
|
13
|
-
Requires-
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: UnityPy>=1.25
|
|
7
|
+
Requires-Dist: unitypy>=1.25
|
|
17
8
|
Requires-Dist: numpy>=2.0
|
|
18
|
-
Requires-Dist:
|
|
9
|
+
Requires-Dist: pillow>=10.0
|
|
19
10
|
Requires-Dist: pycryptodome>=3.20
|
|
20
11
|
Requires-Dist: grpcio>=1.49.1
|
|
21
12
|
Requires-Dist: brotli>=1.1
|
|
22
|
-
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
13
|
+
Requires-Dist: fonttools>=4.50 ; extra == 'fonts'
|
|
14
|
+
Requires-Dist: freetype-py>=2.5 ; extra == 'fonts'
|
|
15
|
+
Requires-Dist: scipy>=1.13 ; extra == 'fonts'
|
|
16
|
+
Requires-Dist: pytest>=8 ; extra == 'test'
|
|
17
|
+
Requires-Dist: pyflakes>=3.2 ; extra == 'test'
|
|
18
|
+
Requires-Dist: jsonschema>=4.18 ; extra == 'test'
|
|
26
19
|
Provides-Extra: fonts
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
Provides-Extra: test
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Summary: Offline data toolkit for BanG Dream! Our Notes game files: catalogs, bundles, master data, stories, Live2D, audio and live charts
|
|
23
|
+
Author: MetaMiku, emptysekai
|
|
24
|
+
License-Expression: MIT
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
27
|
+
Project-URL: Homepage, https://github.com/MetaSekaiLab/nnnotes
|
|
28
|
+
Project-URL: Issues, https://github.com/MetaSekaiLab/nnnotes/issues
|
|
29
|
+
Project-URL: Source, https://github.com/MetaSekaiLab/nnnotes
|
|
31
30
|
|
|
32
31
|
# nnnotes?!
|
|
33
32
|
|
|
33
|
+
Japanese-release support includes anonymous version discovery, authenticated CDN downloads, gzip catalogs,
|
|
34
|
+
snapshot-isolated caches and split APKs. See the [JP guide](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/jp.md)
|
|
35
|
+
for configuration and validation limits.
|
|
36
|
+
|
|
34
37
|
[简体中文](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.md) | [English](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.en.md)
|
|
35
38
|
|
|
36
39
|
nnnotes is an offline data toolkit for the game files of BanG Dream! Our Notes: it reads Addressables catalogs,
|
|
@@ -78,9 +81,10 @@ nnnotes config check # each setting's origin and whether it is valid
|
|
|
78
81
|
| `audio` | CRI cue sheet | one audio file per cue (FLAC / Ogg / WAV) + cue metadata |
|
|
79
82
|
| `crikey` | APK | the CRI HCA keycode from the game's boot data (shows whether it was found; can write a `.hcakey`) |
|
|
80
83
|
| `player` | APK | render-related global settings (color space, quality levels, renderers) as JSON |
|
|
84
|
+
| `ui` (experimental) | APK set and its embedded catalog | an offline serialized prefab library with dependency roots, AnimatorControllers, stable references and PNG/font resources for the optional ournotes-player UI preview ([format and limits](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/ui.md)) |
|
|
81
85
|
| `live` | music ID + difficulty | a full chart directory: chart and runtime notes, 3D scene, note and effect assets, BGM and sounds, sound routing |
|
|
82
86
|
| `web` | `--pair music:difficulty` (repeatable) or `--all`; `--live2d model` (repeatable) or `--all-live2d`; `--story episode` (repeatable) or `--all-stories`; `--region region` (repeatable) or `--all-regions` | an ournotes-player static site: shared player + per-chart / per-model / per-episode manifests + content-addressed assets; the Live2D models of the stories are built first as models, listed in `models.json`, and the story manifests reference them; one site can serve several regions, with listing texts in five languages; a story's interface texts are grouped by language, with TextMeshPro font assets generated from open fonts (the game's fonts with `--fonts game`); compressible assets (JSON, shaders, moc3, ...) are stored gzip encoded by default (`--compress br` / `none`) |
|
|
83
|
-
| `
|
|
87
|
+
| `music-data` | master data files (`--master-files` directory or `--apk-master`), or decoded master data with its manifest (`--decoded-master`) | one JSON file with every song and chart: titles and credits in five languages, bands, vocal characters, category, tags, release time, score ranks, BGM length; the Gekisou catalog (member cards, snaps and their Gekisou skills and support skills); per difficulty the level, note counts, BPM, chart times, skill events and fever ranges; and the chart statistics the deck model ournotes-deck (built into nnnotes) measures on its whole-live simulation (the no-skill score, the weight of every score-up skill kind at every position), plus single-shape Gekisou aptitude (increments and standard errors, not an optimal deck; omit with `--no-gekisou-aptitude`). `--full` adds the deck model's input: every chart's runtime notes and the master data tables about cards, skills, bonuses, scores and events ([format](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/music-data.md)) |
|
|
84
88
|
|
|
85
89
|
Export conventions:
|
|
86
90
|
|
|
@@ -220,3 +224,4 @@ See [docs/performance.md](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs
|
|
|
220
224
|
## License
|
|
221
225
|
|
|
222
226
|
MIT, see [LICENSE](https://github.com/MetaSekaiLab/nnnotes/blob/main/LICENSE).
|
|
227
|
+
|
|
@@ -1,36 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: nnnotes
|
|
3
|
-
Version: 0.1.2
|
|
4
|
-
Summary: Offline data toolkit for BanG Dream! Our Notes game files: catalogs, bundles, master data, stories, Live2D, audio and live charts
|
|
5
|
-
Author: MetaMiku, emptysekai
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/MetaSekaiLab/nnnotes
|
|
8
|
-
Project-URL: Source, https://github.com/MetaSekaiLab/nnnotes
|
|
9
|
-
Project-URL: Issues, https://github.com/MetaSekaiLab/nnnotes/issues
|
|
10
|
-
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Classifier: Topic :: Multimedia
|
|
13
|
-
Requires-Python: >=3.11
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
|
-
License-File: LICENSE
|
|
16
|
-
Requires-Dist: UnityPy>=1.25
|
|
17
|
-
Requires-Dist: numpy>=2.0
|
|
18
|
-
Requires-Dist: Pillow>=10.0
|
|
19
|
-
Requires-Dist: pycryptodome>=3.20
|
|
20
|
-
Requires-Dist: grpcio>=1.49.1
|
|
21
|
-
Requires-Dist: brotli>=1.1
|
|
22
|
-
Provides-Extra: test
|
|
23
|
-
Requires-Dist: pytest>=8; extra == "test"
|
|
24
|
-
Requires-Dist: pyflakes>=3.2; extra == "test"
|
|
25
|
-
Requires-Dist: jsonschema>=4.18; extra == "test"
|
|
26
|
-
Provides-Extra: fonts
|
|
27
|
-
Requires-Dist: fonttools>=4.50; extra == "fonts"
|
|
28
|
-
Requires-Dist: freetype-py>=2.5; extra == "fonts"
|
|
29
|
-
Requires-Dist: scipy>=1.13; extra == "fonts"
|
|
30
|
-
Dynamic: license-file
|
|
31
|
-
|
|
32
1
|
# nnnotes?!
|
|
33
2
|
|
|
3
|
+
Japanese-release support includes anonymous version discovery, authenticated CDN downloads, gzip catalogs,
|
|
4
|
+
snapshot-isolated caches and split APKs. See the [JP guide](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/jp.md)
|
|
5
|
+
for configuration and validation limits.
|
|
6
|
+
|
|
34
7
|
[简体中文](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.md) | [English](https://github.com/MetaSekaiLab/nnnotes/blob/main/README.en.md)
|
|
35
8
|
|
|
36
9
|
nnnotes is an offline data toolkit for the game files of BanG Dream! Our Notes: it reads Addressables catalogs,
|
|
@@ -78,9 +51,10 @@ nnnotes config check # each setting's origin and whether it is valid
|
|
|
78
51
|
| `audio` | CRI cue sheet | one audio file per cue (FLAC / Ogg / WAV) + cue metadata |
|
|
79
52
|
| `crikey` | APK | the CRI HCA keycode from the game's boot data (shows whether it was found; can write a `.hcakey`) |
|
|
80
53
|
| `player` | APK | render-related global settings (color space, quality levels, renderers) as JSON |
|
|
54
|
+
| `ui` (experimental) | APK set and its embedded catalog | an offline serialized prefab library with dependency roots, AnimatorControllers, stable references and PNG/font resources for the optional ournotes-player UI preview ([format and limits](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/ui.md)) |
|
|
81
55
|
| `live` | music ID + difficulty | a full chart directory: chart and runtime notes, 3D scene, note and effect assets, BGM and sounds, sound routing |
|
|
82
56
|
| `web` | `--pair music:difficulty` (repeatable) or `--all`; `--live2d model` (repeatable) or `--all-live2d`; `--story episode` (repeatable) or `--all-stories`; `--region region` (repeatable) or `--all-regions` | an ournotes-player static site: shared player + per-chart / per-model / per-episode manifests + content-addressed assets; the Live2D models of the stories are built first as models, listed in `models.json`, and the story manifests reference them; one site can serve several regions, with listing texts in five languages; a story's interface texts are grouped by language, with TextMeshPro font assets generated from open fonts (the game's fonts with `--fonts game`); compressible assets (JSON, shaders, moc3, ...) are stored gzip encoded by default (`--compress br` / `none`) |
|
|
83
|
-
| `
|
|
57
|
+
| `music-data` | master data files (`--master-files` directory or `--apk-master`), or decoded master data with its manifest (`--decoded-master`) | one JSON file with every song and chart: titles and credits in five languages, bands, vocal characters, category, tags, release time, score ranks, BGM length; the Gekisou catalog (member cards, snaps and their Gekisou skills and support skills); per difficulty the level, note counts, BPM, chart times, skill events and fever ranges; and the chart statistics the deck model ournotes-deck (built into nnnotes) measures on its whole-live simulation (the no-skill score, the weight of every score-up skill kind at every position), plus single-shape Gekisou aptitude (increments and standard errors, not an optimal deck; omit with `--no-gekisou-aptitude`). `--full` adds the deck model's input: every chart's runtime notes and the master data tables about cards, skills, bonuses, scores and events ([format](https://github.com/MetaSekaiLab/nnnotes/blob/main/docs/music-data.md)) |
|
|
84
58
|
|
|
85
59
|
Export conventions:
|
|
86
60
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
3
|
-
build-backend = "
|
|
2
|
+
requires = ["maturin>=1.9,<2"]
|
|
3
|
+
build-backend = "maturin"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nnnotes"
|
|
@@ -37,14 +37,14 @@ Homepage = "https://github.com/MetaSekaiLab/nnnotes"
|
|
|
37
37
|
Source = "https://github.com/MetaSekaiLab/nnnotes"
|
|
38
38
|
Issues = "https://github.com/MetaSekaiLab/nnnotes/issues"
|
|
39
39
|
|
|
40
|
-
[tool.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
[tool.maturin]
|
|
41
|
+
# the pure Python package src/nnnotes with the extension module nnnotes._deck (rust/: ournotes-deck, pinned by
|
|
42
|
+
# commit); the version is rust/Cargo.toml's, kept equal to nnnotes.__version__ (tests/test_musicdata.py)
|
|
43
|
+
python-source = "src"
|
|
44
|
+
module-name = "nnnotes._deck"
|
|
45
|
+
manifest-path = "rust/Cargo.toml"
|
|
46
|
+
profile = "release"
|
|
47
|
+
locked = true
|
|
48
48
|
|
|
49
49
|
[tool.pytest.ini_options]
|
|
50
50
|
testpaths = ["tests"]
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "heck"
|
|
7
|
+
version = "0.5.0"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
10
|
+
|
|
11
|
+
[[package]]
|
|
12
|
+
name = "itoa"
|
|
13
|
+
version = "1.0.18"
|
|
14
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
16
|
+
|
|
17
|
+
[[package]]
|
|
18
|
+
name = "libc"
|
|
19
|
+
version = "0.2.189"
|
|
20
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
+
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
|
22
|
+
|
|
23
|
+
[[package]]
|
|
24
|
+
name = "memchr"
|
|
25
|
+
version = "2.8.3"
|
|
26
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
28
|
+
|
|
29
|
+
[[package]]
|
|
30
|
+
name = "nnnotes-deck"
|
|
31
|
+
version = "0.1.3"
|
|
32
|
+
dependencies = [
|
|
33
|
+
"ournotes-deck",
|
|
34
|
+
"pyo3",
|
|
35
|
+
"serde_json",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[[package]]
|
|
39
|
+
name = "once_cell"
|
|
40
|
+
version = "1.21.4"
|
|
41
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
42
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
43
|
+
|
|
44
|
+
[[package]]
|
|
45
|
+
name = "ournotes-deck"
|
|
46
|
+
version = "0.0.1"
|
|
47
|
+
source = "git+https://github.com/empty-sekai/ournotes-deck?rev=dbd9cf01a4854808dceb6aedcd4041af372faeee#dbd9cf01a4854808dceb6aedcd4041af372faeee"
|
|
48
|
+
dependencies = [
|
|
49
|
+
"serde",
|
|
50
|
+
"serde_json",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[[package]]
|
|
54
|
+
name = "portable-atomic"
|
|
55
|
+
version = "1.15.0"
|
|
56
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
57
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
58
|
+
|
|
59
|
+
[[package]]
|
|
60
|
+
name = "proc-macro2"
|
|
61
|
+
version = "1.0.107"
|
|
62
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
63
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
64
|
+
dependencies = [
|
|
65
|
+
"unicode-ident",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[[package]]
|
|
69
|
+
name = "pyo3"
|
|
70
|
+
version = "0.29.2"
|
|
71
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
72
|
+
checksum = "4688ddedf473e32662b9b067670129a8afb8c18e351482c70d62ba4a88171e8b"
|
|
73
|
+
dependencies = [
|
|
74
|
+
"libc",
|
|
75
|
+
"once_cell",
|
|
76
|
+
"portable-atomic",
|
|
77
|
+
"pyo3-build-config",
|
|
78
|
+
"pyo3-ffi",
|
|
79
|
+
"pyo3-macros",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[[package]]
|
|
83
|
+
name = "pyo3-build-config"
|
|
84
|
+
version = "0.29.2"
|
|
85
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
86
|
+
checksum = "f41027e41b4bd03f6e60f9f417fe24a6341a6bb744edd62b6f709f2a52ea30e9"
|
|
87
|
+
dependencies = [
|
|
88
|
+
"target-lexicon",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
[[package]]
|
|
92
|
+
name = "pyo3-ffi"
|
|
93
|
+
version = "0.29.2"
|
|
94
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
95
|
+
checksum = "e591a95526fead067432c3b3a33fc74770b87b1e04e73671090d9c2055a2b327"
|
|
96
|
+
dependencies = [
|
|
97
|
+
"libc",
|
|
98
|
+
"pyo3-build-config",
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
[[package]]
|
|
102
|
+
name = "pyo3-macros"
|
|
103
|
+
version = "0.29.2"
|
|
104
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
105
|
+
checksum = "73225868fc1cd84eef2c3c230ddb91273bf1de46aeb8a4248da76d32a0924a1c"
|
|
106
|
+
dependencies = [
|
|
107
|
+
"proc-macro2",
|
|
108
|
+
"pyo3-macros-backend",
|
|
109
|
+
"quote",
|
|
110
|
+
"syn 2.0.119",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
[[package]]
|
|
114
|
+
name = "pyo3-macros-backend"
|
|
115
|
+
version = "0.29.2"
|
|
116
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
117
|
+
checksum = "571575aa3749fa6216757dd47d2a3e7ef360f329a40f0666a9fbd14889024952"
|
|
118
|
+
dependencies = [
|
|
119
|
+
"heck",
|
|
120
|
+
"proc-macro2",
|
|
121
|
+
"quote",
|
|
122
|
+
"syn 2.0.119",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
[[package]]
|
|
126
|
+
name = "quote"
|
|
127
|
+
version = "1.0.47"
|
|
128
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
129
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
130
|
+
dependencies = [
|
|
131
|
+
"proc-macro2",
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
[[package]]
|
|
135
|
+
name = "serde"
|
|
136
|
+
version = "1.0.229"
|
|
137
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
138
|
+
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
139
|
+
dependencies = [
|
|
140
|
+
"serde_core",
|
|
141
|
+
"serde_derive",
|
|
142
|
+
]
|
|
143
|
+
|
|
144
|
+
[[package]]
|
|
145
|
+
name = "serde_core"
|
|
146
|
+
version = "1.0.229"
|
|
147
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
148
|
+
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
|
149
|
+
dependencies = [
|
|
150
|
+
"serde_derive",
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
[[package]]
|
|
154
|
+
name = "serde_derive"
|
|
155
|
+
version = "1.0.229"
|
|
156
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
157
|
+
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
|
158
|
+
dependencies = [
|
|
159
|
+
"proc-macro2",
|
|
160
|
+
"quote",
|
|
161
|
+
"syn 3.0.6",
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
[[package]]
|
|
165
|
+
name = "serde_json"
|
|
166
|
+
version = "1.0.151"
|
|
167
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
168
|
+
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
|
169
|
+
dependencies = [
|
|
170
|
+
"itoa",
|
|
171
|
+
"memchr",
|
|
172
|
+
"serde",
|
|
173
|
+
"serde_core",
|
|
174
|
+
"zmij",
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
[[package]]
|
|
178
|
+
name = "syn"
|
|
179
|
+
version = "2.0.119"
|
|
180
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
181
|
+
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
|
182
|
+
dependencies = [
|
|
183
|
+
"proc-macro2",
|
|
184
|
+
"quote",
|
|
185
|
+
"unicode-ident",
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
[[package]]
|
|
189
|
+
name = "syn"
|
|
190
|
+
version = "3.0.6"
|
|
191
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
192
|
+
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
|
193
|
+
dependencies = [
|
|
194
|
+
"proc-macro2",
|
|
195
|
+
"quote",
|
|
196
|
+
"unicode-ident",
|
|
197
|
+
]
|
|
198
|
+
|
|
199
|
+
[[package]]
|
|
200
|
+
name = "target-lexicon"
|
|
201
|
+
version = "0.13.5"
|
|
202
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
203
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
204
|
+
|
|
205
|
+
[[package]]
|
|
206
|
+
name = "unicode-ident"
|
|
207
|
+
version = "1.0.26"
|
|
208
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
209
|
+
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
|
210
|
+
|
|
211
|
+
[[package]]
|
|
212
|
+
name = "zmij"
|
|
213
|
+
version = "1.0.23"
|
|
214
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
215
|
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "nnnotes-deck"
|
|
3
|
+
# the nnnotes version (src/nnnotes/__init__.py); the wheel takes its version from here
|
|
4
|
+
version = "0.1.3"
|
|
5
|
+
edition = "2024"
|
|
6
|
+
rust-version = "1.85"
|
|
7
|
+
description = "nnnotes._deck: the ournotes-deck chart statistics as a Python extension module"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
publish = false
|
|
10
|
+
|
|
11
|
+
[lib]
|
|
12
|
+
name = "_deck"
|
|
13
|
+
crate-type = ["cdylib"]
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
pyo3 = { version = "0.29", features = ["abi3-py311"] }
|
|
17
|
+
# pinned by commit; .github/workflows/deck.yml opens a pull request when ournotes-deck moves
|
|
18
|
+
ournotes-deck = { git = "https://github.com/empty-sekai/ournotes-deck", rev = "dbd9cf01a4854808dceb6aedcd4041af372faeee" }
|
|
19
|
+
serde_json = { version = "1", features = ["raw_value", "arbitrary_precision"] }
|
|
20
|
+
|
|
21
|
+
[profile.release]
|
|
22
|
+
lto = "thin"
|
|
23
|
+
codegen-units = 1
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//! Records the ournotes-deck package the module is built with (version and git commit, from Cargo.lock) as the
|
|
2
|
+
//! environment variables DECK_VERSION, DECK_SOURCE and DECK_COMMIT of the crate.
|
|
3
|
+
|
|
4
|
+
use std::path::Path;
|
|
5
|
+
|
|
6
|
+
fn main() {
|
|
7
|
+
let dir = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR");
|
|
8
|
+
let lock = Path::new(&dir).join("Cargo.lock");
|
|
9
|
+
println!("cargo:rerun-if-changed={}", lock.display());
|
|
10
|
+
let text = std::fs::read_to_string(&lock).expect("rust/Cargo.lock (the deck commit is read from it)");
|
|
11
|
+
let (mut version, mut source) = (None, None);
|
|
12
|
+
for block in text.split("[[package]]") {
|
|
13
|
+
let field = |k: &str| {
|
|
14
|
+
block.lines().find_map(|l| {
|
|
15
|
+
let v = l.trim().strip_prefix(k)?.trim_start().strip_prefix('=')?.trim();
|
|
16
|
+
Some(v.trim_matches('"').to_string())
|
|
17
|
+
})
|
|
18
|
+
};
|
|
19
|
+
if field("name").as_deref() == Some("ournotes-deck") {
|
|
20
|
+
version = field("version");
|
|
21
|
+
source = field("source");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
let version = version.expect("Cargo.lock has no ournotes-deck package");
|
|
25
|
+
let source = source.expect("ournotes-deck has no source in Cargo.lock");
|
|
26
|
+
// git+https://github.com/empty-sekai/ournotes-deck?rev=<rev>#<commit>
|
|
27
|
+
let (url, commit) = source.split_once('#').expect("ournotes-deck is not a git dependency");
|
|
28
|
+
let url = url.strip_prefix("git+").unwrap_or(url);
|
|
29
|
+
let url = url.split_once('?').map_or(url, |(u, _)| u);
|
|
30
|
+
println!("cargo:rustc-env=DECK_VERSION={version}");
|
|
31
|
+
println!("cargo:rustc-env=DECK_SOURCE={url}");
|
|
32
|
+
println!("cargo:rustc-env=DECK_COMMIT={commit}");
|
|
33
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
//! `nnnotes._deck`: the chart statistics of ournotes-deck (`ournotes-deck.chart-stats/2`) on a deck data document
|
|
2
|
+
//! held in memory, the charts measured in parallel.
|
|
3
|
+
|
|
4
|
+
use std::sync::Mutex;
|
|
5
|
+
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
6
|
+
|
|
7
|
+
use ournotes_deck::chartstats::{self, AptitudeOptions, ChartStats, GEKISOU_SEEDS, Options};
|
|
8
|
+
use ournotes_deck::data::DeckData;
|
|
9
|
+
use ournotes_deck::error::Error;
|
|
10
|
+
use pyo3::exceptions::PyValueError;
|
|
11
|
+
use pyo3::prelude::*;
|
|
12
|
+
use pyo3::types::PyDict;
|
|
13
|
+
|
|
14
|
+
fn value_error(e: impl std::fmt::Display) -> PyErr {
|
|
15
|
+
PyValueError::new_err(e.to_string())
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// The statistics of every chart, in chart order, on `workers` threads.
|
|
19
|
+
fn measure(data: &DeckData, options: &Options, workers: usize) -> Result<Vec<ChartStats>, Error> {
|
|
20
|
+
let kinds = chartstats::kinds(&data.master);
|
|
21
|
+
let n = data.charts.len();
|
|
22
|
+
let next = AtomicUsize::new(0);
|
|
23
|
+
let out: Mutex<Vec<Option<Result<ChartStats, Error>>>> = Mutex::new((0..n).map(|_| None).collect());
|
|
24
|
+
std::thread::scope(|s| {
|
|
25
|
+
for _ in 0..workers.clamp(1, n.max(1)) {
|
|
26
|
+
s.spawn(|| {
|
|
27
|
+
loop {
|
|
28
|
+
let i = next.fetch_add(1, Ordering::Relaxed);
|
|
29
|
+
if i >= n {
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
let c = &data.charts[i];
|
|
33
|
+
// as chartstats::document names a chart's domain errors
|
|
34
|
+
let r = chartstats::chart_stats_with(&data.master, c, &kinds, options).map_err(|e| match e {
|
|
35
|
+
Error::Domain(m) => Error::Domain(format!("chart {}: {m}", c.score_id)),
|
|
36
|
+
e => e,
|
|
37
|
+
});
|
|
38
|
+
let failed = r.is_err();
|
|
39
|
+
out.lock().expect("results")[i] = Some(r);
|
|
40
|
+
if failed {
|
|
41
|
+
next.store(n, Ordering::Relaxed);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
// charts are taken in order and a taken chart always completes, so every chart before the first failure has
|
|
48
|
+
// its result: the error returned is the first in chart order, as the command's
|
|
49
|
+
let mut stats = Vec::with_capacity(n);
|
|
50
|
+
for r in out.into_inner().expect("results") {
|
|
51
|
+
stats.push(r.expect("a chart before the first failure has run")?);
|
|
52
|
+
}
|
|
53
|
+
Ok(stats)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// chart_stats(data, seeds=None, workers=None, aptitude=True, aptitude_max_seeds=None,
|
|
57
|
+
/// aptitude_cross_seeds=None) -> str
|
|
58
|
+
///
|
|
59
|
+
/// The `ournotes-deck.chart-stats/2` document (JSON text) of a deck data document (`nnnotes.deck-data/1` JSON text),
|
|
60
|
+
/// as `ournotes-deck chart-stats` writes it. `seeds`: the size of the seed set of charts with a luck range (default
|
|
61
|
+
/// 8); `workers`: threads measuring charts (default: the available parallelism). Raises ValueError for data the
|
|
62
|
+
/// deck model cannot read or a chart whose check deck fails. `aptitude`: measure single Gekisou skill shapes
|
|
63
|
+
/// (default true); `aptitude_max_seeds` and `aptitude_cross_seeds`: sample caps (defaults 65536 and 64).
|
|
64
|
+
#[pyfunction]
|
|
65
|
+
#[pyo3(signature = (data, seeds=None, workers=None, aptitude=true, aptitude_max_seeds=None, aptitude_cross_seeds=None))]
|
|
66
|
+
fn chart_stats(
|
|
67
|
+
py: Python<'_>,
|
|
68
|
+
data: &str,
|
|
69
|
+
seeds: Option<usize>,
|
|
70
|
+
workers: Option<usize>,
|
|
71
|
+
aptitude: bool,
|
|
72
|
+
aptitude_max_seeds: Option<usize>,
|
|
73
|
+
aptitude_cross_seeds: Option<usize>,
|
|
74
|
+
) -> PyResult<String> {
|
|
75
|
+
let seeds = seeds.unwrap_or(GEKISOU_SEEDS);
|
|
76
|
+
let defaults = AptitudeOptions::default();
|
|
77
|
+
let options = Options {
|
|
78
|
+
seeds,
|
|
79
|
+
aptitude: aptitude.then_some(AptitudeOptions {
|
|
80
|
+
max_seeds: aptitude_max_seeds.unwrap_or(defaults.max_seeds),
|
|
81
|
+
cross_seeds: aptitude_cross_seeds.unwrap_or(defaults.cross_seeds),
|
|
82
|
+
}),
|
|
83
|
+
};
|
|
84
|
+
let workers = workers.unwrap_or_else(|| std::thread::available_parallelism().map_or(1, |n| n.get()));
|
|
85
|
+
py.detach(|| {
|
|
86
|
+
let mut data = DeckData::from_json(data).map_err(value_error)?;
|
|
87
|
+
let charts = std::mem::take(&mut data.charts);
|
|
88
|
+
// the document of no chart: the format, source, model and kinds, exactly as the command writes them
|
|
89
|
+
let mut doc = chartstats::document_with(&data, &options).map_err(value_error)?;
|
|
90
|
+
data.charts = charts;
|
|
91
|
+
let stats = measure(&data, &options, workers).map_err(value_error)?;
|
|
92
|
+
doc["charts"] = serde_json::to_value(stats).map_err(value_error)?;
|
|
93
|
+
serde_json::to_string(&doc).map_err(value_error)
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// info() -> dict: the ournotes-deck package of this module (name, version, source, commit) and the formats it reads
|
|
98
|
+
/// and writes.
|
|
99
|
+
#[pyfunction]
|
|
100
|
+
fn info(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
|
|
101
|
+
let d = PyDict::new(py);
|
|
102
|
+
d.set_item("name", "ournotes-deck")?;
|
|
103
|
+
d.set_item("version", env!("DECK_VERSION"))?;
|
|
104
|
+
d.set_item("source", env!("DECK_SOURCE"))?;
|
|
105
|
+
d.set_item("commit", env!("DECK_COMMIT"))?;
|
|
106
|
+
d.set_item("dataFormat", ournotes_deck::data::FORMAT)?;
|
|
107
|
+
d.set_item("format", chartstats::FORMAT)?;
|
|
108
|
+
Ok(d)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#[pymodule]
|
|
112
|
+
fn _deck(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
113
|
+
m.add_function(wrap_pyfunction!(chart_stats, m)?)?;
|
|
114
|
+
m.add_function(wrap_pyfunction!(info, m)?)?;
|
|
115
|
+
Ok(())
|
|
116
|
+
}
|
|
@@ -4,4 +4,4 @@ Reads Addressables catalogs, fetches and decrypts asset bundles, decodes master
|
|
|
4
4
|
models, spots, shaders, CRI audio and live charts as JSON and common file formats. Game files, keys and server
|
|
5
5
|
addresses are supplied by the user through the configuration; nothing of the game is included.
|
|
6
6
|
"""
|
|
7
|
-
__version__ = "0.1.
|
|
7
|
+
__version__ = "0.1.3"
|