feat(rust): chat titles rank twenty-three conditions, and admins name the categories (PLAN_REDESIGNS §5, D172-D175, D209)

- Schema: fourteen title columns on rust_player_wipe_stats (the two
  best_* distances move by GREATEST, the rest are sums), rust_weapon_kills
  (kills by weapon prefab name) and rust_title_categories (the admin's
  title per category). purge.sql drops the two tables.
- Ingest: player.tally's new fields, in one statement per frame, none
  for an older plugin's frame.
- Titles: 23 categories plus playtime, each naming where it is read
  from (a sum, a MAX, npc_kills - animal_kills in signed arithmetic, or
  a named list). The bow/melee/blade/revolver/wood/ore/plants lists are
  one file, applied when a title is read. "NPC kills" ranks human NPCs
  only (D209).
- A rule's text may be empty, meaning the category's title: the rule's
  own, then the admin's, then the default. Typed-only-markup is still
  refused. A rename forgets every server's cached answer.
- Admin API: GET /admin/rust/title-categories and
  PUT /admin/rust/title-categories/:stat (empty text resets); the server
  list returns them too. Swagger fragment and routes.manifest.json
  regenerated (63 routes, against the pinned core).
- Screen: every category in the rule form, the category's title as a
  placeholder, and a Category titles section with Save and Reset.

The weapon lists are unverified until the rig probe runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-09-28 23:32:59 -05:00
parent afb16112b0
commit aea94b5d7a
18 changed files with 1150 additions and 65 deletions

View File

@@ -19,6 +19,11 @@
-- it knows this module registered, because it is the side that knows which
-- registrant owned what.
-- The chat-title conditions (PLAN_REDESIGNS §5). No foreign keys; the stats
-- columns go with their table below.
DROP TABLE IF EXISTS rust_title_categories;
DROP TABLE IF EXISTS rust_weapon_kills;
-- The permission manager, rebuilt (PLAN_REDESIGNS §1). Children before
-- `rust_permgroups`, which they reference.
DROP TABLE IF EXISTS rust_perm_exceptions;

View File

@@ -958,10 +958,13 @@ ALTER TABLE rust_servers ADD COLUMN IF NOT EXISTS wipe_once_at DATETIME NULL;
-- time they are pushed or shown, so nothing rolls them over at a wipe and
-- nothing can go stale (`model/titles`).
--
-- stat `kills` · `npckills` · `playtime`
-- stat one of the category ids in `model/titles/titles.js` (`kills`,
-- `playtime` and, since PLAN_REDESIGNS §5, twenty-two more)
-- top_n 1–10
-- text at most 24 characters, with `[ ] < > { }` stripped on save so an
-- operator's title can carry no markup of its own (§33.4)
-- operator's title can carry no markup of its own (§33.4). Empty
-- means "the category's title" (D175), except for `playtime`,
-- which has none and always carries its own
-- color `#rrggbb`
-- position the operator's order, which is also precedence (D136)
CREATE TABLE IF NOT EXISTS rust_title_rules (
@@ -1163,3 +1166,58 @@ ALTER TABLE rust_servers ADD COLUMN IF NOT EXISTS perm_policy VARCHAR(16) NOT NU
-- `split` (D190 gave a server its own copy of a shared group, and says so in
-- case the change was meant for every server).
ALTER TABLE rust_perm_drift ADD COLUMN IF NOT EXISTS direction VARCHAR(16) NOT NULL DEFAULT 'added';
-- ── The chat-title conditions (PLAN_REDESIGNS §5, D172–D175, D209) ────────
--
-- Twenty-three things a title can rank, counted by the plugin into
-- `player.tally` and kept here as more of the permanent record. They feed
-- titles only: the public leaderboard keeps its columns (§5.5).
--
-- `npc_kills` keeps counting every NPC AND animal, as it always has, so the
-- public NPC column does not change meaning mid-wipe (§5.2). `animal_kills`
-- counts the animals again, and a title's "NPC kills" is the difference (D209).
--
-- Every column is a sum except the two `best_*`, which hold the longest single
-- kill in metres and move by GREATEST at ingest: a tally carries its interval's
-- maximum, and adding two maxima is not a distance.
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS animal_kills INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS headshots INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS best_pvp_m DECIMAL(7,1) NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS best_pve_m DECIMAL(7,1) NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS apc_kills INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS heli_kills INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS crafted_attire INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS crafted_weapons INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS built INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS repaired INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS healed INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS rockets INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS explosives INT UNSIGNED NOT NULL DEFAULT 0;
ALTER TABLE rust_player_wipe_stats ADD COLUMN IF NOT EXISTS missions INT UNSIGNED NOT NULL DEFAULT 0;
-- Every credited kill by the weapon's short prefab name, the name the killfeed
-- already shows (§5.3). Shaped like `rust_gather_totals`, and for the same
-- reason: the bow, melee, blade and revolver lists are applied when a title is
-- READ, so editing a list corrects the whole wipe and a new Rust weapon needs no
-- plugin release.
CREATE TABLE IF NOT EXISTS rust_weapon_kills (
server_id VARCHAR(64) NOT NULL,
wipe_id VARCHAR(48) NOT NULL,
steam_id VARCHAR(32) NOT NULL,
weapon VARCHAR(64) NOT NULL,
kills INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (server_id, wipe_id, steam_id, weapon),
KEY idx_rust_weapon_kills_top (server_id, wipe_id, weapon)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- The admin's title for a category, for the whole site (D175). A row exists
-- only while the admin has one; deleting it brings the module's default back.
-- A rule's own text still wins over both (§5.5), and a rule saved with no text
-- means "the category's title", which is how a rename reaches existing rules.
CREATE TABLE IF NOT EXISTS rust_title_categories (
stat VARCHAR(16) NOT NULL PRIMARY KEY,
text VARCHAR(24) NOT NULL,
updated_by INT NULL,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;