Fix bank GUID serialization on T5 and T6 (Refs #15)

This commit is contained in:
2026-10-12 23:45:44 -04:00
parent 3bb0b5178e
commit ab989395f7
10 changed files with 347 additions and 21 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ telemetry and leaderboard modules; neither includes bank or database modules.
| 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` sources from Plutonium's `player.guid` engine property (T5 uses `player getGuid()` method); per-match `kills`/`headshots`/`downs`/`revives` read from `player.pers[]`, with missing or negative values reported as `0` | T6 has no `getGuid` method but exposes the persistent identity as `.guid` on the player entity; stock `initpersstat` / `incpersstat` maintain match counters in `player.pers[]`, whereas T5 uses `player.stats[]`. Payload keys match T5 for downstream shape parity |
| 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 retains the T5 HUD constants, helpers and first-spawn dispatcher.
+12 -4
View File
@@ -48,13 +48,21 @@ The optional `tws_t6_bank.gsc` adds `.b`, `.d <amount|all>` and
`.w <amount|all>` and registers them in help. It requires common and telemetry
`1.0.0` or newer, the TWS t6 plugin `1.1.0`, Electric Cherry's bank API and
a private per-server credential. Follow [bank setup and recovery](../../README.md#player-bank-t5-and-t6),
including a full process restart for the plugin. Bank `2.0.0` uses only
including a full process restart for the plugin. Bank `2.0.0+` uses only
`https://ec.thewrightserver.net/api/bank` and ignores `tws_bank_url`.
Update EC agents to `1.9.1+` first. If the old endpoint differs, follow the
[endpoint upgrade procedure](../../README.md#upgrading-the-bank-endpoint):
an EC rebuild must settle legacy journals before the new scripts start.
When the endpoint already matches, only a map restart is required.
Bank `2.0.1` reads the persistent `player.guid` field used by telemetry and
converts it to a string before requests or journal writes. Existing strings
are preserved exactly; missing or invalid identities fail privately without
changing points. Stock T6
[`callback_playerconnect()`](https://github.com/plutoniummod/t6-scripts/blob/2d8440321602f22f63f5335817110d60ddf223d5/ZM/Core/maps/mp/gametypes_zm/_globallogic_player.gsc)
populates that field before the `connected` notification. Follow the shared
[identity and deployment checks](../../README.md#bank-identity-validation).
## Persistent Discord text
The HUD shows `https://discord.thewrightserver.net` in small light-gray text
@@ -156,9 +164,9 @@ It sends four event types over the life of a match, mirroring the T5 script:
Each event payload includes `event`, `server`, `map`, `match`, `seq`, `round` (except `game_start`)
and a `players` array with `name`, `guid`, `kills`, `headshots`, `downs`, `revives`
and `score` plus `score_total` per player in stat reports. `game_start` includes
only player identity. `guid` reads Plutonium's `player.guid` engine property
(T5 uses the `player getGuid()` method — T6 has no such method, but the field is
equivalent for identity purposes). `kills`/`headshots`/`downs`/`revives` read
only player identity. `guid` reads the persistent `player.guid` field populated
by T6's stock connection initialization (T5 reads `player getGuid()` directly).
`kills`/`headshots`/`downs`/`revives` read
from T6's stock match counters in `player.pers[]`; missing or negative values
are reported as `0`. `score` is the player's current spendable `player.score`.
`score_total` reads `player.score_total`, the stock cumulative match score used
+32 -1
View File
@@ -119,12 +119,43 @@ bank_request(player, args)
level.bank_busy = false;
}
bank_guid(player)
{
if (!isDefined(player))
return undefined;
// Use the persistent field populated at connection, as telemetry does.
guid = player.guid;
if (!isDefined(guid) || (typeof(guid) != "string" && typeof(guid) != "int"))
return undefined;
// Preserve string identities without numeric casts, including large GUIDs.
guid = "" + guid;
if (guid.size == 0 || guid.size > 64)
return undefined;
allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.:-";
for (i = 0; i < guid.size; i++)
{
found = false;
for (j = 0; j < allowed.size; j++)
if (guid[i] == allowed[j])
found = true;
if (!found)
return undefined;
}
return guid;
}
bank_transfer(entry, args)
{
player = entry.player;
guid = bank_guid(player);
if (!isDefined(guid))
{
bank_say(entry, "^3Bank player identity unavailable. Try again shortly; points unchanged.");
return;
}
data = [];
data["server"] = level.bank_server;
data["guid"] = player getGuid();
data["guid"] = guid;
if (args[0] == ".b")
{
if (args.size != 1)