Show personal map records on join and replay

This commit is contained in:
2026-10-19 14:11:54 -04:00
parent 9ef5932d36
commit e93182cd02
11 changed files with 620 additions and 200 deletions
+64 -34
View File
@@ -458,12 +458,13 @@ count appears only when more than one page is needed. Each page lasts
command restarts page one. Both engines position rows explicitly, avoiding
T5's newline-rendering problem.
Records use the same service area, right aligned: `Map record | Round N`
followed by up to three bounded holder lines. Single-page records have no
counter or footer; ties spanning multiple pages retain a page count and
12 seconds per page. Help pauses a visible record and resumes its remaining
page time when help ends. `.leaders` during help replaces the pending record
with a fresh replay from page one. Round-start reminders use just the record
Records use the same service area, right aligned: `Map Record | Round N`,
followed by every tied holder on a separate line. After a blank row,
`Your Best | Round N` uses the same heading style as the map record, distinct
from the holder names. The entire announcement is visible at once for 12 seconds;
records have no pages, counter or footer. Help pauses a visible record and
resumes its remaining time when help ends. `.leaders` during help replaces the
pending record with a fresh replay. Round-start reminders use just the record
header and one proximity or milestone line for six seconds. They skip busy
services; opening help discards a reminder instead of resuming it later.
One service is visible at a time. Services remain private and work when the
@@ -472,7 +473,8 @@ HUD module is omitted.
Both games allocate only the active service view and release it when idle or
before switching between help and records. Pages reuse the active view's
elements. The core uses 10 archived elements, plus two independent elements for AFK. A nine-row help page uses 19 nonarchived elements, or 20 with a multi-page
counter; records use four, or five with a multi-page counter. Hidden elements
counter; full records use one element per holder plus the map and personal
headings. Hidden elements
still occupy slots. Compact reminders use two nonarchived elements.
The controller and pending requests are separate from
display lifetime, so an idle service holds no HUD elements.
@@ -484,7 +486,8 @@ avoiding dynamic counter strings in the text config-string pool. Numeric HP
still uses `SetValue`. On r5334+, deploy the updated HUD script and restart
the map; no full server-process restart is required. On older Plutonium
revisions, update clients and server and fully restart them before deploying.
Leaderboard `1.2.0` requires matching common `1.5.0+` for round-start reminders.
Leaderboard `1.3.1` requires matching common `1.6.1+` for personal records
and round-start reminders.
AFK `2.0.0` requires plugin `1.4.0+`,
common `1.4.0+` and the EC reserve service; see the [AFK guide](docs/afk.md). Existing
leaderboard plugin requirements still apply. Common retains its older panel
@@ -526,10 +529,9 @@ Before rollout, validate both engines in Plutonium:
exercise the nine-row page limit, page counter and repeat-to-restart behavior.
Remove optional modules and restart the map to confirm filtering, including
`.hud` disappearing without HUD, then restore them.
4. Interrupt records with help and check that the interrupted page resumes for
4. Interrupt records with help and check that the full announcement resumes for
its remaining time. Repeat `.leaders` while help is open; only the latest
replay should start, at page one. Check long holder names, ties spanning
pages, no records, and unavailable records. Repeat without the HUD installed.
replay should start. Check long holder names, all tied holders visible at once, no records, and unavailable records. Repeat without the HUD installed.
5. Disconnect or end the game while help/records are active, reconnect and
request them again. Verify no duplicate elements, stale timeout closures or
surviving service windows. Confirm `.join`, bank commands and lobby lock
@@ -548,13 +550,14 @@ Before rollout, validate both engines in Plutonium:
## Map record announcements
Install `tws_t5_leaderboard.gsc` for T5 or `tws_t6_leaderboard.gsc` for T6,
**along with common `1.5.0+`** for that game when using leaderboard `1.2.0`.
**along with common `1.6.1+`** for that game when using leaderboard `1.3.1`.
Copy both scripts for each installed game and restart the map. This update
adds no native-plugin or backend requirement and needs no full server-process
restart when existing leaderboard dependencies are already installed.
The module privately announces the current map's fleet-wide highest recorded
round and every tied holder once per connection, including spectator newcomers.
Type `.leaders` to replay the record privately from the latest usable cache.
round, every tied holder and the joining player’s personal best on that map once
per connection, including spectator newcomers. Type `.leaders` to replay both
records privately. Personal bests use the same game and exact map variant.
Repeating the command restarts the announcement from its first page. It appears
in `.help` when the leaderboard module is enabled. If no usable record is
available, the service identifies the record as unavailable; this differs from
@@ -580,18 +583,32 @@ exist in the API's map list and match the current game and engine map. Clear it
when changing variants; restart the map after changing these settings.
The announcement starts five seconds after player readiness and waits for the
initial record fetch if necessary. It appears as right-aligned text in the
common-owned upper-right service area: `Map record | Round N`, followed by up
to three holder lines. There is no background or replay footer, and a page
count appears only for multi-page records. Each page lasts 12 seconds. Opening `.help` pauses the record's remaining
page time until help closes. A `.leaders` request during help replaces any
pending replay and starts from page one after help closes.
initial map and personal record fetches if necessary. It appears as right-aligned
text in the common-owned upper-right service area, all at once:
```text
Map Record | Round 25
Player 1
Player 2
Player 3
Player 4
Your Best | Round 15
```
Each holder has a separate line. The personal best has its own heading below a
blank row and uses the map heading's brighter colour and font size. A confirmed
empty personal history shows `Your Best | None yet`; a failed lookup shows
`Your Best | Unavailable`. There is no background, replay footer, pagination or
page counter. The whole view lasts 12 seconds. Opening `.help` pauses its
remaining time until help closes. A `.leaders` request during help replaces any
pending replay and starts a fresh 12-second view after help closes.
All holders are included; colour/control codes are removed, and overlong
individual names are abbreviated without splitting UTF-8 characters. Bounded
lines and additional pages preserve every tied holder. The window closes when
the announcement finishes. Both games release their view elements when idle or
changing service kinds. Disconnect or game end cleans up any remaining service
elements.
individual names are abbreviated without splitting UTF-8 characters. The window
closes when the announcement finishes. Both games release their view elements
when idle or changing service kinds, and resize the holder list when a new record
has a different number of holders. Disconnect or game end cleans up any remaining
service elements.
At round start, reminders become more frequent as the current round approaches
the latest usable cached record. The cadence is measured back from that record:
@@ -607,10 +624,10 @@ the latest usable cached record. The cadence is measured back from that record:
For a round 50 record, reminders appear on rounds 30, 35, 40, 42, 44 and
45–49, with milestones at 50 and 51. Each uses the existing record header and
one short proximity or milestone line for six seconds, without holder pages.
one short proximity or milestone line for six seconds, without the holder list.
Milestones describe the round reached; the new result is recorded only after
the match ends. The full join announcement and `.leaders` retain all holders
and their 12-second pages. `.leaders` remains available after the overtake.
in one 12-second view. `.leaders` remains available after the overtake.
Reminders require player readiness and skip players with a pending welcome,
help or record view, or a welcome/manual record request in the last 30 seconds.
@@ -628,10 +645,21 @@ Partial page results never replace the cache. The API has no pagination snapshot
token: changed totals/record rounds reject the refresh, but concurrent renames can
still move entries between pages. Refreshes deduplicate GUIDs.
Personal lookups use the existing public endpoint’s `q` search, scoped to the
resolved map key. Search results can match names or partial GUIDs, so only an
exact string GUID with matching game/map record evidence is accepted. Successful
personal results cache for five minutes per connection; failures cache as
unavailable for 30 seconds. Searches paginate in groups of three and stop
starting further pages after 15 seconds; incomplete searches are unavailable.
A valid empty map history needs no personal request. No backend or plugin update
is needed. Round reminders continue to use only the map cache.
Requests have a 15-second GSC wait limit. The TWS plugins also enforce native
5-second connection and 15-second transfer limits. The leaderboard waits for native
completion before starting another request;
player threads never wait directly on HTTP. Responses at the plugins' 20 KiB
completion before starting another request. Personal lookups share this request
slot with the map worker, with a 15-second queue wait limit. Disconnect, game
end and a newer manual replay cancel the waiting announcement; the level
collector still drains any native request already started. Responses at the plugins' 20 KiB
truncation boundary are rejected. The complete JSON grammar, UTF-8, string escapes
and response shape are checked before consuming data. These guards also reject
HTML/error bodies. Leaderboard still uses body validation; the new native HTTP
@@ -640,14 +668,16 @@ status diagnostics are consumed by telemetry.
Run the portable data/structure checks with `node tools/check_leaderboard.mjs`.
They execute the scripts' data helpers with engine-value shims, not a game VM.
Live checks: join while playing and spectating; die/respawn (no repeat); reconnect
(one new announcement); compare Town/TranZit/Grief; check one holder, ties across
pages, no records, and a slow/unavailable/malformed API. Disconnect or end the game
(one new announcement); compare Town/TranZit/Grief; check one holder, multiple tied holders, no records, and a slow/unavailable/malformed API. Check a personal best
below the map record, a tied holder, a new player, and two players with different
bests. Confirm GUID substring/name matches cannot supply someone else’s record,
and unavailable lookups never claim an empty history. Disconnect or end the game
mid-announcement and confirm messages stop. Verify existing HUD, `.help`, `.join`
and telemetry still work. Open `.help` during a record page and check that the
and telemetry still work. Open `.help` during a record announcement and check that the
record resumes afterwards without overlapping it. Runtime linking and client
readiness require Plutonium.
Try `.leaders` and `.LEADERS` after the announcement ends and during a later
page: each should start one private announcement from the first page. Repeat
Try `.leaders` and `.LEADERS` after the announcement ends and while it is
visible: each should restart one complete private announcement. Repeat
while help is open, then disconnect or end the game during a replay to check
cleanup. Disable the leaderboard module and verify `.leaders` is absent from help.