Add identity-safe player moderation runtimes for T5 and T6

This commit is contained in:
2026-10-15 21:35:19 -04:00
parent 2b5b1955bc
commit d7bf16e9c2
27 changed files with 1784 additions and 25 deletions
+13 -5
View File
@@ -2,7 +2,7 @@
Plutonium T6 versions of the T5 server scripts. Defaults live in the scripts,
just like T5. The telemetry token is embedded in the reporter script; no
separate telemetry token config is required. The optional bank needs its own
separate telemetry token config is required. The optional bank and moderation modules each need their own
private server token.
| File | Role | Dependencies |
@@ -15,14 +15,16 @@ private server token.
| `tws_t6_join.gsc` | `.join` chat command lets a spectator newcomer enter mid-match once | Common |
| `tws_t6_leaderboard.gsc` | Private map high-round record and every tied holder on connection | Common 1.2.0+, tws-t6-gsc-utils |
| `tws_t6_bank.gsc` | Persistent shared GUID bank | Common, telemetry, TWS plugin 1.2.0 |
| `tws_t6_moderation.gsc` | Optional controller-managed bans, mutes and live moderation | Common 1.2.0+, TWS plugin 1.3.0+ |
## Install
1. Copy all eight `tws_t6_*.gsc` files into
1. Copy the desired modules from the nine `tws_t6_*.gsc` files into
`Plutonium/storage/t6/scripts/zm/`. Update common along with HUD, leaderboard
and AFK when those modules are installed.
2. For telemetry, leaderboard or bank, install the [tws-t6-gsc-utils build](../plugins/README.md), based on upstream v3.1.1,
in `Plutonium/plugins/` and restart the server process. The other five scripts
2. For telemetry, leaderboard, bank or moderation, install the [tws-t6-gsc-utils build](../plugins/README.md), based on upstream v3.1.1,
in `Plutonium/plugins/` and restart the server process. Moderation requires
plugin 1.3.0+ before its script is installed; see [moderation setup](../../docs/moderation.md). The other five scripts
do not require that plugin.
3. Ensure the API service's `EC_TELEMETRY_TOKEN` matches the token embedded in
the reporter; see [authentication setup](../../README.md#telemetry-authentication-t5-and-t6).
@@ -260,7 +262,7 @@ another mod installed one first.
Run the shared [portable and live HUD checks](../../README.md#hud-validation)
for core placement, service pagination, record interruptions and command regressions.
To compile all eight scripts for T6 PC with gsc-tool:
To compile all nine scripts for T6 PC with gsc-tool:
```powershell
.\tools\check.ps1 -CompilerPath C:\path\to\gsc-tool.exe
@@ -268,3 +270,9 @@ To compile all eight scripts for T6 PC with gsc-tool:
Compilation does not verify engine/plugin linking or gameplay. T6 differences,
research sources and live checks are in [NOTES.md](NOTES.md).
## Moderation
Optional `tws_t6_moderation.gsc` 1.0.0 requires common 1.2.0 and the matching
plugin 1.3.0. See the [moderation contract](../../docs/moderation.md) for private
configuration, persistence, action results and deployment checks.
+3 -3
View File
@@ -6,8 +6,8 @@ $ErrorActionPreference = 'Stop'
$compiler = (Resolve-Path -LiteralPath $CompilerPath).Path
$repo = Split-Path -Parent $PSScriptRoot
$files = @(Get-ChildItem -LiteralPath $repo -Filter 'tws_*.gsc' | Sort-Object Name)
$expected = @('tws_t6_common.gsc', 'tws_t6_hud.gsc', 'tws_t6_afk.gsc', 'tws_t6_lock.gsc', 'tws_t6_telemetry.gsc', 'tws_t6_join.gsc', 'tws_t6_leaderboard.gsc', 'tws_t6_bank.gsc')
if (@(Compare-Object $expected @($files.Name)).Count -ne 0) { throw 'Expected the eight TWS modules: common, HUD, AFK, lock, telemetry, join, leaderboard, bank.' }
$expected = @('tws_t6_common.gsc', 'tws_t6_hud.gsc', 'tws_t6_afk.gsc', 'tws_t6_lock.gsc', 'tws_t6_telemetry.gsc', 'tws_t6_join.gsc', 'tws_t6_leaderboard.gsc', 'tws_t6_bank.gsc', 'tws_t6_moderation.gsc')
if (@(Compare-Object $expected @($files.Name)).Count -ne 0) { throw 'Expected the nine TWS modules: common, HUD, AFK, lock, telemetry, join, leaderboard, bank, moderation.' }
$common = Get-Content -LiteralPath (Join-Path $repo 'tws_t6_common.gsc') -Raw
$functions = @([regex]::Matches($common, '(?m)^([a-zA-Z_][a-zA-Z_0-9]*)\([^\r\n]*\)\s*\r?\n\{') | ForEach-Object { $_.Groups[1].Value })
foreach ($file in $files) {
@@ -32,4 +32,4 @@ foreach ($file in $files) {
}
Write-Output "PASS $($file.Name)"
}
Write-Output 'All eight T6 compile checks and common references passed. Runtime linking/gameplay require Plutonium.'
Write-Output 'All nine T6 compile checks and common references passed. Runtime linking/gameplay require Plutonium.'
+66
View File
@@ -0,0 +1,66 @@
/* TWS moderation 1.0.0: native durable policy, connection-safe actions, HTTPS synchronization. */
#include maps\mp\_utility;
#include common_scripts\utility;
// T6 loader probes main and init; initialize only once.
main()
{
}
init()
{
scripts\zm\tws_t6_common::ensure_config();
level.moderation_ready = false;
scripts\zm\tws_t6_common::register_connect_handler(::moderation_connected);
level thread moderation_loop();
}
moderation_connected()
{
self endon("disconnect");
if (!level.moderation_ready)
return;
moderation_observe(self);
moderationPump();
}
moderation_observe(player)
{
if (!isDefined(player))
return;
guid = player.guid;
if (!isDefined(guid) || (typeof(guid) != "string" && typeof(guid) != "int"))
return;
// Preserve large identifiers as strings; native validation rejects ambiguous inputs.
guid = "" + guid;
name = player.name;
if (!isDefined(name))
name = "Unknown player";
player moderationObserve(guid, name);
}
moderation_loop()
{
for (;;)
{
if (GetDvar("tws_moderation_enabled") == "0")
{
moderationStop();
level.moderation_ready = false;
wait 3;
continue;
}
level.moderation_ready = moderationConfigure(GetDvar("tws_server_id"), GetDvar("tws_moderation_url"),
GetDvar("tws_moderation_token"), GetDvarInt("tws_moderation_generation"));
if (!level.moderation_ready)
{
wait 3;
continue;
}
players = getPlayers();
for (i = 0; i < players.size; i++)
moderation_observe(players[i]);
moderationPump();
wait 0.5;
}
}