diff --git a/android/PLAN.md b/android/PLAN.md index b195e1e..4afac85 100644 --- a/android/PLAN.md +++ b/android/PLAN.md @@ -1639,6 +1639,83 @@ push, and Play (M6–M8) follow the designed app. Excluded: the rules, the mode and group styles, which are all operator configuration. +21. **M20 — the app's words for every game** (post-v1; planned 2026-10-23, to land in `edge` + **before** the `edge` → `main` release that first ships the Rust screens). This is the app's + half of the vocabulary rule the website docs and runicgateway.com already follow + (runicgateway.com `PLAN.md` §16, D63/D64). Each game's words stay on that game's screens, and + the screens every deployment shows use core words. Found while capturing runicgateway.com's + phase 18 screenshots on the emulator: the first screen a Rust community's player sees says + *Connect to your shard*, and the next one says *Sign in with your shard account*. The org lead + took four decisions on 2026-10-23: + + - **Core screens only.** The UO screens keep their words, as the site's game sections do: + the shard hub, guilds, champion spawns, governors, falling houses, the market, the shard's + ruleset, *My characters / vendors / houses*, their push streams, and staff moderation + through the shard. Code identifiers (`ui/shard`, `Shard*` classes, `shard_*` keys) are + **not** renamed: that would be a large diff with no visible change. + - **A guard**, so the words cannot creep back: a JVM unit test in the existing + `./gradlew test` step (see *The guard* below). + - **It lands before the release**, so the first build with Rust screens doesn't greet a Rust + community with a UO word. + - **Weapon names come from the module.** Module-Rust's events now carry `frame.weaponName` + (Module-Rust#60, `server/model/titles/weaponNames.js`): the game's own name for a ranged + weapon, or the prefab name as words. `RustFeed.kt` prints it, and against an older module + falls back to `prefabName()` with the `.entity` / `.weapon` ending dropped. So the app never + prints "with ak47u entity", as it does today. + + **Measured on `edge` (2c8ab39):** 576 strings, every visible one in `res/values/strings.xml` + (no hard-coded Compose text). 60 of them carry a game word, and about 16 of those are on + screens any deployment shows: + + | String | Today | Becomes (core words, as the site uses them) | + |---|---|---| + | `connect_title` | Connect to your shard | Connect to your community | + | `connect_subtitle` | Enter your shard's website address… | Enter your community's website address… | + | `connect_url_hint` | https://your-shard.example.com | https://your-community.example.com | + | `connect_error_not_runic` | That site isn't a Runic Gateway shard. | That site isn't a Runic Gateway site. | + | `login_subtitle` | Sign in with your shard account. | Sign in with your account on this site. | + | `error_shard_offline` | The shard is offline right now. | The game server is offline right now. | + | `error_feature_unavailable` | This shard doesn't publish this here. | This site doesn't publish this here. | + | `notifications_subtitle`, `_empty`, `_unsupported`, `_relay_error` | This shard… | This site… | + | `push_channel_messages`, `_desc`, `push_service_text` | Shard notifications… | Notifications from your community… | + + The list is a starting point, not the verdict. **Each string is classified by the screens that + use it**, traced in code: a string any screen a Rust deployment can reach shows is core, even + if its key says `shard_`. Two need the trace before they move. `error_shard_offline` is the + shared "server down" text (`ApiResult` offline) that both games' screens use, so it is core. + `push_stream_server_status` ("Shard status changed") is core if the stream catalog offers it + for every module. + + **The guard.** The strings are split by owner into three resource files that Android merges + as one: `values/strings.xml` (core), `values/strings_uo.xml` and `values/strings_rust.xml`. + No key changes, so no Kotlin changes. A unit test reads the three files and fails, naming the + key and the word, when: + - the core file holds either game's word; + - the UO file holds a Rust word; + - the Rust file holds a UO word. + + The word list is runicgateway.com's `checkTerms.mjs` list: *shard, guild, IDOC, ServUO, …* for + UO; *clan, wipe, Oxide, Carbon, uMod, rust-link, …* for Rust. Its one allowlist entry + (Discord's *guild ID*) carries over only if the app ever shows it. Splitting by file rather + than by key prefix keeps the rule visible where a translator or a new screen adds a string, + and needs no prefix list to keep in step. The alternative, one file and a prefix allowlist, + is what the decision named; the split does the same job, so it is the plan unless review + objects. + + **One PR into `edge`**, with the steps in this order: + 1. The trace and the split, with no text changed, so the diff shows only moves. + 2. The core rewording. + 3. The guard test. + 4. `weaponName` in `RustFeed.kt`, with a DTO test against an older module that sends none. + + **Walked on the emulator** against both demo deployments before the PR: the UO one (rgdemo) + and the Rust one (rgdemorust). First run, sign-in, the drawer, notifications, and a server + down are checked on each. + + Excluded: the website's own leftovers listed in website#221 (`PlayerInbox.jsx`, `Events.jsx`, + `PlayerNotifications.jsx`, `coreTriggers.js`, `templateSeeds.js`), which belong to `website/`, + not the app. + ### Deferred (not a milestone) - **Platform Teams in the app** — **deferred 2026-08-17, no app work scheduled.** The website is diff --git a/modules/rust/PLAN.md b/modules/rust/PLAN.md index fb1e280..05ab84a 100644 --- a/modules/rust/PLAN.md +++ b/modules/rust/PLAN.md @@ -6998,6 +6998,29 @@ permission and group, not only those it authored. They are planned in their own describes: the permission manager, the event step editor, zone options and domes, the map's marker types and the chat title conditions. The Carbon pass is still to be walked and may add to it. +## 36. Weapons by name in the feed (2026-10-23) + +The feed printed a kill's weapon as **"with ak47u entity"**. The bridge names the weapon by the held +entity's short prefab name (`ak47u.entity`). That is the right key for the title lists, which count +kills by it (§5.3, `server/model/titles/lists.js`), but the wrong thing to print, and the site and +the app printed it with only the dots turned to spaces. Found while capturing runicgateway.com's +phase 18 screenshots. The org lead chose a table of the game's own names with a stripped fallback, +kept once on the server (Module-Rust#60): + +- **`server/model/titles/weaponNames.js`** names the 53 ranged weapons (guns, bows, crossbows, + launchers, flamethrowers) as the game does: `ak47u.entity` → *Assault Rifle*, `mp5.entity` → + *MP5A4*. It was read off the Oxide rig's item list on Rust 26139947 by the same read-only walk + `lists.js` came from, not written from memory. Anything else falls back to the prefab name as + words, without its `.entity` / `.weapon` ending: `salvaged_sword.entity` → *salvaged sword*. +- **Every event read adds `frame.weaponName`** (`events.model.js` `shape()`). It's added at read, + so stored rows are renamed too, and editing the table renames every kill the feed still shows. + `frame.weapon` is unchanged. +- **The site prints `weaponName`**, and the app does from M20 (`android/PLAN.md`). Each falls back + to the same stripping against a module too old to send it. + +**No protocol change:** the frame on the wire is as it was, and only the module's read adds the +field. To refresh the table after a Rust update, walk the item list again. + [kit]: https://gitea.whitlocktech.com/RunicGateway/Integration-kit [protocol]: ../../rust-link/PROTOCOL.md [pw]: ../../rust-link/PLAYER_WALK.md