Remove T5 bank and database modules and standardize script names
This commit is contained in:
@@ -5,7 +5,7 @@ Combined working repo for the TWS Plutonium Zombies GSC scripts across two games
|
|||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- [t5/](t5/) — Plutonium **T5** (Call of Duty: Black Ops 1) Zombies scripts. Most-developed baseline. See [t5/README.md](t5/README.md) and [t5/NOTES.md](t5/NOTES.md).
|
- [t5/](t5/) — Plutonium **T5** (Call of Duty: Black Ops 1) Zombies scripts. Most-developed baseline. See [t5/README.md](t5/README.md) and [t5/NOTES.md](t5/NOTES.md).
|
||||||
- [t6/](t6/) — Plutonium **T6** (Call of Duty: Black Ops 2) Zombies scripts. Ported from T5; at parity on common, HUD, AFK, lock, telemetry, join and leaderboard. Only `db` and `bank` remain T5-only. See [t6/README.md](t6/README.md), [t6/NOTES.md](t6/NOTES.md), and [t6/tools/check.ps1](t6/tools/check.ps1).
|
- [t6/](t6/) — Plutonium **T6** (Call of Duty: Black Ops 2) Zombies scripts. Ported from T5; at parity on common, HUD, AFK, lock, telemetry, join and leaderboard. See [t6/README.md](t6/README.md), [t6/NOTES.md](t6/NOTES.md), and [t6/tools/check.ps1](t6/tools/check.ps1).
|
||||||
|
|
||||||
## Parity
|
## Parity
|
||||||
|
|
||||||
@@ -15,21 +15,17 @@ Modules currently in each tree:
|
|||||||
|
|
||||||
| Module | T5 | T6 |
|
| Module | T5 | T6 |
|
||||||
|------------|-------------------------------|---------------------------------|
|
|------------|-------------------------------|---------------------------------|
|
||||||
| common | `t5/tws_common.gsc` | `t6/tws_t6_common.gsc` |
|
| common | `t5/tws_t5_common.gsc` | `t6/tws_t6_common.gsc` |
|
||||||
| hud | `t5/tws_hud.gsc` | `t6/tws_t6_hud.gsc` |
|
| hud | `t5/tws_t5_hud.gsc` | `t6/tws_t6_hud.gsc` |
|
||||||
| afk | `t5/tws_afk.gsc` | `t6/tws_t6_afk.gsc` |
|
| afk | `t5/tws_t5_afk.gsc` | `t6/tws_t6_afk.gsc` |
|
||||||
| lock | `t5/tws_lock.gsc` | `t6/tws_t6_lock.gsc` |
|
| lock | `t5/tws_t5_lock.gsc` | `t6/tws_t6_lock.gsc` |
|
||||||
| telemetry | `t5/tws_telemetry.gsc` | `t6/tws_t6_telemetry.gsc` — queued `game_start` / `heartbeat` / `round_change` / `game_end` matching T5 |
|
| telemetry | `t5/tws_t5_telemetry.gsc` | `t6/tws_t6_telemetry.gsc` — queued `game_start` / `heartbeat` / `round_change` / `game_end` matching T5 |
|
||||||
| join | `t5/tws_join.gsc` | `t6/tws_t6_join.gsc` |
|
| join | `t5/tws_t5_join.gsc` | `t6/tws_t6_join.gsc` |
|
||||||
| leaderboard | `t5/tws_leaderboard.gsc` | `t6/tws_t6_leaderboard.gsc` |
|
| leaderboard | `t5/tws_t5_leaderboard.gsc` | `t6/tws_t6_leaderboard.gsc` |
|
||||||
| db | `t5/tws_db.gsc` | *(not ported)* |
|
|
||||||
| bank | `t5/tws_bank.gsc` | *(not ported)* |
|
|
||||||
|
|
||||||
`db` and `bank` are T5-only for now.
|
|
||||||
|
|
||||||
## Map record announcements
|
## Map record announcements
|
||||||
|
|
||||||
Install `tws_leaderboard.gsc` for T5 or `tws_t6_leaderboard.gsc` for T6,
|
Install `tws_t5_leaderboard.gsc` for T5 or `tws_t6_leaderboard.gsc` for T6,
|
||||||
**along with the updated common module** for that game.
|
**along with the updated common module** for that game.
|
||||||
The new module privately announces the current map's fleet-wide highest recorded
|
The new module privately announces the current map's fleet-wide highest recorded
|
||||||
round and every tied holder once per connection, including spectator newcomers.
|
round and every tied holder once per connection, including spectator newcomers.
|
||||||
|
|||||||
+18
-36
@@ -1,16 +1,19 @@
|
|||||||
# tws-t5-aio notes
|
# TWS T5 script notes
|
||||||
|
|
||||||
Reference for the `tws_*.gsc` files in this repo. Platform quirks and
|
Reference for the `tws_t5_*.gsc` files in this repo. Platform quirks and
|
||||||
load-bearing decisions that show up as invariants in the code.
|
load-bearing decisions that show up as invariants in the code.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
Copy all `tws_*.gsc` to `storage/t5/scripts/sp/` on the Plutonium T5 server
|
Copy all `tws_t5_*.gsc` to `storage/t5/scripts/sp/` on the Plutonium T5 server
|
||||||
(v2 Plutainer: `app/runtime/plutonium/storage/t5/scripts/sp/`).
|
(v2 Plutainer: `app/runtime/plutonium/storage/t5/scripts/sp/`).
|
||||||
|
|
||||||
- `sudo chown -R 1000:1000 <app>` — Plutainer runs as UID 1000
|
- `sudo chown -R 1000:1000 <app>` — Plutainer runs as UID 1000
|
||||||
- `docker exec <container> rcon-cli map_restart` — reloads scripts in place
|
- `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)
|
## Platform quirks (T5 SP engine, Plutonium)
|
||||||
|
|
||||||
- **Initialize locals before loops when reading them afterwards.** T5 rejected
|
- **Initialize locals before loops when reading them afterwards.** T5 rejected
|
||||||
@@ -18,9 +21,9 @@ Copy all `tws_*.gsc` to `storage/t5/scripts/sp/` on the Plutonium T5 server
|
|||||||
inside the map-search loop, even though its later use was guarded by the
|
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.
|
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.
|
The JavaScript fixture harness and T6 compiler did not catch this T5 error.
|
||||||
- **One `level waittill("connected")` only.** `tws_common` owns it. A
|
- **One `level waittill("connected")` only.** `tws_t5_common` owns it. A
|
||||||
second listener breaks the T5 SP connect handshake. Per-player work goes
|
second listener breaks the T5 SP connect handshake. Per-player work goes
|
||||||
through `tws_common::register_spawn_handler` after `spawned_player`, or
|
through `tws_t5_common::register_spawn_handler` after `spawned_player`, or
|
||||||
`register_connect_handler` for spectator-safe work after the dispatcher yields.
|
`register_connect_handler` for spectator-safe work after the dispatcher yields.
|
||||||
Leaderboard uses the latter; its level worker owns all HTTP work.
|
Leaderboard uses the latter; its level worker owns all HTTP work.
|
||||||
- **Chat uses `level waittill("say", ...)`**, not `callbackPlayerSay`. T5 SP
|
- **Chat uses `level waittill("say", ...)`**, not `callbackPlayerSay`. T5 SP
|
||||||
@@ -39,9 +42,9 @@ Copy all `tws_*.gsc` to `storage/t5/scripts/sp/` on the Plutonium T5 server
|
|||||||
- **Zombies namespace is WaW-derived** (`maps\_zombiemode_*`), not BO2's
|
- **Zombies namespace is WaW-derived** (`maps\_zombiemode_*`), not BO2's
|
||||||
`maps\mp\zombies\_zm_*`.
|
`maps\mp\zombies\_zm_*`.
|
||||||
- **Check `t5-gsc-utils` source as well as its README.** Current source
|
- **Check `t5-gsc-utils` source as well as its README.** Current source
|
||||||
includes `http::request` and `jsonSerialize` / `jsonParse`, in addition
|
includes `http::request` and `jsonSerialize` / `jsonParse`. Telemetry and
|
||||||
to file IO, console commands and MySQL. Telemetry requires a DLL built
|
leaderboard require a DLL built with these HTTP/JSON components; older
|
||||||
with these HTTP/JSON components; older builds may lack them.
|
builds may lack them.
|
||||||
See [HTTP source](https://github.com/alicealys/t5-gsc-utils/blob/main/src/component/http.cpp)
|
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).
|
and [JSON source](https://github.com/alicealys/t5-gsc-utils/blob/main/src/component/json.cpp).
|
||||||
|
|
||||||
@@ -59,35 +62,14 @@ Copy all `tws_*.gsc` to `storage/t5/scripts/sp/` on the Plutonium T5 server
|
|||||||
is intercepted by the zombiemode scripts before it reaches our scope, and
|
is intercepted by the zombiemode scripts before it reaches our scope, and
|
||||||
polling `self.health` misses the zero-crossing (health is rewritten during
|
polling `self.health` misses the zero-crossing (health is rewritten during
|
||||||
the game-over sequence).
|
the game-over sequence).
|
||||||
- **Bank writes DB-first, memory-second.** Every mutation writes to the DB
|
|
||||||
and only updates `self.bank` / `self.score` after the write confirms. A
|
|
||||||
dead DB can never create phantom money. Deposits use `INSERT ... ON
|
|
||||||
DUPLICATE KEY UPDATE`; withdrawals gate on `WHERE balance >= ?` so the DB
|
|
||||||
itself blocks overdrafts under concurrent commands.
|
|
||||||
- **Bank command surface is `command::add_sv` (server console), not chat.**
|
|
||||||
SP-engine chat is unreliable and `chat::register_command` isn't available
|
|
||||||
in `t5-gsc-utils`.
|
|
||||||
|
|
||||||
## Current state / caveats
|
|
||||||
|
|
||||||
- `bank_load` in `tws_bank.gsc` is a **diagnostic stub**: bare minimum to
|
|
||||||
isolate what specifically kills the connect handshake. Do not restore the
|
|
||||||
stripped `getGuid` / MySQL body until the stub passes join cleanly.
|
|
||||||
- DB credentials in `tws_db.gsc` are hardcoded for the initial fleet test.
|
|
||||||
Move to dvars (`tws_db_host` / `tws_db_user` / `tws_db_password` /
|
|
||||||
`tws_db_name`) before this repo goes public — otherwise the fleet's DB
|
|
||||||
password lives in source.
|
|
||||||
|
|
||||||
## Module map
|
## Module map
|
||||||
|
|
||||||
| File | Role | Fires notifies | Reads notifies |
|
| File | Role | Fires notifies | Reads notifies |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `tws_common` | Shared config, HUD helpers, `.help` registry, spawn-handler registry, single connect listener + dispatcher | — | `say` |
|
| `tws_t5_common` | Shared config, HUD helpers, `.help` registry, spawn-handler registry, single connect listener + dispatcher | — | `say` |
|
||||||
| `tws_db` | MariaDB pool config + reachability probe | `db_probe_done` | — |
|
| `tws_t5_hud` | Timer row, zombie count, health bar | `hud_round_changed`, `hud_match_started`, `hud_game_over` | (internal) |
|
||||||
| `tws_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_bank` | Persistent bank + `bank` / `deposit` / `withdraw` commands | — | `db_probe_done` |
|
| `tws_t5_join` | `.join` for spectators who have not played on this connection | — | `say`, `end_game`, `game_ended`, `intermission` |
|
||||||
| `tws_afk` | `.afk` / `.back` chat toggle, owns its [AFK] indicator | — | — |
|
| `tws_t5_lock` | Lobby `g_password` lock at milestone round (`tws_lock_round`, default 20) | — | `hud_round_changed`, `hud_game_over` |
|
||||||
| `tws_join` | `.join` for spectators who have not played on this connection | — | `say`, `end_game`, `game_ended`, `intermission` |
|
| `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_lock` | Lobby `g_password` lock at milestone round (`tws_lock_round`, default 20) | — | `hud_round_changed`, `hud_game_over` |
|
| `tws_t5_leaderboard` | Cached completed-match map record and all tied holders, privately on join | — | `end_game`, `game_ended`, `intermission` |
|
||||||
| `tws_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_leaderboard` | Cached completed-match map record and all tied holders, privately on join | — | `end_game`, `game_ended`, `intermission` |
|
|
||||||
|
|||||||
+70
-134
@@ -1,9 +1,8 @@
|
|||||||
# tws-t5-aio
|
# TWS T5 Zombies scripts
|
||||||
|
|
||||||
Custom HUD + persistent bank + AFK toggle + immediate join + lobby lock + game telemetry + map records for Plutonium T5
|
Custom HUD + AFK toggle + immediate join + lobby lock + game telemetry + map records for Plutonium T5
|
||||||
(Black Ops 1) zombies dedicated servers. Split across nine `.gsc` files,
|
(Black Ops 1) zombies dedicated servers. Split across seven `.gsc` files,
|
||||||
each installable / removable in isolation (with `tws_common` as the shared
|
with `tws_t5_common` as the shared hub. Lobby lock also requires the HUD module.
|
||||||
hub).
|
|
||||||
|
|
||||||
Platform quirks and deploy commands: [NOTES.md](NOTES.md).
|
Platform quirks and deploy commands: [NOTES.md](NOTES.md).
|
||||||
|
|
||||||
@@ -11,19 +10,30 @@ Platform quirks and deploy commands: [NOTES.md](NOTES.md).
|
|||||||
|
|
||||||
| File | Role |
|
| File | Role |
|
||||||
|---|---|
|
|---|---|
|
||||||
| [tws_common.gsc](tws_common.gsc) | Shared config, HUD helpers, `.help`, connect/spawn registries, single `connected` listener + dispatcher |
|
| [tws_t5_common.gsc](tws_t5_common.gsc) | Shared config, HUD helpers, `.help`, connect/spawn registries, single `connected` listener + dispatcher |
|
||||||
| [tws_db.gsc](tws_db.gsc) | MariaDB pool config + reachability probe |
|
| [tws_t5_hud.gsc](tws_t5_hud.gsc) | Bottom-left HUD stack: timers, zombie count, health bar |
|
||||||
| [tws_hud.gsc](tws_hud.gsc) | Bottom-left HUD stack: timers, zombie count, health bar |
|
| [tws_t5_afk.gsc](tws_t5_afk.gsc) | `.afk` / `.back` chat toggle + `[AFK]` indicator |
|
||||||
| [tws_bank.gsc](tws_bank.gsc) | Persistent per-player bank + console commands |
|
| [tws_t5_join.gsc](tws_t5_join.gsc) | `.join` lets newcomers spawn before the current round ends |
|
||||||
| [tws_afk.gsc](tws_afk.gsc) | `.afk` / `.back` chat toggle + `[AFK]` indicator |
|
| [tws_t5_lock.gsc](tws_t5_lock.gsc) | Lobby `g_password` lock at a milestone round |
|
||||||
| [tws_join.gsc](tws_join.gsc) | `.join` lets newcomers spawn before the current round ends |
|
| [tws_t5_telemetry.gsc](tws_t5_telemetry.gsc) | Direct HTTP game start, round, heartbeat, and game end reports |
|
||||||
| [tws_lock.gsc](tws_lock.gsc) | Lobby `g_password` lock at a milestone round |
|
| [tws_t5_leaderboard.gsc](tws_t5_leaderboard.gsc) | Private map high-round record and all tied holders on connection |
|
||||||
| [tws_telemetry.gsc](tws_telemetry.gsc) | Direct HTTP game start, round, heartbeat, and game end reports |
|
|
||||||
| [tws_leaderboard.gsc](tws_leaderboard.gsc) | Private map high-round record and all tied holders on connection |
|
## Install / upgrade
|
||||||
|
|
||||||
|
Copy `tws_t5_*.gsc` to `storage/t5/scripts/sp/`, then restart the map.
|
||||||
|
When upgrading an existing installation, first remove these old scripts from
|
||||||
|
that directory:
|
||||||
|
|
||||||
|
- `tws_bank.gsc` and `tws_db.gsc` (removed modules)
|
||||||
|
- `tws_common.gsc`, `tws_hud.gsc`, `tws_afk.gsc`, `tws_join.gsc`,
|
||||||
|
`tws_lock.gsc`, `tws_telemetry.gsc` and `tws_leaderboard.gsc` (renamed modules)
|
||||||
|
|
||||||
|
Do not leave both common scripts installed: duplicate connection listeners
|
||||||
|
break T5's connect handshake. Existing dvar names are unchanged.
|
||||||
|
|
||||||
## Map record announcements
|
## Map record announcements
|
||||||
|
|
||||||
Copy `tws_leaderboard.gsc` and the updated `tws_common.gsc` to
|
Copy `tws_t5_leaderboard.gsc` and the updated `tws_t5_common.gsc` to
|
||||||
`storage/t5/scripts/sp/`, then restart the map. Leaderboard requires a
|
`storage/t5/scripts/sp/`, then restart the map. Leaderboard requires a
|
||||||
[t5-gsc-utils](https://github.com/alicealys/t5-gsc-utils) build exposing
|
[t5-gsc-utils](https://github.com/alicealys/t5-gsc-utils) build exposing
|
||||||
`http::request`, `jsonParse`, `typeof` and `formatString`. A plugin upgrade
|
`http::request`, `jsonParse`, `typeof` and `formatString`. A plugin upgrade
|
||||||
@@ -31,7 +41,7 @@ requires a full server-process restart. To omit leaderboard, remove its script;
|
|||||||
the enable dvar does not bypass native linking dependencies.
|
the enable dvar does not bypass native linking dependencies.
|
||||||
|
|
||||||
Records are read from the public Electric Cherry API with no credentials and
|
Records are read from the public Electric Cherry API with no credentials and
|
||||||
work independently of telemetry, HUD and the bank. Spectator newcomers receive
|
work independently of telemetry and HUD. Spectator newcomers receive
|
||||||
the same private announcement as playable joins. T5 matches its engine map to
|
the same private announcement as playable joins. T5 matches its engine map to
|
||||||
the API's map list. [Shared configuration, caching and validation](../README.md#map-record-announcements)
|
the API's map list. [Shared configuration, caching and validation](../README.md#map-record-announcements)
|
||||||
apply to both games.
|
apply to both games.
|
||||||
@@ -52,62 +62,55 @@ counter and health display. Typing `.help` again restarts that display time.
|
|||||||
| `.join` | Join mid-round (newcomers only) |
|
| `.join` | Join mid-round (newcomers only) |
|
||||||
|
|
||||||
Each module registers its own help entries; removing AFK or join also removes
|
Each module registers its own help entries; removing AFK or join also removes
|
||||||
those entries from `.help` after a map restart. The bank's `bank`, `deposit`, and
|
those entries from `.help` after a map restart.
|
||||||
`withdraw` commands are server-console commands and are not listed in chat help.
|
|
||||||
|
|
||||||
## Dependency graph
|
## Dependency graph
|
||||||
|
|
||||||
Arrows read "depends on" — solid means the source names the target with
|
Arrows read "depends on" — solid means the source names the target with
|
||||||
`scripts\sp\tws_common::...`, dashed means the source waits on a level
|
`scripts\sp\tws_t5_common::...`, dashed means the source waits on a level
|
||||||
notify fired by the target. Transitive edges are elided (so `tws_bank`
|
notify fired by the target.
|
||||||
and `tws_lock` reach `tws_common` through `tws_db` / `tws_hud` on the
|
|
||||||
graph, but they also call `tws_common` directly).
|
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph BT
|
graph BT
|
||||||
common[tws_common<br/><i>config + helpers + dispatcher</i>]
|
common[tws_t5_common<br/><i>config + helpers + dispatcher</i>]
|
||||||
|
|
||||||
db[tws_db]
|
hud[tws_t5_hud]
|
||||||
hud[tws_hud]
|
afk[tws_t5_afk]
|
||||||
afk[tws_afk]
|
join[tws_t5_join]
|
||||||
join[tws_join]
|
lock[tws_t5_lock]
|
||||||
bank[tws_bank]
|
telemetry[tws_t5_telemetry]
|
||||||
lock[tws_lock]
|
leaderboard[tws_t5_leaderboard]
|
||||||
telemetry[tws_telemetry]
|
|
||||||
leaderboard[tws_leaderboard]
|
|
||||||
|
|
||||||
db --> common
|
|
||||||
hud --> common
|
hud --> common
|
||||||
afk --> common
|
afk --> common
|
||||||
join --> common
|
join --> common
|
||||||
|
lock --> common
|
||||||
telemetry --> common
|
telemetry --> common
|
||||||
leaderboard --> common
|
leaderboard --> common
|
||||||
|
|
||||||
bank -. db_probe_done .-> db
|
|
||||||
lock -. hud_round_changed<br/>hud_game_over .-> hud
|
lock -. hud_round_changed<br/>hud_game_over .-> hud
|
||||||
```
|
```
|
||||||
|
|
||||||
- `tws_common` is the only module named by other files at compile time.
|
- `tws_t5_common` is the only module named by other files at compile time.
|
||||||
- All other cross-module coupling flows through level notifies
|
- All other cross-module coupling flows through level notifies
|
||||||
(`db_probe_done`, `hud_round_changed`, `hud_match_started`,
|
(`hud_round_changed`, `hud_match_started`,
|
||||||
`hud_game_over`) or through spawn handlers registered with
|
`hud_game_over`) or through spawn handlers registered with
|
||||||
`tws_common::register_spawn_handler` / `register_connect_handler`.
|
`tws_t5_common::register_spawn_handler` / `register_connect_handler`.
|
||||||
- Any file except `tws_common` can be removed; the rest still load.
|
- Any file except `tws_t5_common` can be removed; the rest still load.
|
||||||
`tws_afk` has no downstream consumers — pull it independently.
|
`tws_t5_afk` has no downstream consumers — pull it independently.
|
||||||
`tws_bank` needs `tws_db`; `tws_lock` needs `tws_hud`.
|
`tws_t5_lock` needs `tws_t5_hud` to receive round and game-over notifications.
|
||||||
|
|
||||||
## Runtime notifies
|
## Runtime notifies
|
||||||
|
|
||||||
| Notify | Fired by | Read by |
|
| Notify | Fired by | Read by |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `db_probe_done` | `tws_db` | `tws_bank` (via `bank_deferred_start`) |
|
| `hud_round_changed` | `tws_t5_hud` | `tws_t5_hud` (round-timer reset), `tws_t5_lock` |
|
||||||
| `hud_round_changed` | `tws_hud` | `tws_hud` (round-timer reset), `tws_lock` |
|
| `hud_match_started` | `tws_t5_hud` | `tws_t5_hud` (match-timer reveal) |
|
||||||
| `hud_match_started` | `tws_hud` | `tws_hud` (match-timer reveal) |
|
| `hud_game_over` | `tws_t5_hud` | `tws_t5_hud` (freeze timers), `tws_t5_lock` (clear password) |
|
||||||
| `hud_game_over` | `tws_hud` | `tws_hud` (freeze timers), `tws_lock` (clear password) |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## tws_common.gsc
|
## tws_t5_common.gsc
|
||||||
|
|
||||||
Hub file. Shared config, HUD helpers, spawn-handler registry, and the
|
Hub file. Shared config, HUD helpers, spawn-handler registry, and the
|
||||||
single `level waittill("connected")` in the fleet. Adding a second
|
single `level waittill("connected")` in the fleet. Adding a second
|
||||||
@@ -153,31 +156,7 @@ connect listener anywhere else crashes the T5 SP handshake.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## tws_db.gsc
|
## tws_t5_hud.gsc
|
||||||
|
|
||||||
**Features**
|
|
||||||
- One MariaDB connection pool for the whole script (used by bank now,
|
|
||||||
leaderboard later)
|
|
||||||
- Reachability probe: round-trips `SELECT 1` and flips `level.db_online`
|
|
||||||
- Fires `db_probe_done` so waiters can proceed regardless of outcome
|
|
||||||
|
|
||||||
**Provides**
|
|
||||||
| Level var / notify | Meaning |
|
|
||||||
|---|---|
|
|
||||||
| `level.db_online` | `true` iff the probe query returned without error |
|
|
||||||
| `level.db_probe_done` | `true` once the probe has completed (either way) |
|
|
||||||
| notify `db_probe_done` | Fired once after probe completion |
|
|
||||||
|
|
||||||
**Depends on**
|
|
||||||
- `scripts\sp\tws_common::ensure_config()`
|
|
||||||
- `t5-gsc-utils` (`mysql::set_config`, `mysql::query`)
|
|
||||||
|
|
||||||
**Config (currently hardcoded — TODO: dvarize before repo goes public)**
|
|
||||||
- Host `mariadb`, port `3306`, DB `tws_zm`, user `josh`, password `joshster`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## tws_hud.gsc
|
|
||||||
|
|
||||||
Bottom-left cluster. Per-player elements spawn via `::hud_start`.
|
Bottom-left cluster. Per-player elements spawn via `::hud_start`.
|
||||||
|
|
||||||
@@ -201,56 +180,17 @@ Spawn handler registered: `::hud_start` — threads `hud_timer_row`,
|
|||||||
`hud_zombie_counter`, `hud_health_display`.
|
`hud_zombie_counter`, `hud_health_display`.
|
||||||
|
|
||||||
**Depends on**
|
**Depends on**
|
||||||
- `scripts\sp\tws_common::` — `ensure_config`, `make_text_elem`,
|
- `scripts\sp\tws_t5_common::` — `ensure_config`, `make_text_elem`,
|
||||||
`make_shader_elem`, `destroy_on_disconnect`, `format_mmss`,
|
`make_shader_elem`, `destroy_on_disconnect`, `format_mmss`,
|
||||||
`register_spawn_handler`
|
`register_spawn_handler`
|
||||||
- Every `level.hud_*` config value from `tws_common`
|
- Every `level.hud_*` config value from `tws_t5_common`
|
||||||
- Stock BO1 state: `level.round_number`, `level.zombie_total`,
|
- Stock BO1 state: `level.round_number`, `level.zombie_total`,
|
||||||
`level.players`, `self.health`, `self.maxhealth`, `self.name` /
|
`level.players`, `self.health`, `self.maxhealth`, `self.name` /
|
||||||
`self.playername`, AI entities' `.animname` and `.ignore_enemy_count`
|
`self.playername`, AI entities' `.animname` and `.ignore_enemy_count`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## tws_bank.gsc
|
## tws_t5_afk.gsc
|
||||||
|
|
||||||
Persistent per-player bank. Balances survive server hops within the fleet
|
|
||||||
because rows are keyed on XUID.
|
|
||||||
|
|
||||||
**Features**
|
|
||||||
- Server-console commands: `bank`, `deposit <amount>`, `withdraw <amount>`
|
|
||||||
- DB-first / memory-second: `self.bank` and `self.score` only move after
|
|
||||||
the DB write confirms
|
|
||||||
- Deposits: `INSERT ... ON DUPLICATE KEY UPDATE` — lazy row create, atomic
|
|
||||||
- Withdrawals: `WHERE balance >= ?` — DB blocks overdrafts under concurrency
|
|
||||||
- Score-drift refund guard on deposit
|
|
||||||
- `bank_load` currently a **diagnostic stub** (bare-minimum to isolate the
|
|
||||||
connect-handshake crash — do not restore the stripped body until it passes
|
|
||||||
join)
|
|
||||||
|
|
||||||
**Provides**
|
|
||||||
| Command | Args | Effect |
|
|
||||||
|---|---|---|
|
|
||||||
| `bank` | — | Prints current `Bank` and `Score` to the caller |
|
|
||||||
| `deposit` | `<amount>` | Score → bank, DB-first with refund on race |
|
|
||||||
| `withdraw` | `<amount>` | Bank → score, DB-first with overdraft guard |
|
|
||||||
|
|
||||||
Per-player state: `self.bank` (int), `self.bank_unavailable` (bool),
|
|
||||||
`self.bank_guid` (set in the full impl — currently unset by the stub).
|
|
||||||
|
|
||||||
**Depends on**
|
|
||||||
- `scripts\sp\tws_common::` — `ensure_config`, `register_spawn_handler`
|
|
||||||
- `tws_db` — waits on `db_probe_done`, gates on `level.db_online`
|
|
||||||
- `t5-gsc-utils` — `mysql::query`, `mysql::prepared_statement`,
|
|
||||||
`command::add_sv`
|
|
||||||
- Stock BO1: `self.score`
|
|
||||||
- Dvar: `tws_server_id` (optional; labels `last_server` on bank rows)
|
|
||||||
- External: MariaDB schema — `bank(guid, balance, last_name, last_server)`
|
|
||||||
|
|
||||||
Spawn handler registered: `::bank_load`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## tws_afk.gsc
|
|
||||||
|
|
||||||
Self-invoked pause mode. Owns the `[AFK]` indicator element entirely — HUD
|
Self-invoked pause mode. Owns the `[AFK]` indicator element entirely — HUD
|
||||||
module has zero knowledge of AFK.
|
module has zero knowledge of AFK.
|
||||||
@@ -271,7 +211,7 @@ module has zero knowledge of AFK.
|
|||||||
- Level var: `level.afk_grace_seconds` (default 2)
|
- Level var: `level.afk_grace_seconds` (default 2)
|
||||||
|
|
||||||
**Depends on**
|
**Depends on**
|
||||||
- `scripts\sp\tws_common::` — `ensure_config`, `make_text_elem`,
|
- `scripts\sp\tws_t5_common::` — `ensure_config`, `make_text_elem`,
|
||||||
`destroy_on_disconnect`, `register_spawn_handler`, `register_help_command`
|
`destroy_on_disconnect`, `register_spawn_handler`, `register_help_command`
|
||||||
- Shared config: `level.hud_x`, `level.hud_row_match`,
|
- Shared config: `level.hud_x`, `level.hud_row_match`,
|
||||||
`level.hud_font_small`, `level.hud_c_afk`
|
`level.hud_font_small`, `level.hud_c_afk`
|
||||||
@@ -282,10 +222,10 @@ Spawn handler registered: `::afk_spawn`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## tws_join.gsc
|
## tws_t5_join.gsc
|
||||||
|
|
||||||
Type `.join` in chat while spectating after joining a match in progress to
|
Type `.join` in chat while spectating after joining a match in progress to
|
||||||
spawn immediately. Install with `tws_common.gsc`; no HUD or DB dependency.
|
spawn immediately. Install with `tws_t5_common.gsc`; no HUD dependency.
|
||||||
|
|
||||||
**Eligibility**
|
**Eligibility**
|
||||||
|
|
||||||
@@ -323,7 +263,7 @@ and [spawn entry point](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## tws_lock.gsc
|
## tws_t5_lock.gsc
|
||||||
|
|
||||||
**Features**
|
**Features**
|
||||||
- Sets `g_password` to a random per-lobby value when the round crosses a
|
- Sets `g_password` to a random per-lobby value when the round crosses a
|
||||||
@@ -339,8 +279,8 @@ and [spawn entry point](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/
|
|||||||
| `level.lock_active` | `true` after the password has been set |
|
| `level.lock_active` | `true` after the password has been set |
|
||||||
|
|
||||||
**Depends on**
|
**Depends on**
|
||||||
- `scripts\sp\tws_common::` — `ensure_config`, `int_dvar_or`
|
- `scripts\sp\tws_t5_common::` — `ensure_config`, `int_dvar_or`
|
||||||
- `tws_hud` — waits on `hud_round_changed` and `hud_game_over`
|
- `tws_t5_hud` — waits on `hud_round_changed` and `hud_game_over`
|
||||||
- Stock BO1: `level.round_number`
|
- Stock BO1: `level.round_number`
|
||||||
- Dvar: `tws_lock_round` (int, default `20`)
|
- Dvar: `tws_lock_round` (int, default `20`)
|
||||||
|
|
||||||
@@ -351,17 +291,17 @@ and [spawn entry point](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/
|
|||||||
| Dvar | Consumer | Default | Purpose |
|
| Dvar | Consumer | Default | Purpose |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `zombiemode` | every module | — | Gate: every `init()` returns early unless `"1"` |
|
| `zombiemode` | every module | — | Gate: every `init()` returns early unless `"1"` |
|
||||||
| `tws_lock_round` | `tws_lock` | `20` | Round at which the lobby locks |
|
| `tws_lock_round` | `tws_t5_lock` | `20` | Round at which the lobby locks |
|
||||||
| `tws_server_id` | `tws_bank`, `tws_telemetry` | Required for telemetry | Exact registered Electric Cherry server name; also used as the bank label |
|
| `tws_server_id` | `tws_t5_telemetry` | Required for telemetry | Exact registered Electric Cherry server name |
|
||||||
| `tws_telemetry_enabled` | `tws_telemetry` | `1` | Set to `0` to disable telemetry at init |
|
| `tws_telemetry_enabled` | `tws_t5_telemetry` | `1` | Set to `0` to disable telemetry at init |
|
||||||
| `tws_telemetry_url` | `tws_telemetry` | `https://ec.thewrightserver.net/api/telemetry` | Electric Cherry telemetry endpoint for JSON POSTs |
|
| `tws_telemetry_url` | `tws_t5_telemetry` | `https://ec.thewrightserver.net/api/telemetry` | Electric Cherry telemetry endpoint for JSON POSTs |
|
||||||
| `tws_telemetry_log_level` | `tws_telemetry` | `1` | Read live: `0` warnings/errors/recovery only, `1` lifecycle/request/health logs, `2` also capture/queue logs and response previews |
|
| `tws_telemetry_log_level` | `tws_t5_telemetry` | `1` | Read live: `0` warnings/errors/recovery only, `1` lifecycle/request/health logs, `2` also capture/queue logs and response previews |
|
||||||
|
|
||||||
## tws_telemetry.gsc
|
## tws_t5_telemetry.gsc
|
||||||
|
|
||||||
Uses `t5-gsc-utils` HTTP/JSON components to POST directly to Electric Cherry's
|
Uses `t5-gsc-utils` HTTP/JSON components to POST directly to Electric Cherry's
|
||||||
`/api/telemetry`. Install alongside `tws_common.gsc` in `storage/t5/scripts/sp/`.
|
`/api/telemetry`. Install alongside `tws_t5_common.gsc` in `storage/t5/scripts/sp/`.
|
||||||
No HUD or database dependency. Reports run whether or not a beta is active.
|
No HUD dependency. Reports run whether or not a beta is active.
|
||||||
Follow the shared [authentication setup](../README.md#telemetry-authentication-t5-and-t6)
|
Follow the shared [authentication setup](../README.md#telemetry-authentication-t5-and-t6)
|
||||||
to configure the service before upgrading. The reporter token is embedded in
|
to configure the service before upgrading. The reporter token is embedded in
|
||||||
`level.telemetry_token`; it must match the service's `EC_TELEMETRY_TOKEN`. Short
|
`level.telemetry_token`; it must match the service's `EC_TELEMETRY_TOKEN`. Short
|
||||||
@@ -503,7 +443,7 @@ and [score tracking](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/Com
|
|||||||
4. Delay HTTP completion while rounds advance and the match ends. Verify
|
4. Delay HTTP completion while rounds advance and the match ends. Verify
|
||||||
requests remain ordered and retain the stats captured at each event.
|
requests remain ordered and retain the stats captured at each event.
|
||||||
With the API unreachable, verify transport-error logging and continued
|
With the API unreachable, verify transport-error logging and continued
|
||||||
gameplay. Repeat without an active beta and with HUD/DB modules removed.
|
gameplay. Repeat without an active beta and with the HUD module removed.
|
||||||
5. Stay in one round for over a minute. Verify heartbeats at 30 and 60 seconds
|
5. Stay in one round for over a minute. Verify heartbeats at 30 and 60 seconds
|
||||||
after start, with current stats and the same fields as `round_change`.
|
after start, with current stats and the same fields as `round_change`.
|
||||||
Check that round changes and joins do not reset or duplicate the interval,
|
Check that round changes and joins do not reset or duplicate the interval,
|
||||||
@@ -522,11 +462,7 @@ and [score tracking](https://github.com/plutoniummod/t5-scripts/blob/main/ZM/Com
|
|||||||
|
|
||||||
## External dependencies
|
## External dependencies
|
||||||
|
|
||||||
- **[t5-gsc-utils](https://github.com/alicealys/t5-gsc-utils)** — required.
|
[t5-gsc-utils](https://github.com/alicealys/t5-gsc-utils) is required for telemetry
|
||||||
`tws_db` and `tws_bank` need the `mysql::` namespace; `tws_bank` also
|
and leaderboard HTTP, JSON, type and string helpers. Install a build exposing
|
||||||
needs `command::add_sv`.
|
the natives listed in each module's documentation, then restart the server
|
||||||
- **MariaDB / MySQL server** reachable from the Plutonium container as
|
process. No database is required.
|
||||||
`mariadb:3306` (currently hardcoded — see `tws_db.gsc`).
|
|
||||||
- **Schema** — `bank(guid VARCHAR PRIMARY KEY, balance INT, last_name
|
|
||||||
VARCHAR, last_server VARCHAR)`. `tws_bank` lazily inserts rows on first
|
|
||||||
deposit.
|
|
||||||
|
|||||||
-229
@@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
tws_bank.gsc — persistent per-player bank, MariaDB-backed. See NOTES.md
|
|
||||||
for the DB-first / spawn-dispatch / command surface invariants.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include maps\_utility;
|
|
||||||
#include common_scripts\utility;
|
|
||||||
|
|
||||||
init()
|
|
||||||
{
|
|
||||||
if (GetDvar(#"zombiemode") != "1")
|
|
||||||
return;
|
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
|
||||||
|
|
||||||
bank_init();
|
|
||||||
|
|
||||||
scripts\sp\tws_common::register_spawn_handler(::bank_load);
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_init()
|
|
||||||
{
|
|
||||||
if (!isDefined(level.db_probe_done) || !level.db_probe_done)
|
|
||||||
level thread bank_deferred_start();
|
|
||||||
else
|
|
||||||
bank_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_deferred_start()
|
|
||||||
{
|
|
||||||
level waittill("db_probe_done");
|
|
||||||
bank_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_start()
|
|
||||||
{
|
|
||||||
if (!level.db_online)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bank_register_commands();
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_register_commands()
|
|
||||||
{
|
|
||||||
command::add_sv("bank", ::bank_cmd_bank);
|
|
||||||
command::add_sv("deposit", ::bank_cmd_deposit);
|
|
||||||
command::add_sv("withdraw", ::bank_cmd_withdraw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DIAGNOSTIC STUB — bare minimum to isolate the connect-handshake crash.
|
|
||||||
// Do not restore the getGuid / mysql body until this passes join.
|
|
||||||
bank_load()
|
|
||||||
{
|
|
||||||
self endon("disconnect");
|
|
||||||
self iPrintLnBold("^2bank_load: entered");
|
|
||||||
self.bank = 0;
|
|
||||||
self.bank_unavailable = false;
|
|
||||||
self iPrintLnBold("^2bank_load: done");
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_available(player)
|
|
||||||
{
|
|
||||||
if (!level.db_online)
|
|
||||||
{
|
|
||||||
player iPrintLnBold("^1Bank offline");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_true(player.bank_unavailable))
|
|
||||||
{
|
|
||||||
player iPrintLnBold("^1Bank unavailable for your account");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDefined(player.bank))
|
|
||||||
{
|
|
||||||
player iPrintLnBold("^3Bank still loading, try again");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_cmd_bank(args)
|
|
||||||
{
|
|
||||||
if (!bank_available(self))
|
|
||||||
return;
|
|
||||||
|
|
||||||
self iPrintLnBold("Bank: " + self.bank + " Score: " + self.score);
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_cmd_deposit(args)
|
|
||||||
{
|
|
||||||
if (!bank_available(self))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (args.size < 2)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("Usage: deposit <amount>");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
amount = int(args[1]);
|
|
||||||
|
|
||||||
if (amount <= 0)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Amount must be positive");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount > self.score)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Not enough score");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self thread bank_deposit_write(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_cmd_withdraw(args)
|
|
||||||
{
|
|
||||||
if (!bank_available(self))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (args.size < 2)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("Usage: withdraw <amount>");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
amount = int(args[1]);
|
|
||||||
|
|
||||||
if (amount <= 0)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Amount must be positive");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount > self.bank)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Insufficient balance");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self thread bank_withdraw_write(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// upsert: first deposit creates the row, later ones increment
|
|
||||||
bank_deposit_write(amount)
|
|
||||||
{
|
|
||||||
self endon("disconnect");
|
|
||||||
|
|
||||||
name = bank_display_name(self);
|
|
||||||
server_id = bank_server_id();
|
|
||||||
|
|
||||||
q = mysql::prepared_statement(
|
|
||||||
"INSERT INTO bank (guid, balance, last_name, last_server) VALUES (?, ?, ?, ?) " +
|
|
||||||
"ON DUPLICATE KEY UPDATE balance = balance + VALUES(balance), " +
|
|
||||||
"last_name = VALUES(last_name), last_server = VALUES(last_server)",
|
|
||||||
self.bank_guid, amount, name, server_id);
|
|
||||||
|
|
||||||
q waittill("done", result, affected_rows, error);
|
|
||||||
|
|
||||||
if (isDefined(error) && error != "")
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Deposit failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// score can change between dispatch and write completing — refund if so
|
|
||||||
if (amount > self.score)
|
|
||||||
{
|
|
||||||
mysql::prepared_statement(
|
|
||||||
"UPDATE bank SET balance = balance - ? WHERE guid = ?",
|
|
||||||
amount, self.bank_guid);
|
|
||||||
self iPrintLnBold("^1Deposit rolled back (score changed)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.score -= amount;
|
|
||||||
self.bank += amount;
|
|
||||||
self iPrintLnBold("Deposited " + amount + " Bank: " + self.bank);
|
|
||||||
}
|
|
||||||
|
|
||||||
// balance guard lives in the WHERE so concurrent commands can't overdraw
|
|
||||||
bank_withdraw_write(amount)
|
|
||||||
{
|
|
||||||
self endon("disconnect");
|
|
||||||
|
|
||||||
q = mysql::prepared_statement(
|
|
||||||
"UPDATE bank SET balance = balance - ? WHERE guid = ? AND balance >= ?",
|
|
||||||
amount, self.bank_guid, amount);
|
|
||||||
|
|
||||||
q waittill("done", result, affected_rows, error);
|
|
||||||
|
|
||||||
if (isDefined(error) && error != "")
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Withdraw failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDefined(affected_rows) || affected_rows == 0)
|
|
||||||
{
|
|
||||||
self iPrintLnBold("^1Insufficient balance");
|
|
||||||
self thread bank_load(); // re-sync in case memory drifted from DB
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.score += amount;
|
|
||||||
self.bank -= amount;
|
|
||||||
self iPrintLnBold("Withdrew " + amount + " Bank: " + self.bank);
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_display_name(player)
|
|
||||||
{
|
|
||||||
if (isDefined(player.name))
|
|
||||||
return player.name;
|
|
||||||
if (isDefined(player.playername))
|
|
||||||
return player.playername;
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
bank_server_id()
|
|
||||||
{
|
|
||||||
id = GetDvar("tws_server_id");
|
|
||||||
if (id == "")
|
|
||||||
return "unknown";
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/* tws_db.gsc — MariaDB pool + reachability probe. Fires db_probe_done. */
|
|
||||||
|
|
||||||
#include maps\_utility;
|
|
||||||
#include common_scripts\utility;
|
|
||||||
|
|
||||||
init()
|
|
||||||
{
|
|
||||||
if (GetDvar(#"zombiemode") != "1")
|
|
||||||
return;
|
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
|
||||||
|
|
||||||
db_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: move creds to dvars before this repo goes public
|
|
||||||
db_init()
|
|
||||||
{
|
|
||||||
level.db_online = false;
|
|
||||||
level.db_probe_done = false;
|
|
||||||
|
|
||||||
cfg = spawnStruct();
|
|
||||||
cfg.host = "mariadb";
|
|
||||||
cfg.user = "josh";
|
|
||||||
cfg.password = "joshster";
|
|
||||||
cfg.port = 3306;
|
|
||||||
cfg.database = "tws_zm";
|
|
||||||
|
|
||||||
mysql::set_config(cfg);
|
|
||||||
|
|
||||||
level thread db_probe();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_config is silent on failure; only a real query surfaces the error
|
|
||||||
db_probe()
|
|
||||||
{
|
|
||||||
q = mysql::query("SELECT 1 AS ok");
|
|
||||||
q waittill("done", result, affected_rows, error);
|
|
||||||
|
|
||||||
if (isDefined(error) && error != "")
|
|
||||||
level.db_online = false;
|
|
||||||
else
|
|
||||||
level.db_online = true;
|
|
||||||
|
|
||||||
level.db_probe_done = true;
|
|
||||||
level notify("db_probe_done");
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
tws_afk.gsc — .afk / .back chat toggle. Owns the [AFK] indicator element.
|
tws_t5_afk.gsc — .afk / .back chat toggle. Owns the [AFK] indicator element.
|
||||||
Chat uses level waittill("say") — callbackPlayerSay never fires on T5 SP
|
Chat uses level waittill("say") — callbackPlayerSay never fires on T5 SP
|
||||||
dedicated (see NOTES.md).
|
dedicated (see NOTES.md).
|
||||||
*/
|
*/
|
||||||
@@ -12,13 +12,13 @@ init()
|
|||||||
if (GetDvar(#"zombiemode") != "1")
|
if (GetDvar(#"zombiemode") != "1")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
scripts\sp\tws_t5_common::ensure_config();
|
||||||
scripts\sp\tws_common::register_help_command(".afk", "Pause with protection");
|
scripts\sp\tws_t5_common::register_help_command(".afk", "Pause with protection");
|
||||||
scripts\sp\tws_common::register_help_command(".back", "Return from AFK");
|
scripts\sp\tws_t5_common::register_help_command(".back", "Return from AFK");
|
||||||
|
|
||||||
afk_init();
|
afk_init();
|
||||||
|
|
||||||
scripts\sp\tws_common::register_spawn_handler(::afk_spawn);
|
scripts\sp\tws_t5_common::register_spawn_handler(::afk_spawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
afk_init()
|
afk_init()
|
||||||
@@ -50,7 +50,7 @@ afk_spawn()
|
|||||||
{
|
{
|
||||||
self endon("disconnect");
|
self endon("disconnect");
|
||||||
|
|
||||||
afk = scripts\sp\tws_common::make_text_elem(
|
afk = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x + 42, level.hud_row_match,
|
self, level.hud_x + 42, level.hud_row_match,
|
||||||
"left", level.hud_font_small, level.hud_c_afk);
|
"left", level.hud_font_small, level.hud_c_afk);
|
||||||
afk SetText("[AFK]");
|
afk SetText("[AFK]");
|
||||||
@@ -59,7 +59,7 @@ afk_spawn()
|
|||||||
|
|
||||||
elems = [];
|
elems = [];
|
||||||
elems[elems.size] = afk;
|
elems[elems.size] = afk;
|
||||||
self thread scripts\sp\tws_common::destroy_on_disconnect(elems);
|
self thread scripts\sp\tws_t5_common::destroy_on_disconnect(elems);
|
||||||
}
|
}
|
||||||
|
|
||||||
afk_enter()
|
afk_enter()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tws_common.gsc — shared config, HUD helpers, connect/spawn/help registries. */
|
/* tws_t5_common.gsc — shared config, HUD helpers, connect/spawn/help registries. */
|
||||||
|
|
||||||
#include maps\_utility;
|
#include maps\_utility;
|
||||||
#include common_scripts\utility;
|
#include common_scripts\utility;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tws_hud.gsc — bottom-left HUD stack. Timer / zombie count / health bar. */
|
/* tws_t5_hud.gsc — bottom-left HUD stack. Timer / zombie count / health bar. */
|
||||||
|
|
||||||
#include maps\_utility;
|
#include maps\_utility;
|
||||||
#include common_scripts\utility;
|
#include common_scripts\utility;
|
||||||
@@ -8,12 +8,12 @@ init()
|
|||||||
if (GetDvar(#"zombiemode") != "1")
|
if (GetDvar(#"zombiemode") != "1")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
scripts\sp\tws_t5_common::ensure_config();
|
||||||
|
|
||||||
level thread round_watcher();
|
level thread round_watcher();
|
||||||
level thread game_over_watcher();
|
level thread game_over_watcher();
|
||||||
|
|
||||||
scripts\sp\tws_common::register_spawn_handler(::hud_start);
|
scripts\sp\tws_t5_common::register_spawn_handler(::hud_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
hud_start()
|
hud_start()
|
||||||
@@ -87,18 +87,18 @@ hud_timer_row()
|
|||||||
level notify("hud_match_started");
|
level notify("hud_match_started");
|
||||||
}
|
}
|
||||||
|
|
||||||
match = scripts\sp\tws_common::make_text_elem(
|
match = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x, level.hud_row_match,
|
self, level.hud_x, level.hud_row_match,
|
||||||
"left", level.hud_font_small, level.hud_c_dim);
|
"left", level.hud_font_small, level.hud_c_dim);
|
||||||
match.alpha = 0; // revealed by match_timer_bind when round 1 opens
|
match.alpha = 0; // revealed by match_timer_bind when round 1 opens
|
||||||
|
|
||||||
round = scripts\sp\tws_common::make_text_elem(
|
round = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x, level.hud_row_round,
|
self, level.hud_x, level.hud_row_round,
|
||||||
"left", level.hud_font_small, level.hud_c_dim);
|
"left", level.hud_font_small, level.hud_c_dim);
|
||||||
round SetTimerUp(0);
|
round SetTimerUp(0);
|
||||||
|
|
||||||
// name only shows in co-op — your own name is noise in solo
|
// name only shows in co-op — your own name is noise in solo
|
||||||
name = scripts\sp\tws_common::make_text_elem(
|
name = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x, level.hud_row_name,
|
self, level.hud_x, level.hud_row_name,
|
||||||
"left", level.hud_font_small, level.hud_c_name);
|
"left", level.hud_font_small, level.hud_c_name);
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ hud_timer_row()
|
|||||||
elems[elems.size] = match;
|
elems[elems.size] = match;
|
||||||
elems[elems.size] = round;
|
elems[elems.size] = round;
|
||||||
elems[elems.size] = name;
|
elems[elems.size] = name;
|
||||||
self thread scripts\sp\tws_common::destroy_on_disconnect(elems);
|
self thread scripts\sp\tws_t5_common::destroy_on_disconnect(elems);
|
||||||
|
|
||||||
self thread reset_timer_each_round(round);
|
self thread reset_timer_each_round(round);
|
||||||
self thread match_timer_bind(match);
|
self thread match_timer_bind(match);
|
||||||
@@ -177,22 +177,22 @@ freeze_timers_on_game_over(match_elem, round_elem)
|
|||||||
level waittill("hud_game_over");
|
level waittill("hud_game_over");
|
||||||
|
|
||||||
if (isDefined(match_elem) && isDefined(level.match_start_time))
|
if (isDefined(match_elem) && isDefined(level.match_start_time))
|
||||||
match_elem SetText(scripts\sp\tws_common::format_mmss(getTime() - level.match_start_time));
|
match_elem SetText(scripts\sp\tws_t5_common::format_mmss(getTime() - level.match_start_time));
|
||||||
|
|
||||||
if (isDefined(round_elem) && isDefined(level.round_start_time))
|
if (isDefined(round_elem) && isDefined(level.round_start_time))
|
||||||
round_elem SetText(scripts\sp\tws_common::format_mmss(getTime() - level.round_start_time));
|
round_elem SetText(scripts\sp\tws_t5_common::format_mmss(getTime() - level.round_start_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
hud_zombie_counter()
|
hud_zombie_counter()
|
||||||
{
|
{
|
||||||
self endon("disconnect");
|
self endon("disconnect");
|
||||||
|
|
||||||
label = scripts\sp\tws_common::make_text_elem(
|
label = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x, level.hud_row_count,
|
self, level.hud_x, level.hud_row_count,
|
||||||
"left", level.hud_font_large, level.hud_c_label);
|
"left", level.hud_font_large, level.hud_c_label);
|
||||||
label SetText("Zombies");
|
label SetText("Zombies");
|
||||||
|
|
||||||
count = scripts\sp\tws_common::make_text_elem(
|
count = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_col_count, level.hud_row_count,
|
self, level.hud_col_count, level.hud_row_count,
|
||||||
"left", level.hud_font_large, level.hud_c_count);
|
"left", level.hud_font_large, level.hud_c_count);
|
||||||
count SetValue(0);
|
count SetValue(0);
|
||||||
@@ -200,7 +200,7 @@ hud_zombie_counter()
|
|||||||
elems = [];
|
elems = [];
|
||||||
elems[elems.size] = label;
|
elems[elems.size] = label;
|
||||||
elems[elems.size] = count;
|
elems[elems.size] = count;
|
||||||
self thread scripts\sp\tws_common::destroy_on_disconnect(elems);
|
self thread scripts\sp\tws_t5_common::destroy_on_disconnect(elems);
|
||||||
|
|
||||||
last = -1;
|
last = -1;
|
||||||
|
|
||||||
@@ -245,12 +245,12 @@ hud_health_display()
|
|||||||
bar_width = level.hud_bar_width;
|
bar_width = level.hud_bar_width;
|
||||||
|
|
||||||
// -2 on both axes so the back frames the bar with 2px padding
|
// -2 on both axes so the back frames the bar with 2px padding
|
||||||
back = scripts\sp\tws_common::make_shader_elem(self, level.hud_x - 2, level.hud_row_bar - 2);
|
back = scripts\sp\tws_t5_common::make_shader_elem(self, level.hud_x - 2, level.hud_row_bar - 2);
|
||||||
back.alpha = 0.5;
|
back.alpha = 0.5;
|
||||||
back.color = (0, 0, 0);
|
back.color = (0, 0, 0);
|
||||||
back SetShader("black", bar_width + 4, level.hud_bar_height + 4);
|
back SetShader("black", bar_width + 4, level.hud_bar_height + 4);
|
||||||
|
|
||||||
bar = scripts\sp\tws_common::make_shader_elem(self, level.hud_x, level.hud_row_bar);
|
bar = scripts\sp\tws_t5_common::make_shader_elem(self, level.hud_x, level.hud_row_bar);
|
||||||
bar.color = level.hud_c_high;
|
bar.color = level.hud_c_high;
|
||||||
bar SetShader("white", bar_width, level.hud_bar_height);
|
bar SetShader("white", bar_width, level.hud_bar_height);
|
||||||
|
|
||||||
@@ -260,17 +260,17 @@ hud_health_display()
|
|||||||
cur is right-aligned so digits grow leftward and the slash + max
|
cur is right-aligned so digits grow leftward and the slash + max
|
||||||
never shift.
|
never shift.
|
||||||
*/
|
*/
|
||||||
cur = scripts\sp\tws_common::make_text_elem(
|
cur = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_col_health + 26, level.hud_row_bar + 3,
|
self, level.hud_col_health + 26, level.hud_row_bar + 3,
|
||||||
"right", level.hud_font_mid, level.hud_c_high);
|
"right", level.hud_font_mid, level.hud_c_high);
|
||||||
cur SetValue(self.health);
|
cur SetValue(self.health);
|
||||||
|
|
||||||
slash = scripts\sp\tws_common::make_text_elem(
|
slash = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_col_health + 30, level.hud_row_bar + 3,
|
self, level.hud_col_health + 30, level.hud_row_bar + 3,
|
||||||
"center", level.hud_font_mid, level.hud_c_high);
|
"center", level.hud_font_mid, level.hud_c_high);
|
||||||
slash SetText("/");
|
slash SetText("/");
|
||||||
|
|
||||||
max_hp = scripts\sp\tws_common::make_text_elem(
|
max_hp = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_col_health + 34, level.hud_row_bar + 3,
|
self, level.hud_col_health + 34, level.hud_row_bar + 3,
|
||||||
"left", level.hud_font_mid, level.hud_c_high);
|
"left", level.hud_font_mid, level.hud_c_high);
|
||||||
max_hp SetValue(self.maxhealth);
|
max_hp SetValue(self.maxhealth);
|
||||||
@@ -285,7 +285,7 @@ hud_health_display()
|
|||||||
elems[elems.size] = cur;
|
elems[elems.size] = cur;
|
||||||
elems[elems.size] = slash;
|
elems[elems.size] = slash;
|
||||||
elems[elems.size] = max_hp;
|
elems[elems.size] = max_hp;
|
||||||
self thread scripts\sp\tws_common::destroy_on_disconnect(elems);
|
self thread scripts\sp\tws_t5_common::destroy_on_disconnect(elems);
|
||||||
|
|
||||||
last_width = bar_width;
|
last_width = bar_width;
|
||||||
last_health = -1;
|
last_health = -1;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tws_join.gsc - .join lets a newcomer leave spectator mode before round end. */
|
/* tws_t5_join.gsc - .join lets a newcomer leave spectator mode before round end. */
|
||||||
|
|
||||||
#include maps\_utility;
|
#include maps\_utility;
|
||||||
#include common_scripts\utility;
|
#include common_scripts\utility;
|
||||||
@@ -8,9 +8,9 @@ init()
|
|||||||
if (GetDvar(#"zombiemode") != "1")
|
if (GetDvar(#"zombiemode") != "1")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
scripts\sp\tws_t5_common::ensure_config();
|
||||||
scripts\sp\tws_common::register_help_command(".join", "Join mid-round (newcomers only)");
|
scripts\sp\tws_t5_common::register_help_command(".join", "Join mid-round (newcomers only)");
|
||||||
scripts\sp\tws_common::register_spawn_handler(::join_spawn);
|
scripts\sp\tws_t5_common::register_spawn_handler(::join_spawn);
|
||||||
|
|
||||||
level thread join_chat_listener();
|
level thread join_chat_listener();
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tws_leaderboard.gsc - private map record announcement, once per connection. */
|
/* tws_t5_leaderboard.gsc - private map record announcement, once per connection. */
|
||||||
|
|
||||||
#include maps\_utility;
|
#include maps\_utility;
|
||||||
#include common_scripts\utility;
|
#include common_scripts\utility;
|
||||||
@@ -24,7 +24,7 @@ init()
|
|||||||
level.tws_lb_pending = undefined;
|
level.tws_lb_pending = undefined;
|
||||||
level.tws_lb_cache = undefined;
|
level.tws_lb_cache = undefined;
|
||||||
level.tws_lb_attempt = 0;
|
level.tws_lb_attempt = 0;
|
||||||
scripts\sp\tws_common::register_connect_handler(::lb_welcome);
|
scripts\sp\tws_t5_common::register_connect_handler(::lb_welcome);
|
||||||
level thread lb_worker();
|
level thread lb_worker();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +99,11 @@ lb_show_hud(snapshot)
|
|||||||
self endon("disconnect");
|
self endon("disconnect");
|
||||||
self endon("tws_lb_hud_done");
|
self endon("tws_lb_hud_done");
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
scripts\sp\tws_t5_common::ensure_config();
|
||||||
// Match .help's position, typography and row spacing below the health bar.
|
// Match .help's position, typography and row spacing below the health bar.
|
||||||
y = level.hud_row_bar + level.hud_bar_height + 20;
|
y = level.hud_row_bar + level.hud_bar_height + 20;
|
||||||
elems = [];
|
elems = [];
|
||||||
title = scripts\sp\tws_common::make_text_elem(
|
title = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x, y, "left", level.hud_font_mid, level.hud_c_afk);
|
self, level.hud_x, y, "left", level.hud_font_mid, level.hud_c_afk);
|
||||||
title.alpha = 0;
|
title.alpha = 0;
|
||||||
if (snapshot.round == 0)
|
if (snapshot.round == 0)
|
||||||
@@ -114,7 +114,7 @@ lb_show_hud(snapshot)
|
|||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
row = scripts\sp\tws_common::make_text_elem(
|
row = scripts\sp\tws_t5_common::make_text_elem(
|
||||||
self, level.hud_x, y + 22 + i * 18,
|
self, level.hud_x, y + 22 + i * 18,
|
||||||
"left", level.hud_font_small, level.hud_c_count);
|
"left", level.hud_font_small, level.hud_c_count);
|
||||||
row.alpha = 0;
|
row.alpha = 0;
|
||||||
@@ -122,7 +122,7 @@ lb_show_hud(snapshot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup runs independently of the welcome thread's endon handlers.
|
// Cleanup runs independently of the welcome thread's endon handlers.
|
||||||
self thread scripts\sp\tws_common::destroy_on_disconnect(elems);
|
self thread scripts\sp\tws_t5_common::destroy_on_disconnect(elems);
|
||||||
self thread lb_hud_end_game(elems, "end_game");
|
self thread lb_hud_end_game(elems, "end_game");
|
||||||
self thread lb_hud_end_game(elems, "game_ended");
|
self thread lb_hud_end_game(elems, "game_ended");
|
||||||
self thread lb_hud_end_game(elems, "intermission");
|
self thread lb_hud_end_game(elems, "intermission");
|
||||||
@@ -303,7 +303,7 @@ lb_collect(request, pending)
|
|||||||
|
|
||||||
lb_log(message)
|
lb_log(message)
|
||||||
{
|
{
|
||||||
print("[tws_leaderboard] " + message);
|
print("[tws_t5_leaderboard] " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pure data helpers below are exercised by tools/check_leaderboard.mjs.
|
// Pure data helpers below are exercised by tools/check_leaderboard.mjs.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
tws_lock.gsc — lobby g_password lock at milestone round. Existing players
|
tws_t5_lock.gsc — lobby g_password lock at milestone round. Existing players
|
||||||
are unaffected; g_password is only checked at connect. Cleared on
|
are unaffected; g_password is only checked at connect. Cleared on
|
||||||
hud_game_over so the next lobby opens unlocked.
|
hud_game_over so the next lobby opens unlocked.
|
||||||
*/
|
*/
|
||||||
@@ -12,14 +12,14 @@ init()
|
|||||||
if (GetDvar(#"zombiemode") != "1")
|
if (GetDvar(#"zombiemode") != "1")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
scripts\sp\tws_t5_common::ensure_config();
|
||||||
|
|
||||||
lock_init();
|
lock_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_init()
|
lock_init()
|
||||||
{
|
{
|
||||||
level.lock_round = scripts\sp\tws_common::int_dvar_or("tws_lock_round", 20);
|
level.lock_round = scripts\sp\tws_t5_common::int_dvar_or("tws_lock_round", 20);
|
||||||
level.lock_active = false;
|
level.lock_active = false;
|
||||||
|
|
||||||
// recover from a prior lobby that crashed before clearing
|
// recover from a prior lobby that crashed before clearing
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tws_telemetry.gsc - Electric Cherry game reports via t5-gsc-utils. */
|
/* tws_t5_telemetry.gsc - Electric Cherry game reports via t5-gsc-utils. */
|
||||||
|
|
||||||
#include maps\_utility;
|
#include maps\_utility;
|
||||||
#include common_scripts\utility;
|
#include common_scripts\utility;
|
||||||
@@ -8,11 +8,11 @@ init()
|
|||||||
if (GetDvar(#"zombiemode") != "1")
|
if (GetDvar(#"zombiemode") != "1")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scripts\sp\tws_common::ensure_config();
|
scripts\sp\tws_t5_common::ensure_config();
|
||||||
|
|
||||||
if (GetDvar("tws_telemetry_enabled") == "0")
|
if (GetDvar("tws_telemetry_enabled") == "0")
|
||||||
{
|
{
|
||||||
print("[tws_telemetry] Disabled by tws_telemetry_enabled=0");
|
print("[tws_t5_telemetry] Disabled by tws_telemetry_enabled=0");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ init()
|
|||||||
|
|
||||||
if (getSubStr(toLower(level.telemetry_url), 0, 8) != "https://")
|
if (getSubStr(toLower(level.telemetry_url), 0, 8) != "https://")
|
||||||
{
|
{
|
||||||
print("^1[tws_telemetry] Telemetry disabled: tws_telemetry_url must use HTTPS");
|
print("^1[tws_t5_telemetry] Telemetry disabled: tws_telemetry_url must use HTTPS");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,14 +34,14 @@ init()
|
|||||||
level.telemetry_token = "e03a03f7d22418f0c062b0b2a7317fd91b1194c4400e84b469866de501180dc2";
|
level.telemetry_token = "e03a03f7d22418f0c062b0b2a7317fd91b1194c4400e84b469866de501180dc2";
|
||||||
if (level.telemetry_token.size < 32)
|
if (level.telemetry_token.size < 32)
|
||||||
{
|
{
|
||||||
print("^1[tws_telemetry] Telemetry disabled: embedded telemetry token must be at least 32 characters");
|
print("^1[tws_t5_telemetry] Telemetry disabled: embedded telemetry token must be at least 32 characters");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
level.telemetry_server = GetDvar("tws_server_id");
|
level.telemetry_server = GetDvar("tws_server_id");
|
||||||
if (level.telemetry_server == "")
|
if (level.telemetry_server == "")
|
||||||
{
|
{
|
||||||
print("^1[tws_telemetry] Set tws_server_id to the registered Electric Cherry server name");
|
print("^1[tws_t5_telemetry] Set tws_server_id to the registered Electric Cherry server name");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ init()
|
|||||||
telemetry_log(1, "Initialized; waiting for match start. log_level=" + telemetry_log_level());
|
telemetry_log(1, "Initialized; waiting for match start. log_level=" + telemetry_log_level());
|
||||||
|
|
||||||
// Use the shared dispatcher; a second connected listener breaks T5 SP.
|
// Use the shared dispatcher; a second connected listener breaks T5 SP.
|
||||||
scripts\sp\tws_common::register_spawn_handler(::telemetry_game_start);
|
scripts\sp\tws_t5_common::register_spawn_handler(::telemetry_game_start);
|
||||||
|
|
||||||
level thread telemetry_game_end_watcher();
|
level thread telemetry_game_end_watcher();
|
||||||
level thread telemetry_sender();
|
level thread telemetry_sender();
|
||||||
@@ -367,7 +367,7 @@ telemetry_log(verbosity, message)
|
|||||||
if (verbosity > telemetry_log_level())
|
if (verbosity > telemetry_log_level())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
print("[tws_telemetry] server=" + level.telemetry_server + " map=" + GetDvar("mapname") + " time_ms=" + getTime() + " " + message);
|
print("[tws_t5_telemetry] server=" + level.telemetry_server + " map=" + GetDvar("mapname") + " time_ms=" + getTime() + " " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape newlines/control characters and bound response/error output. Do not
|
// Escape newlines/control characters and bound response/error output. Do not
|
||||||
+4
-5
@@ -1,8 +1,7 @@
|
|||||||
# T6 port notes
|
# T6 port notes
|
||||||
|
|
||||||
Baseline: the current files in `C:\Users\josh1\Documents\Code\TWS-T5-AIO`.
|
T6 is ported from T5. Both source trees contain common, HUD, AFK, join, lock,
|
||||||
The T5 originals were not modified. DB, bank, their schema and the added example
|
telemetry and leaderboard modules; neither includes bank or database modules.
|
||||||
config have been removed from this project.
|
|
||||||
|
|
||||||
## Differences retained for T6 and requested fixes
|
## Differences retained for T6 and requested fixes
|
||||||
|
|
||||||
@@ -16,7 +15,7 @@ config have been removed from this project.
|
|||||||
| Timers | Seed elapsed time for late joiners; stop round watcher/reset on game over | T6 timer behavior; keep frozen timers frozen |
|
| 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 |
|
| 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` fall back to `0` when `player.stats[]` is unpopulated | T6 has no `getGuid` method but exposes the persistent identity as `.guid` on the player entity; `_zm_stats` writes only into persistent stat storage, so `player.stats[]` is not a stock T6 field. 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` sources from Plutonium's `player.guid` engine property (T5 uses `player getGuid()` method); per-match `kills`/`headshots`/`downs`/`revives` fall back to `0` when `player.stats[]` is unpopulated | T6 has no `getGuid` method but exposes the persistent identity as `.guid` on the player entity; `_zm_stats` writes only into persistent stat storage, so `player.stats[]` is not a stock T6 field. Payload keys match T5 for downstream shape parity |
|
||||||
| Join | Port of T5 `tws_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 |
|
| 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.
|
Common retains the T5 HUD constants, helpers and first-spawn dispatcher.
|
||||||
HUD again owns the `hud_game_over` notification fan-out. Lock again waits on HUD
|
HUD again owns the `hud_game_over` notification fan-out. Lock again waits on HUD
|
||||||
@@ -46,7 +45,7 @@ not an external configuration system.
|
|||||||
|
|
||||||
## Leaderboard join announcements
|
## Leaderboard join announcements
|
||||||
|
|
||||||
The module is `tws_t6_leaderboard.gsc` in T6 and `tws_leaderboard.gsc` in T5.
|
The module is `tws_t6_leaderboard.gsc` in T6 and `tws_t5_leaderboard.gsc` in T5.
|
||||||
Common's existing
|
Common's existing
|
||||||
connection listener now also dispatches optional connection handlers after a
|
connection listener now also dispatches optional connection handlers after a
|
||||||
one-frame yield. Leaderboard waits for player readiness and uses a level-owned
|
one-frame yield. Leaderboard waits for player readiness and uses a level-owned
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ function functions(source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function engine(game) {
|
function engine(game) {
|
||||||
const source = readFileSync(new URL(`${game}/${game === 't6' ? 'tws_t6_leaderboard' : 'tws_leaderboard'}.gsc`, root), 'utf8');
|
const source = readFileSync(new URL(`${game}/tws_${game}_leaderboard.gsc`, root), 'utf8');
|
||||||
const all = functions(source);
|
const all = functions(source);
|
||||||
const excluded = new Set(['lb_worker', 'lb_welcome', 'lb_get', 'lb_collect', 'lb_log', 'lb_show_hud', 'lb_hud_help_visible', 'lb_hud_end_game', 'lb_hud_destroy']);
|
const excluded = new Set(['lb_worker', 'lb_welcome', 'lb_get', 'lb_collect', 'lb_log', 'lb_show_hud', 'lb_hud_help_visible', 'lb_hud_end_game', 'lb_hud_destroy']);
|
||||||
const table = [];
|
const table = [];
|
||||||
@@ -89,7 +89,7 @@ for (const game of ['t5', 't6']) {
|
|||||||
const { context: c, source, all, dvars, responses, queries } = engine(game);
|
const { context: c, source, all, dvars, responses, queries } = engine(game);
|
||||||
const option = mapOption(game);
|
const option = mapOption(game);
|
||||||
check(`${game} exactly one connect listener across modules`, () => {
|
check(`${game} exactly one connect listener across modules`, () => {
|
||||||
const common = readFileSync(new URL(game === 't5' ? 't5/tws_common.gsc' : 't6/tws_t6_common.gsc', root), 'utf8');
|
const common = readFileSync(new URL(`${game}/tws_${game}_common.gsc`, root), 'utf8');
|
||||||
assert.equal((common.match(/waittill\("connected"/g) ?? []).length, 1);
|
assert.equal((common.match(/waittill\("connected"/g) ?? []).length, 1);
|
||||||
assert(!source.includes('waittill("connected"'));
|
assert(!source.includes('waittill("connected"'));
|
||||||
assert(!all.get('lb_welcome').includes('spawned_player'));
|
assert(!all.get('lb_welcome').includes('spawned_player'));
|
||||||
@@ -212,11 +212,11 @@ for (const game of ['t5', 't6']) {
|
|||||||
assert.equal(responses.length, 0, `${game} unused responses`);
|
assert.equal(responses.length, 0, `${game} unused responses`);
|
||||||
}
|
}
|
||||||
check('paired data helpers stay identical', () => {
|
check('paired data helpers stay identical', () => {
|
||||||
const t5 = functions(readFileSync(new URL('t5/tws_leaderboard.gsc', root), 'utf8'));
|
const t5 = functions(readFileSync(new URL('t5/tws_t5_leaderboard.gsc', root), 'utf8'));
|
||||||
const t6 = functions(readFileSync(new URL('t6/tws_t6_leaderboard.gsc', root), 'utf8'));
|
const t6 = functions(readFileSync(new URL('t6/tws_t6_leaderboard.gsc', root), 'utf8'));
|
||||||
for (const [name, fn] of t5) {
|
for (const [name, fn] of t5) {
|
||||||
if (!['lb_selection', 'lb_welcome', 'lb_get', 'lb_log'].includes(name)) {
|
if (!['lb_selection', 'lb_welcome', 'lb_get', 'lb_log'].includes(name)) {
|
||||||
const normalized = t6.get(name).replaceAll('scripts\\zm\\tws_t6_common::', 'scripts\\sp\\tws_common::');
|
const normalized = t6.get(name).replaceAll('scripts\\zm\\tws_t6_common::', 'scripts\\sp\\tws_t5_common::');
|
||||||
assert.equal(normalized, fn, name);
|
assert.equal(normalized, fn, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user