Add achievement export support

This commit is contained in:
Golumpa 2026-08-19 13:00:09 +01:00
parent 40b44521aa
commit 5fe39b96ae
15 changed files with 197 additions and 55 deletions

View file

@ -15,7 +15,7 @@ decoder-only offsets.
"capture_source": "npcap",
"exporter": {
"name": "nte-history-exporter",
"version": "0.2.1"
"version": "0.3.0"
},
"banner": {
"id": "Lottery_Permanent",
@ -176,6 +176,79 @@ Mystery Box:
}
```
## Achievement export
Achievements are written separately as
`<user_uid>_Achievements_<date_time>.json`. The document contains only records
observed in the account's login response; definitions found only in the asset
mapping are not synthesized into the export.
```json
{
"format": "nte-achievement-export",
"format_version": 1,
"game": "Neverness to Everness",
"source": "live_capture",
"capture_source": "npcap",
"exporter": {
"name": "nte-history-exporter",
"version": "0.3.0"
},
"scan": {
"in_game": {
"total_achievements": 367,
"completed_achievements": 310,
"in_progress_achievements": 57
},
"playstation": {
"total_achievements": 35,
"completed_achievements": 31,
"in_progress_achievements": 4
}
},
"user_uid": "218216016349",
"server_id": "23003",
"account_region": "EU",
"categories": {
"battle": [
{
"id": "Battle_25",
"platform": "in_game",
"status": "in_progress",
"progress": 20,
"completed": false,
"completed_at": null,
"name": "Devil Within II",
"description": "Trigger Hexed ×50.",
"quality": "high",
"target": 50,
"rewards": [
{"item_id": "Annulith", "amount": 10}
]
}
]
}
}
```
Achievement fields:
- `scan.in_game` and `scan.playstation` separate records visible in game from
PlayStation trophy records and report completed/in-progress totals.
- `categories` groups records by the prefix of their captured ID. The category
is therefore not repeated on every record.
- `status` is `completed` when completion ticks are present and `in_progress`
otherwise. An observed compound achievement can be in progress while its
numeric `progress` is zero because individual checklist state is server-side.
- `completed_at` is a decoded UTC time for completed records and `null` for
in-progress records.
- `name`, `description`, `quality`, `target`, and `rewards` are optional display
metadata from `mappings/achievements.json`.
- A newly captured ID missing from the bundled mapping still exports its core
captured fields; only optional display metadata is omitted.
- Asset definitions absent from the network response are not exported because
absence cannot distinguish unstarted, locked, or unavailable content.
## CSV diagnostics
CSV exports are mainly for debugging the decoder. Tools should prefer JSON

View file

@ -21,5 +21,13 @@ Known limitations:
- The file adapter reads mitmproxy `.flows` captures for research and testing.
- Npcap is Windows-only and is not redistributed with this project; Linux and macOS use their system libpcap.
- Reward keys decode to their reward id string, so unknown rewards still export a usable `reward_id`; display names/ranks come from the mapping JSON files and should be expanded as new rewards appear.
- Achievement exports contain only records observed in the login response.
Asset-only definitions are not synthesized because absence cannot distinguish
unstarted, locked, or unavailable content. Unknown captured achievement IDs
still export without optional display metadata.
- Observed achievements have only `completed` and `in_progress` states. Some
compound achievements expose numeric progress `0` while the server tracks
hidden checklist progress, so every observed record without completion ticks
is classified as `in_progress`.
Privacy guardrail: raw packet data must not be included in sanitized exports.

View file

@ -1,4 +1,4 @@
# Reward mapping updates
# Mapping updates
`tools/update_mappings.py` rebuilds `arcs.json`, `characters.json`,
`items.json`, and `achievements.json` directly from the current
@ -19,7 +19,7 @@ game whose asset tables evolve over time.
### GitHub Actions
Run **Update reward mappings** from the repository's Actions tab. The optional
Run **Update mappings** from the repository's Actions tab. The optional
`source_ref` input accepts an NTE_Assets branch, tag, or commit and defaults to
`main`.
@ -68,7 +68,7 @@ python -m pytest -q
```
For CI, `--check` exits with status 1 whenever the generated snapshot differs
from the committed reward mappings. It still writes the staged artifacts.
from the committed mappings. It still writes the staged artifacts.
## Source rules
@ -100,7 +100,7 @@ reads or writes the permanent, limited, beginner, or Arc pool mapping files.
Banner IDs, timestamps, record ordering, format version, and all UID inputs are
therefore unchanged by mapping synchronization.
Reward IDs and display metadata may change or disappear when the authoritative
NTE_Assets snapshot changes. Existing exported history files remain unchanged;
new exports describe rewards using the current asset snapshot. UID stability is
independent of reward display mappings.
Reward and achievement IDs or display metadata may change or disappear when
the authoritative NTE_Assets snapshot changes. Existing exports remain
unchanged; new exports use the current asset snapshot. UID stability is
independent of display mappings.

View file

@ -1,6 +1,21 @@
# Packet Format Notes
This prototype supports separate Monopoly, Arc/Gashapon, and Mystery Box history decoders.
This prototype supports separate Monopoly, Arc/Gashapon, Mystery Box history,
and achievement decoders.
## Achievements
The account's achievement component arrives in an inbound TCP game-data block
during login. The block is LZ4-decoded and contains `AchievementRecord` entries.
Each record provides an achievement ID, an unsigned numeric progress value, and
a .NET completion timestamp. A non-zero timestamp marks a completed record.
Every observed record without completion ticks is treated as in progress;
compound achievements can have server-side checklist progress while exposing a
numeric value of zero.
Only records present in the network response are exported. Display metadata is
looked up case-insensitively in `mappings/achievements.json`, because captured
and asset-table ID casing can differ. Missing metadata never prevents export.
## Decoder strategy