Files

104 lines
6.6 KiB
Markdown
Raw Permalink Normal View History

# Damage Analyst: native live statistics
The Client's final PVEBattleResult packet can contain a correct monster/team
total while all AvatarBattleInfo detail counters are zero. Its cached native
PVEGameStatistics still contains the complete character details. The old live
sender also read this last completed report during the next battle.
The live sender now reads the active BattleGamePhase.BattleInstanceRef's logic
GameWorld, then the native level entity's StatisticsComponent. It reads only
known fields and caches them; component discovery is bounded to 16 entities
and 32 component slots per sample and uses the named StatisticsComponent type.
No assembly-wide reflection is performed. Do not call BuildPVEStatistics while
playing: native code caches the snapshot it builds, so calling it for a UI
poll could freeze the game's eventual report at an early point.
The source `_LightTeamStt` contains the current AvatarBattleInfo. Native
PVECharacterStt dictionaries supply attack-type totals (`FNFFCPLHPGI`), break
totals (`HNJNDLEFMBE`) and maximum hits (`KEOOJBHFLFD`) because the corresponding
protobuf lists are assembled only at settlement. The aggregate total remains
the named TotalDamage; some attribution counters do not appear in the category
dictionary, so that aggregate is not replaced by a category sum.
Additional fixes:
- XLua returns protobuf byte arrays as Lua strings on this Client. Their byte
length is `#bytes`; `.Length` was nil and stopped all uploads.
- UploadHandlerRaw accepts the ASCII JSON body directly as bytes. Calling the
unavailable Encoding.GetBytes overload stopped uploads after the first fix.
- Sampling runs every 750 ms through render callbacks, with a heartbeat
fallback for background windows/render paths that suppress a callback.
Callbacks read the current sample function after a script refresh; earlier
broken callback states are disabled without changing Client battle state.
- Native NOGHNMCDDAI is a damage-taken breakdown, verified against supports with
zero dealt damage. It is no longer used as a damage-dealt fallback.
- BattleInfo accompanies live reports, providing StageID, BattleID, level,
rank and each avatar's actual slot. The companion UI orders by these slots,
independently of the overworld team. Historical reports without slots keep
their recorded order.
- Final native details are attached only to a completed result whose duration,
turn count and avatar IDs match. Server outcome and monster analysis remain
intact; mismatching snapshots are rejected and cannot change the report.
- The UI renders additional native attack types, including ElationDamage and
TrueDamage, with escaped labels instead of omitting those categories.
## Evidence and verification
The ignored `battle_diagnostics/damage-live-20261019` directory preserves native
protobuf snapshots, diagnostic logs and `live-api-verified.json`. The Client
assembly SHA-256 is
`c5e02e6e984f7e5577c78b995a8efeee2d06ee22e67d484ad5e859c8bf21e144`.
During the user's active stage 1052106, API `is_live=true` changed from
5,906,923.87 to 6,825,838.95 damage before settlement, with four current
characters in slots 0–3, level/rank metadata, native category breakdowns and
shares summing to 100%. This verifies the Client-to-SDK live path; it is not a
synthetic test report. Frontend slot/category changes require the corresponding
GaC-srtool build to be published before they appear on hosted GitHub Pages.
Focused Go report/API tests cover damage-taken exclusion, native category data,
slot identity, final matching/rejection and expiry. The frontend Node tests
cover actual battle order versus a different overworld team and historical
report behavior. Diagnostic probes are kept outside scripts after capture.
Published GaC-srtool commit e03e5b1 to main with user approval. The GitHub Pages workflow completed successfully, and fetching the public app.js confirmed the battle-slot and additional-category code. The final real Client report retained WIN, Stage1052106, four slots 0-3 and detailed damage after leaving battle. Browser UI automation was unavailable in local Work settings; frontend rendering was checked with the actual captured live report in a DOM fixture, plus a public asset check.
## Memosprite attribution and Other (2026-10-20)
The earlier reader omitted the separate servant statistics. The native named
StatisticsComponent field `_ServantStt` contains `LLPEHDFMLNJ` values; bounded
reflection of this specific type found `LJLDPJFOKCE` (HFALLFOEHKN servant
protobuf) and the same three attack-type dictionaries as character statistics.
Completed PVEGameStatistics exposes `servantBattleInfoList`. Both are now sent
through the SDK as separate servant protobufs; active category dictionaries are
hydrated without invoking the native final snapshot builder.
The checked-in protocol's BattleAvatarServantInfo explicitly names `avatar_id`,
`entity_id`, aggregate damage and attack-type lists. Ownership uses `avatar_id`,
with no character ID or lineup-position special cases. The report combines the
separate servant damage/healing/shield with that owner and exposes the included
damage as `memosprite_damage`. Damage taken and owner turns remain the owner's
counters. Maximum hit uses the maximum across owner and servant, rather than
adding maxima. Repeated nonzero entity IDs are ignored. Team totals/shares are
rebuilt from attributed records so a monster damage-taken fallback is not added
again. Inputs are not modified, and alternate servant sources cannot be mixed
in the same request.
The fifth frontend category is Other: the nonnegative remainder after Basic,
Skill, Ultimate and Break. Existing named extra categories remain visible as
details. A Memosprite line explicitly marks its damage as included in the
character total. Frontend commit `ca5831c` contains only these damage changes;
unrelated item-catalog work in the shared checkout was left uncommitted.
Verification: focused Go report/API tests pass, including an HTTP roundtrip
with owner-only and servant records, correct percentage recalculation,
duplicate/unknown owner handling, and prevention of monster-fallback double
counting. Four frontend tests pass, including Other arithmetic and existing
slot order. The local SDK executable has the new receiver. Temporary servant
probes have been removed from scripts/ and retained only under tools/.
Runtime limitation: the current session did not provide a nonempty servant
sample. The previous real Client verification above used a team without
memosprites. Evernight's live/final ownership and aggregate behavior still need
a real battle capture; passing synthetic tests does not establish that the
Client integration works. Native obfuscated field names remain revision-bound.