237 lines
16 KiB
Markdown
237 lines
16 KiB
Markdown
# T6 port notes
|
||
|
||
T6 is ported from T5. Both source trees contain common, HUD, AFK, join, lock,
|
||
telemetry, leaderboard and bank modules; neither includes direct-database modules.
|
||
|
||
## Differences retained for T6 and requested fixes
|
||
|
||
| Area | Difference from T5 | Reason |
|
||
| --- | --- | --- |
|
||
| Paths | `maps/mp/_utility`, `scripts/zm/tws_t6_common` | T6 namespaces and requested filenames |
|
||
| Loading | No T5 `zombiemode` dvar gate; each module has `main()` and `init()` | Zombies-only folder loading; avoid r5346 missing-main warnings |
|
||
| HUD positioning | Fullscreen X/Y anchors, direct normalized `640 × 480` coordinates, unboxed core and service area | Bypass safe-area insets; validate Plutonium tag clearance and font fit at each aspect ratio |
|
||
| HUD rendering | Precached white shader, local max-health fallback, floating-point ratio, `getPlayers()` | T6 rendering/state handling without changing player max health |
|
||
| Enemy count | Stock `_zm_utility::get_current_zombie_count()` plus queued zombies | Uses the map's zombie team and enemy filters |
|
||
| Timers | Seed elapsed time for late joiners; stop round watcher/reset on game over | T6 timer behavior; keep frozen timers frozen |
|
||
| AFK | Maintain control freeze, disable guns/grenades, guard player state and stale grace threads | Requested movement/shooting fix; retain `.afk` / `.back` and two-second grace |
|
||
| Telemetry | Global `httpPost(url, options)`; T5-parity queue + heartbeat + game_start/end + watchdog + log-level dvar; per-player `guid` comes from the persistent `player.guid` field (T5 uses `player getGuid()` directly); per-match `kills`/`headshots`/`downs`/`revives` read from `player.pers[]`, with missing or negative values reported as `0` | Stock T6 connection initialization populates `.guid` before notifying `connected`; stock `initpersstat` / `incpersstat` maintain match counters in `player.pers[]`, whereas T5 uses `player.stats[]`. Payload keys match T5 for downstream shape parity |
|
||
| Join | Port of T5 `tws_t5_join.gsc`; uses `level.spawnplayer` / `level.custom_spawnplayer` (lowercase) and `maps\mp\zombies\_zm::spectator_respawn`; readiness gated on `self.sessionstate == "spectator"` instead of T5's `self.initialized` | T6 stock spectator respawn hook lives in `_zm.gsc`; `self.initialized` is a T5 SP zombiemode marker that T6 stock does not populate the same way |
|
||
|
||
Common provides matching T5/T6 HUD layout constants, helpers and first-spawn dispatcher.
|
||
HUD again owns the `hud_game_over` notification fan-out. Lock again waits on HUD
|
||
notifications, applies T5's random password, and clears it on startup/game over.
|
||
The added password-preservation dvars and independent lock watcher are gone.
|
||
|
||
Common also listens for `.help` through the native `say` notification, independent
|
||
of first-spawn initialization so newcomers can view commands while spectating.
|
||
Each loaded command module registers its command and description with
|
||
`register_help_command()` during `init()`. Lazy registry initialization preserves
|
||
registrations regardless of module initialization order. Common owns one
|
||
unboxed upper-right service area. Help shows all nine installed commands in
|
||
explicit command/description rows; extra registered commands use pages of nine
|
||
rows. Pages last 12 seconds, with automatic dismissal after the final page and
|
||
a counter only for multi-page lists. `.help` / `.commands` restart at page one.
|
||
Help pauses record page time, and a `.leaders` request during help replaces
|
||
the pending replay from page one. Service state prevents old requests from
|
||
closing newer displays. Disconnect and game-end cleanup are independent of
|
||
page timing. Command handlers retain their existing listeners, and help/records
|
||
work without the HUD module.
|
||
|
||
Both engines use explicit help rows; T5 no longer relies on newline rendering,
|
||
and T6 has the same row geometry. Common allocates only the active service
|
||
view: 19 nonarchived elements for nine-command help (20 with a multi-page
|
||
counter), or four for records (five with a multi-page counter). Closing the
|
||
service or switching kinds destroys the view; idle holds no elements. Pages
|
||
reuse the active elements, separately from controller and pending-request state.
|
||
Core + AFK use 10 + 1 archived elements. Hidden elements still occupy slots.
|
||
The [T6 player HUD structure](https://github.com/skiff/t6-gsc-helper/blob/50ff6cb7397c9376894a195f48118d1743812d1d/src/game/structs.hpp#L184)
|
||
has 31 slots in each bucket; it does not establish current Plutonium stock HUD
|
||
usage. Keep the live overlap/element-budget checks alongside the portable checks.
|
||
|
||
The core is created on connection for waiting spectators with placeholders,
|
||
while timer updates retain the existing spawn/round lifecycle. Connection-time
|
||
creation must not seed the match clock. The unboxed layout has timers at the
|
||
upper left, branding at top center and zombies/health at bottom center. HP
|
||
numbers appear to the right of the bar only while injured; AFK sits above the
|
||
zombie count. Services never reposition the core. Records are right aligned,
|
||
with `Map record | Round N` followed by up to three bounded holder lines, no
|
||
footer and no single-page counter. Their 12-second page timing is unchanged.
|
||
|
||
HUD `1.4.2` requires matching common `1.4.0+` and
|
||
[Plutonium r5334+](https://plutonium.pw/docs/changelog/#r5334) for
|
||
`SetTextUnlimited`. The `N ZOMBIES` counter is one element centered at the
|
||
health track's midpoint with uniform scale `1.25`, starting as `-- ZOMBIES`.
|
||
Only changed counts update its text; numeric HP retains `SetValue`. On r5334+,
|
||
update the HUD script and restart the map. Older Plutonium clients and servers
|
||
need updates and full restarts first. AFK `1.2.0` and leaderboard `1.1.0` remain
|
||
compatible; AFK still requires common `1.4.0+`.
|
||
Overlay helpers use direct normalized `640 × 480` coordinates. Dynamic health
|
||
fills use `make_overlay_width()` like their tracks. Apply `int()` after `max()`
|
||
in that helper: native `max()` returns a float, but `SetShader` requires an
|
||
integer width. Legacy panel helpers retain their `0.75` horizontal conversion
|
||
for existing consumers. Font scale is at least `1.0`. There is no new
|
||
native-plugin/backend dependency or full server-process restart requirement
|
||
when already using Plutonium r5334+.
|
||
|
||
HUD owns the exact, case-insensitive `.hud` chat command and registers it in
|
||
help only while installed. Common's core wrappers preserve each element's
|
||
intended alpha behind a per-player visibility mask; health and AFK changes use
|
||
`set_core_alpha()`. Data/timers keep updating while hidden and freeze at game
|
||
over. Help, records, stock HUD and AFK protection are unaffected. Visibility
|
||
defaults on, survives death/respawn during the connection/map, and resets on
|
||
reconnect or map restart. All nine installed commands use one help page,
|
||
ordered `.help`, `.hud`, `.afk`, `.back`, `.join`, `.leaders`, `.b`, `.d`, `.w`.
|
||
Bank commands display the full `<amount|all>` syntax.
|
||
|
||
AFK again listens to the native `say` notification, so it no longer needs plugin
|
||
chat registration. The additional T6 controls are only held while AFK; `.back`
|
||
releases them before the protection grace period. Restoration is deferred during
|
||
death/laststand/intermission until active play. Other mods controlling the same
|
||
invulnerability or weapon flags can still conflict and need live testing.
|
||
|
||
The existing optional T5 dvars remain. Leaderboard adds the three settings
|
||
documented in the [shared README](../../README.md#map-record-announcements).
|
||
`common_config()` and `ensure_config()` are original T5 in-memory HUD helpers,
|
||
not an external configuration system.
|
||
|
||
## Leaderboard join announcements
|
||
|
||
The module is `tws_t6_leaderboard.gsc` in T6 and `tws_t5_leaderboard.gsc` in T5.
|
||
Common's existing
|
||
connection listener now also dispatches optional connection handlers after a
|
||
one-frame yield. Leaderboard waits for player readiness and uses a level-owned
|
||
HTTP cache, independent of the first-spawn handlers. T6 spectators keep
|
||
`hasSpawned` false, so T6 readiness uses session state and the intro-screen flag;
|
||
T5 sets `hasSpawned` for both playable and spectator spawns.
|
||
|
||
T6's active `scr_zm_ui_gametype` / `scr_zm_map_start_location` fields come from
|
||
[stock `_zm.gsc`](https://github.com/plutoniummod/t6-scripts/blob/2d8440321602f22f63f5335817110d60ddf223d5/ZM/Core/maps/mp/zombies/_zm.gsc).
|
||
Mode/location combinations follow the
|
||
[T6 server configurations](https://github.com/xerxes-at/T6ServerConfigs/tree/master/localappdata/Plutonium/storage/t6/gamesettings)
|
||
and Electric Cherry's map catalogue. Unknown selections require an explicit API
|
||
key instead of falling back to another variant sharing the engine map.
|
||
|
||
Historical validation for the initial leaderboard change: 135 fixture/static
|
||
checks passed using the actual data-handling functions from both scripts with
|
||
JavaScript engine-value shims. All seven then-current T6 scripts compiled and
|
||
assembled using a local Intel macOS driver built
|
||
from gsc-tool 1.5.1 sources. PowerShell was unavailable, so `check.ps1` itself was
|
||
not executed here. T5 compilation and live plugin/gameplay checks were not run;
|
||
gsc-tool has no T5 backend. The production API could not be reached from this
|
||
environment. See the shared README for the live validation cases.
|
||
|
||
## Verified primary sources
|
||
|
||
- [Plutonium loading guide](https://plutonium.pw/docs/modding/loading-mods/): T6
|
||
source scripts load from `storage/t6/scripts/zm`.
|
||
- [Entry-point lifecycle](https://plutonium.pw/docs/modding/gsc/new-scripting-features/):
|
||
`main()` runs early; `init()` runs after gametype startup. Empty `main()` must
|
||
not call `init()` and duplicate initialization.
|
||
- [Plutonium changelog, r2234](https://plutonium.pw/docs/changelog/): documents T6
|
||
`level waittill("say", message, player)`.
|
||
- [Stock T6 Zombies](https://github.com/plutoniummod/t6-scripts/blob/2d8440321602f22f63f5335817110d60ddf223d5/ZM/Core/maps/mp/zombies/_zm.gsc):
|
||
round state, `end_game`, invulnerability, and stock control resets.
|
||
- [Stock zombie utility](https://github.com/plutoniummod/t6-scripts/blob/2d8440321602f22f63f5335817110d60ddf223d5/ZM/Core/maps/mp/zombies/_zm_utility.gsc):
|
||
map-aware enemy counting.
|
||
- [Released plugin HTTP implementation](https://github.com/alicealys/t6-gsc-utils/blob/v3.1.1/src/component/http.cpp):
|
||
global `httpPost(url, options)` takes an options array with `body` and `headers`.
|
||
Its positional README example does not match this implementation.
|
||
Completion is `done(response, success, error)`; success reports transport only.
|
||
- [Plugin JSON implementation](https://github.com/alicealys/t6-gsc-utils/blob/v3.1.1/src/component/json.cpp):
|
||
`jsonSerialize` handles the event payload.
|
||
|
||
Do not create a dummy `http.gsc`. An unresolved `httpPost`/`jsonSerialize` means
|
||
the installed server/plugin must be checked. Installing a DLL requires a full
|
||
server-process restart, not just a map restart.
|
||
|
||
## Telemetry reboot investigation
|
||
|
||
The T5 and T6 implementations are not runtime-verified equivalents. In particular,
|
||
[T6 plugin v3.0.4](https://github.com/alicealys/t6-gsc-utils/blob/v3.0.4/src/component/http.cpp)
|
||
expects `httpPost(url, body, headers)` and notifies only the response body;
|
||
v3.1.1 expects `httpPost(url, options)` and also provides success/error values.
|
||
The current script targets the [TWS build](../plugins/README.md) based on v3.1.1,
|
||
which appends diagnostics and enforces native HTTP deadlines. Switching the function name does not establish
|
||
compatibility with an unknown installed DLL.
|
||
|
||
Console markers identify `main`, `init`, round serialization, HTTP invocation,
|
||
handle return and completion. They do not log the URL or response body. If startup
|
||
fails before `main`, inspect the first linker/plugin error, not the last supervisor
|
||
restart message. If no occupied positive round was observed, this script has not
|
||
called JSON serialization or HTTP yet.
|
||
|
||
Earlier live validation: the operator confirmed successful server startup and
|
||
Fleet delivery with the original direct reporter. The earlier reboot cause was
|
||
not established; logging alone should not be treated as a proven fix.
|
||
|
||
To recover the server while investigating, move `tws_t6_telemetry.gsc` outside the
|
||
autoload directory. The enable dvar cannot bypass unresolved native functions
|
||
at link time. The other four TWS modules can run without telemetry.
|
||
|
||
## Checks
|
||
|
||
### Newcomer eligibility
|
||
|
||
The stock [`_zm_gametype::onspawnplayer`](https://github.com/plutoniummod/t6-scripts/blob/2d8440321602f22f63f5335817110d60ddf223d5/ZM/Core/maps/mp/gametypes_zm/_zm_gametype.gsc)
|
||
can schedule `spawnspectator` after 0.05 seconds while
|
||
[`_globallogic_spawn::spawnplayer`](https://github.com/plutoniummod/t6-scripts/blob/2d8440321602f22f63f5335817110d60ddf223d5/ZM/Core/maps/mp/gametypes_zm/_globallogic_spawn.gsc)
|
||
emits `spawned_player` at frame end. That event alone does not prove gameplay.
|
||
Join `1.0.1` waits 0.1 seconds before checking session state and keeps listening
|
||
after setup spectator spawns. `killed_player` also consumes eligibility so a
|
||
death during that interval cannot restore newcomer access. The common dispatcher
|
||
still starts each registered module once per connection.
|
||
|
||
Run `node tools/check_join.mjs` for portable lifecycle and request fixtures.
|
||
These execute the join script with engine shims, not a GSC VM. Live validation:
|
||
join Farm Survival during round 3 and remain spectating, use `.join` once, then
|
||
try repeated requests, death, and subsequent rounds. On a fresh connection,
|
||
wait for a normal round-start spawn, die, and verify `.join` is rejected.
|
||
Also check a round-1 participant, reconnecting, disconnect during setup, and
|
||
game over. Repeat on another T6 map; compile with the checker below first.
|
||
|
||
Local: `tools/check.ps1` compiles all eight files for T6 PC and checks shared
|
||
references and entry points. It requires PowerShell and gsc-tool. Run the
|
||
[shared HUD checks](../../README.md#hud-validation) for core/service behavior and
|
||
command regressions. Compiler success does not certify runtime linking.
|
||
|
||
Live checks after deploying:
|
||
|
||
1. Join, late-join, die/respawn, and reconnect: one unboxed core per player,
|
||
upper-left timers, top-center branding, bottom-center zombies/health and
|
||
spectator placeholders without an early clock start. Check damage-only HP,
|
||
health/Juggernog changes, AFK placement and timers frozen at game over.
|
||
Test safe-area settings and different resolutions against stock HUD elements.
|
||
Check `0`, `6`, `9`, `10`, `99` and `100 ZOMBIES` remain centered above the
|
||
health track, including after `.hud` toggles and game over freezes the count.
|
||
2. `.afk` blocks movement, shooting and grenades; `.back` restores them. Try rapid
|
||
toggles, a round transition, death/respawn and game over.
|
||
3. Lock fires at the threshold and clears on game over/restart. HUD must be installed.
|
||
T5 semantics intentionally clear an existing password at startup.
|
||
4. Telemetry sends the initial occupied round and each new round to the existing
|
||
endpoint. Check server ID/player count, same-round joins and an unreachable API.
|
||
5. Repeat on the actual server maps, especially afterlife and special-enemy rounds.
|
||
6. Type `.help`, `.HELP` and `.commands` before first spawn, during play and
|
||
while AFK: one page of nine commands with all modules installed, full bank
|
||
syntax and no page counter, only on the requesting player's screen. Verify
|
||
dismissal after 12 seconds and repeat-to-restart behavior. Add custom
|
||
registered commands to exercise the nine-row page limit and page counter.
|
||
Remove optional modules and restart the map to confirm their commands are
|
||
absent. Restore them and confirm command behavior is unchanged.
|
||
7. Interrupt a record with help and check that its remaining page time resumes.
|
||
Repeat `.leaders` during help; only the latest replay should start from page
|
||
one after help closes. Check long names across pages, no records and
|
||
unavailable records. Reopen after expiry, disconnect/reconnect and end the
|
||
game during a service; verify no duplicates or leftovers. Repeat without HUD.
|
||
8. Toggle `.hud` before spawning, while playing/AFK and after game over. Verify
|
||
the core and AFK indicator hide privately while help/records remain visible.
|
||
Show it after taking damage or changing AFK state while hidden: current
|
||
values and intended alpha should return. Confirm updates continue hidden,
|
||
death/respawn keeps the choice, and reconnect/map restart restores visibility.
|
||
|
||
The stock T6 [HUD initialization](https://raw.githubusercontent.com/plutoniummod/t6-scripts/main/ZM/Core/maps/mp/gametypes_zm/_hud.gsc)
|
||
sets a nominal font height of 12; the corresponding
|
||
[font helper](https://raw.githubusercontent.com/plutoniummod/t6-scripts/main/ZM/Core/maps/mp/gametypes_zm/_hud_util.gsc)
|
||
uses `int(level.fontheight * fontscale)` for its height. The portable HUD checks
|
||
use that nominal box to prevent holder-row, help-row and AFK overlaps. Exact
|
||
glyph extents still need live validation, especially on T5.
|