# Persistent AFK reserve AFK `2.0.0` replaces unlimited protected breaks on both T5 and T6. A GUID owns one free allowance and saved reserve across servers, games, maps and reconnects. Electric Cherry owns balances, policy, purchase transactions and the time ledger. The game owns verified contribution events, player commands, countdown rendering, protection and accepted stop decisions. This uses the existing bank account and private instance credential, not a second points bank. ## Commands and behavior | Command | Result | | --- | --- | | `.afk` | Reserve available time, acknowledge its start, then enter protected AFK | | `.back` | Stop time accounting and return, preserving the existing two-second manual grace | | `.afk balance` | Show free, saved and currently reserved seconds as a clock | | `.afk buy 10` | Quote ten minutes and its bank-point price | | `.afk buy 10 confirm` | Accept that quote within 30 seconds | Return with `.back` before purchasing; an existing reservation never extends automatically. Purchases require whole policy packs; the initial pack is 10 minutes for 10,000 points. There is no automatic purchase. EC atomically rejects insufficient funds, pending bank transfers, changed quotes and over-capacity purchases without a point debit. A submitted purchase retains its ID until EC acknowledges it. The central countdown and “Protection ends when this timer reaches zero.” remain visible even with `.hud` hidden. The final minute is larger and red; warnings sound at 60, 30, and each of the final ten seconds. At zero, AFK protection ends immediately, including in the damage callback; the script restores its own controls, weapons and zombie-targeting state. Expiration has no spectator transition, purchase or extra grace. Repeating `.afk` does not restart the timer or reserve twice. AFK `2.1.0` allows solo players and the last active player to enter; all players may be AFK at the same time. Entry still rejects downed/dead/spectating players and stock protection/control restrictions. A default 15-second reentry cooldown prevents repeated combat toggles. Manual `.back` retains a separate two-second grace. The AFK damage callback passes through when it does not own protection, preserving stock game invulnerability. Other mods that restrict controls should set `player.tws_afk_external_controls` while their restriction applies. AFK leaves player session state unchanged, so stock player-count zombie scaling continues to include AFK players. Losing the last non-AFK teammate does not end protected breaks or force a match end. Authorized time continues to count down; normal expiration and stock match-end cleanup still apply. Verify these rules on each deployed map/mode. ## Rewards Initial EC policy: | Source | Time | | --- | --- | | Free allowance | 30 minutes per rolling 24 hours | | Five minutes of active play | 1 minute | | Completed round with participation | 15 seconds | | 100 kills | 30 seconds | | 25 headshot kills | 15 seconds | | Each successful teammate revive | 30 seconds | Saved earned and purchased time has a combined six-hour capacity and no expiry. Free time is separate, non-accumulating and consumed first. EC retains fractional reward progress across reconnects. Round/kill/headshot rewards share eight minutes per rolling active hour; headshots stack with kills. Active-play rewards and **every successful revive** are outside that cap. There is no per-teammate, per-match or hourly revive limit. Retrying a report cannot award it again. Both engines consume stock `zom_kill`, `player_revived` and `end_of_round` notifications. T5 also attaches to stock hellhound spawn/death callbacks because those enemies omit `zom_kill`; T6 hellhounds already emit the stock zombie death event. Completed round numbers are deduplicated locally. Headshots require a lethal head/helmet hit with a qualifying damage type. No reward uses spendable score or `score_total`. A round requires a kill, revive, or at least 30 seconds of active engagement and eligibility at completion. The one-second activity sampler uses movement over four units, a view change over two degrees or a changed input button to refresh a 15-second engagement interval. The stock `is_reviving` state counts support; holding a zombie that targets the player within 512 units counts while deliberate input occurred in the last 60 seconds. Kill/revive events also refresh engagement. AFK, dead and spectator time do not earn rewards. Contributions after manual `.back` count immediately, including during its separate two-second grace. This permits support and zombie holding without a minimum kill rate, while passive connection alone earns nothing. Stock integration was checked against [T5 scripts 70689b8](https://github.com/plutoniummod/t5-scripts/tree/70689b8288e60079d48926657e670c41aab4abdf) and [T6 scripts 2d84403](https://github.com/plutoniummod/t6-scripts/tree/2d8440321602f22f63f5335817110d60ddf223d5). Recheck callback contracts if the stock runtime changes. ## Configuration and coordinated rollout 1. Back up EC and the game runtime journals. Deploy EC #151 and restart its service. 2. Update all EC host agents to **1.12.0+** before enabling these scripts. This adds AFK settlement before deleting/rebuilding stopped runtime storage. 3. Build and install TWS `t5-plugin` and `t6-plugin` **1.4.0+** and matching AFK **2.1.0** scripts. Require common **1.4.0+**, telemetry **1.0.0+**, and Plutonium **r5334+** for `SetTextUnlimited`. Fully restart game-server processes. 4. Retain EC's private `tws_bank_token` and exact `tws_server_id`; telemetry must establish the current match before AFK commands can be authorized. 5. Keep `tws-afk/t5/` and `tws-afk/t6/`, relative to the process working directory, on persistent writable storage with one process per server/endpoint scope. Upgrading AFK scripts from `2.0.0` to `2.1.0` adds no dependency requirement: copy the matching script for each game and restart the map. No full server-process restart is required for this script-only update. | Game dvar | Default | Meaning | | --- | --- | --- | | `tws_afk_enabled` | enabled | `0` disables new AFK service startup | | `tws_afk_cooldown_seconds` | `15` | Reentry cooldown, clamped to 2–300 seconds | | `tws_afk_warning_sound` | `zmb_perks_packa_ready` | Local warning sound alias; verify on deployed maps | Economic configuration lives in EC's `EC_AFK_*` environment settings. See the [EC AFK guide](https://gitea.thewrightserver.net/josh/electric-cherry/src/branch/main/docs/guides/afk.md) for exact rates, rolling-window accounting and JSON schemas. The fixed game endpoint is `https://ec.thewrightserver.net/api/afk`; requests reuse the private `ec_bank_` credential. Shared telemetry tokens cannot spend or reserve time. ## API and recovery ownership The matching native API `1.0.0` exposes `afkVersion`, `afkResponse`, `afkStore`, `afkLoad`, `afkRemove`, `afkPrepare`, `afkAuthorize`, `afkBegin`, `afkRemaining`, `afkCheckpoint`, `afkStop`, and `afkRecover`. Responses must validate their complete schema and request/session identity before authorization takes effect. Requests are immutable; journal writes precede network transmission and native activation. EC actions are `balance`, `event`, `purchase`, `reserve`, `start` and `settle`. Events carry cumulative counters scoped to GUID, instance and match, with a monotonic sequence. The native journal coalesces newer cumulative event snapshots to bound outage queues; EC prevents retries and reordered reports awarding twice. Revive counts still increase for every distinct successful revive. Kill/active progress is flushed at most every 30 seconds and on normal disconnect/end; a hard process crash can lose progress that had not yet reached the local journal. Already accepted rewards and journaled snapshots persist. Protection starts only after reservation and start acknowledgments, a final player-state recheck, and a durable native clock start. Once authorized, an EC outage cannot shorten protection; a local monotonic deadline still ends it at zero. Manual return, disconnect, death and match end stop accounting immediately. A failed stop-journal write freezes the original stop time for retry rather than charging during the delay. Never replay a reserve/start from a background sender. Before activation, an interrupted session recovers as `never_started` with zero consumption. Its tombstone also blocks delayed reserve/start delivery. After activation, a crash with no durable stop becomes `unresolved`, preserving its last confirmed checkpoint and full reservation. Absence of a heartbeat never releases spendable time. An administrator must reconcile such a stopped session using EC's audited correction endpoint; corrected charges remain distinct from exact durations. Do not delete journals or change IDs to unblock a hold. The EC agent independently proves the old process is stopped before recovering journals during remove/rebuild/cancel-create. It sends requests only to its enrolled controller using the assigned teardown operation and host credential. Lost replies, unrecognized endpoints or malformed journals preserve runtime storage for retry. ## Validation Portable checks (engine shims are not live Plutonium): ```sh node tools/check_afk.mjs python3 tools/test_plugin_afk.py --json-header /path/to/pinned/json.hpp node tools/check_bank.mjs node tools/check_hud.mjs node tools/check_telemetry.mjs ``` Use each plugin's pinned JSON header; the native harness also accepts a path with `{game}` for different T5/T6 dependency revisions. It compiles native utilities and actual registration adapters with ASan/UBSan, then exercises separate-process journal recovery. T6 source compilation follows its [script instructions](../t6/scripts/README.md#validation). T5 linking and behavior require a live server. Before production activation, validate **both engines**: - Enter/return/expire, reconnect, die, change maps and restart the process; compare the displayed countdown and EC balances/ledger. At expiry attempt moving, firing, throwing equipment and receiving zombie damage immediately, including `.hud` off. - Try T5 entry while downed, then after a successful revive. Check T6 laststand, afterlife, intermission and stock control restrictions; no stock protection should be removed. Repeat rapid `.afk`/`.back` and concurrent commands during slow replies. - Earn each reward; revive the same teammate repeatedly beyond the performance cap. Verify passive, spectating, AFK and bank point changes earn nothing. Test support and zombie holding. Carry partial progress across maps/servers/T5/T6. - Confirm the displayed purchase price; try expired/changed quotes, insufficient bank funds, pending bank transfers and capacity overflow. Drop purchase replies and retry without a second debit. Attempt simultaneous reservations on two servers. - Disconnect EC after authorization; the countdown must continue and expire locally. Drop reserve/start/stop replies, reorder delivery, fill/fail journal storage, and restart. Verify never-started refunds, durable exact stops and unconfirmed crash holds. Correct only a proven stopped session and confirm the ledger audit. - Enter as the only connected player and as the last active player with downed, dead, spectating or AFK teammates. Put every player in AFK. Kill/disconnect the last active teammate, including while reserve/start replies are pending; verify protection continues without a forced match end. Check solo return/expiration, normal stock match-end settlement, afterlife/Grief recovery and zombie scaling. - Rebuild/remove with journals from both games, retire the instance credential, interrupt the agent after a lost reply, and retry. Runtime deletion must wait for acknowledged recovery and cannot authorize a new purchase. Validation performed for the initial `2.0.0` change: 39 AFK behavior checks, 14 core HUD and 56 service HUD checks passed. All nine T6 scripts compiled and assembled with the upstream [gsc-tool compiler 8f1d6bd](https://github.com/xensik/gsc-tool/tree/8f1d6bd4d51efdc619629b9254fb439427a6d306) using its T6 PC compiler/assembler library in a temporary local driver. No Windows DLL build, production deployment or live T5/T6 validation is implied by these checks.