scoring: the score AUTHORITY is the operator console -- and our port has none
Follow-up to 2772175 (type-0 interceptor restored). Benching the restored
credit exposed the next layer, and two of my attempts at it were wrong; both
are recorded so they are not retried.
FINDING [T1]: the binary flushes ConsolePlayerVTVScoreUpdate(ownerID,
currentScore) then does `param_1[0x9e] = 0` -- UNGATED. So +0x278 is a console
DELTA, never a running total, and it does not matter which NODE computed one:
every delta is stamped with the scoring player's ownerID and the CONSOLE
accumulates. That is almost certainly where the manual chart's "+1000 starting
the game" was seeded, which is why no game-side code grants it.
Our port has no console as score authority. GetScore() (SCORE gauge),
CalcRanking() and the replicated Player__UpdateRecord all read +0x278 on the
OWNING node. Damage is applied on the VICTIM's node, so block B dispatches the
inflicted report to the SHOOTER's player object there -- a REPLICANT -- and the
master's next update record overwrites it. Benched: totals climb to ~35 and
snap back every few seconds. THAT is the "scoring went screwy" report.
WRONG TURN 1 (reverted in spirit, kept only where harmless): blamed the console
flush and added a last-sent watermark so the console still gets deltas while
+0x278 keeps a total. The resets were 2s apart, not on the 10s console
interval -- the timing was already in the data. The watermark stays because it
does stop the FLUSH from zeroing a master's own total, but it was not the bug.
WRONG TURN 2 (reverted): gated the interception to MasterInstance so a
replicant would reroute to the master. The message arrives, but the BT
extension fields (damageAmount@+0x24, senderMechID@+0x34) do NOT survive the
wire -- only the base scoreAward -- so every award computed 0.00. That failure
is the clue to the answer: the kill report (type 2) credits cross-node
correctly precisely because its value rides scoreAward.
FIX SHAPE (not implemented -- landing it deliberately rather than guessing a
third time): compute the award on the victim's node, where the damage data
lives, and ship the RESULT in scoreAward the way the kill report already does,
instead of shipping the basis and recomputing on a machine that cannot see it.
State now = binary-faithful unconditional interception. Re-benched: 79
inflicted rows, awards 0.98..25.00 all positive and tracking damage, 0 type-0
Verify rejections. Cross-node banking still open.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
This commit is contained in:
co-authored by
Claude Opus 5
parent
27721754da
commit
e82f54c957
@@ -646,6 +646,26 @@ is the cross-check for every row and should be consulted before touching this pa
|
||||
| −500 | Destroying your own 'Mech by an ammo explosion |
|
||||
| −1000 | Destroying your own 'Mech by ejecting |
|
||||
|
||||
⚠ **THE SCORE AUTHORITY IS THE OPERATOR CONSOLE, not the player object** [T1, 2026-08-07]. The
|
||||
binary sends `ConsolePlayerVTVScoreUpdate(ownerID, currentScore)` every `CONSOLE_UPDATE_INTERVAL`
|
||||
and then does `param_1[0x9e] = 0` — **ungated**. So `+0x278` is a *console DELTA*, never a running
|
||||
total, and it does not matter which NODE computed a delta: every node's contribution is flushed
|
||||
stamped with the scoring player's `ownerID` and the console accumulates. This is almost certainly
|
||||
where the chart's **+1000 starting the game** was seeded, which is why no game-side code grants it.
|
||||
|
||||
**Consequence for the port** (no console as score authority): `GetScore()` (SCORE gauge),
|
||||
`Player::CalcRanking()` and the replicated `Player__UpdateRecord` all read `+0x278` **on the owning
|
||||
node**. Damage is applied on the VICTIM's node, so block B dispatches the inflicted report to the
|
||||
SHOOTER's player object there — a **REPLICANT** — and the credit is banked on the wrong machine,
|
||||
where the master's next update record overwrites it (benched: totals climb to ~35, snap back every
|
||||
few seconds = the field "scoring is screwy"). ⚠ OPEN. **Tried and rejected:** gating the type-0
|
||||
interception to `MasterInstance` so a replicant reroutes — the message arrives but the BT extension
|
||||
fields (`damageAmount`@+0x24, `senderMechID`@+0x34) do NOT survive the wire, only the base
|
||||
`scoreAward`, so every award computes 0.00. That is also WHY the kill report (type 2) already
|
||||
credits cross-node correctly: its value rides `scoreAward`. **Fix shape:** compute the award on the
|
||||
victim's node (where the damage data is) and ship the RESULT in `scoreAward`, as the kill report
|
||||
does — do not ship the basis and recompute where it cannot be seen.
|
||||
|
||||
⚠ **Three chart rows are NOT yet reconciled with the reconstruction** — treat as open [T4]:
|
||||
(a) a kill benches at `award=4.88`, two orders off the chart's flat **+500**; (b) **+1000 at
|
||||
game start** has no known implementation; (c) **−1000 eject / −500 ammo** would live in
|
||||
|
||||
Reference in New Issue
Block a user