Organize scripts and add TWS plugins with HTTP timeouts
Vendor pinned T5 and T6 plugin sources under the new plugins layout. Add native HTTP deadlines, status and timing diagnostics, telemetry integration, and build/test tooling.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# TWS T5 script notes
|
||||
|
||||
Reference for the `tws_t5_*.gsc` files in this repo. Platform quirks and
|
||||
load-bearing decisions that show up as invariants in the code.
|
||||
|
||||
## Install
|
||||
|
||||
Copy all `tws_t5_*.gsc` to `storage/t5/scripts/sp/` on the Plutonium T5 server
|
||||
(v2 Plutainer: `app/runtime/plutonium/storage/t5/scripts/sp/`).
|
||||
|
||||
- `sudo chown -R 1000:1000 <app>` — Plutainer runs as UID 1000
|
||||
- `docker exec <container> rcon-cli map_restart` — reloads scripts in place
|
||||
|
||||
For existing installations, follow the [upgrade cleanup](README.md#install--upgrade)
|
||||
before copying the renamed scripts.
|
||||
|
||||
## Platform quirks (T5 SP engine, Plutonium)
|
||||
|
||||
- **Initialize locals before loops when reading them afterwards.** T5 rejected
|
||||
leaderboard's `chosen` variable at load time when its only assignment was
|
||||
inside the map-search loop, even though its later use was guarded by the
|
||||
match count. It now starts as `undefined` before that loop in both versions.
|
||||
The JavaScript fixture harness and T6 compiler did not catch this T5 error.
|
||||
- **One `level waittill("connected")` only.** `tws_t5_common` owns it. A
|
||||
second listener breaks the T5 SP connect handshake. Per-player work goes
|
||||
through `tws_t5_common::register_spawn_handler` after `spawned_player`, or
|
||||
`register_connect_handler` for spectator-safe work after the dispatcher yields.
|
||||
Leaderboard uses the latter; its level worker owns all HTTP work.
|
||||
- **Chat uses `level waittill("say", ...)`**, not `callbackPlayerSay`. T5 SP
|
||||
dedicated disables the sound subsystem, cascading through the say-callback
|
||||
dispatch — `callbackPlayerSay` never fires.
|
||||
- **`SetTimerUp(N)` only ticks when `N == 0`** on T5 SP. Non-zero seeds
|
||||
render "0:00" but don't advance. Late joiners see 0, not real elapsed;
|
||||
authoritative elapsed lives in `level.match_start_time`.
|
||||
- **Dynamic text: use `SetValue`, not `SetText`.** `SetText` allocates a
|
||||
config string per call; per-tick rebuilds overflow and take the server
|
||||
down. Composite strings like `"87/160"` are three elements.
|
||||
- **`NewClientHudElem(player)`, not `NewHudElem()`.** `NewHudElem` is
|
||||
globally owned; in co-op every player's HUD draws on top of every other
|
||||
player's. Fall back to `NewHudElem` only if elements don't render at all
|
||||
(diagnostic).
|
||||
- **Zombies namespace is WaW-derived** (`maps\_zombiemode_*`), not BO2's
|
||||
`maps\mp\zombies\_zm_*`.
|
||||
- **Check `t5-gsc-utils` source as well as its README.** Current source
|
||||
includes `http::request` and `jsonSerialize` / `jsonParse`. Telemetry and
|
||||
leaderboard require a DLL built with these HTTP/JSON components; older
|
||||
builds may lack them.
|
||||
See [HTTP source](https://github.com/alicealys/t5-gsc-utils/blob/main/src/component/http.cpp)
|
||||
and [JSON source](https://github.com/alicealys/t5-gsc-utils/blob/main/src/component/json.cpp).
|
||||
|
||||
## Load-bearing decisions
|
||||
|
||||
- **Match / round timers anchor to first spawn / first observed round
|
||||
transition — never level init.** Anchoring at init included the map-load
|
||||
+ connect + intro window, producing "displayed 4:00 → frozen 7:00" drift.
|
||||
Many BO1 maps pre-set `round_number = 1` at init, so the round watcher
|
||||
fires on transitions only and the timer row seeds on first spawn as a
|
||||
fallback.
|
||||
- **Game-over trigger is level-scope, raced across three candidate
|
||||
notifies** (`end_game` / `game_ended` / `intermission`) since BO1 maps
|
||||
are inconsistent. Per-player triggers do not work — `self waittill("death")`
|
||||
is intercepted by the zombiemode scripts before it reaches our scope, and
|
||||
polling `self.health` misses the zero-crossing (health is rewritten during
|
||||
the game-over sequence).
|
||||
## Module map
|
||||
|
||||
| File | Role | Fires notifies | Reads notifies |
|
||||
|---|---|---|---|
|
||||
| `tws_t5_common` | Shared config, HUD helpers, `.help` registry, spawn-handler registry, single connect listener + dispatcher | — | `say` |
|
||||
| `tws_t5_hud` | Timer row, zombie count, health bar | `hud_round_changed`, `hud_match_started`, `hud_game_over` | (internal) |
|
||||
| `tws_t5_afk` | `.afk` / `.back` chat toggle, owns its [AFK] indicator | — | — |
|
||||
| `tws_t5_join` | `.join` for spectators who have not played on this connection | — | `say`, `end_game`, `game_ended`, `intermission` |
|
||||
| `tws_t5_lock` | Lobby `g_password` lock at milestone round (`tws_lock_round`, default 20) | — | `hud_round_changed`, `hud_game_over` |
|
||||
| `tws_t5_telemetry` | Ordered JSON game start, round, 30-second heartbeat, and game end reports with full player snapshots | `telemetry_queued`, `telemetry_finished` (internal) | `end_game`, `game_ended`, `intermission` |
|
||||
| `tws_t5_leaderboard` | Cached completed-match map record and all tied holders, privately on join | — | `end_game`, `game_ended`, `intermission` |
|
||||
Reference in New Issue
Block a user