14 KiB
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 upper-right anchors, fixed core and service-window geometry | Keep clear of top-edge overlays and stock scores/ammo without moving the core for services |
| 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 reusable
service window beneath the fixed core. Help uses four commands per page in stable
order, with 12 seconds per page and automatic dismissal after the final page.
.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. The command handlers retain their
existing listeners, and help/records work without the HUD module.
Help reuses two multiline text columns and a muted command-column backdrop. The service has 19 nonarchived elements independent of command/page count; core + AFK use 15 + 1 archived elements. Hidden elements still occupy slots. The T6 player HUD structure 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. Current/maximum HP remains visible at full health;
the former co-op name row is removed and AFK uses a reserved footer. Opening a
service never changes core position or height. HUD 1.2.0, leaderboard 1.1.0
and AFK 1.0.1 require matching common 1.2.0+; deploy the changed scripts
together and restart the map. This introduces no native-plugin/backend dependency
or full server-process restart requirement.
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.
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.
Mode/location combinations follow the
T6 server configurations
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: T6
source scripts load from
storage/t6/scripts/zm. - Entry-point lifecycle:
main()runs early;init()runs after gametype startup. Emptymain()must not callinit()and duplicate initialization. - Plutonium changelog, r2234: documents T6
level waittill("say", message, player). - Stock T6 Zombies:
round state,
end_game, invulnerability, and stock control resets. - Stock zombie utility: map-aware enemy counting.
- Released plugin HTTP implementation:
global
httpPost(url, options)takes an options array withbodyandheaders. Its positional README example does not match this implementation. Completion isdone(response, success, error); success reports transport only. - Plugin JSON implementation:
jsonSerializehandles 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
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 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
can schedule spawnspectator after 0.05 seconds while
_globallogic_spawn::spawnplayer
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 for core/service behavior and
command regressions. Compiler success does not certify runtime linking.
Live checks after deploying:
- Join, late-join, die/respawn, and reconnect: one core per player, fixed upper-right position, spectator placeholders without an early clock start, visible full/damaged HP, health/Juggernog changes, zombies remaining, and timers frozen at game over. Test safe-area settings and different resolutions.
.afkblocks movement, shooting and grenades;.backrestores them. Try rapid toggles, a round transition, death/respawn and game over.- Lock fires at the threshold and clears on game over/restart. HUD must be installed. T5 semantics intentionally clear an existing password at startup.
- 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.
- Repeat on the actual server maps, especially afterlife and special-enemy rounds.
- Type
.help,.HELPand.commandsbefore first spawn, during play and while AFK: four commands per page, only on the requesting player's screen, without moving or resizing the core. Verify 12 seconds per page and dismissal after the final page; repeat on page two to restart page one. Remove optional modules and restart the map to confirm their commands are absent. Restore the modules and confirm their command behavior is unchanged. - Interrupt a record with help and check that its remaining page time resumes.
Repeat
.leadersduring 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.
The stock T6 HUD initialization
sets a nominal font height of 12; the corresponding
font helper
uses int(level.fontheight * fontscale) for its height. The portable HUD checks
use that nominal box to prevent holder-row and AFK-footer overlaps. Exact glyph
extents and multiline spacing still need live validation, especially on T5.