diff --git a/Cargo.lock b/Cargo.lock index 1b03558c..fd91f862 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -536,6 +536,7 @@ dependencies = [ "objc2-foundation 0.2.2", "rand 0.8.6", "raw-window-handle", + "regex", "rtrb", "serde", "smithay-clipboard", diff --git a/crates/benilla-app/Cargo.toml b/crates/benilla-app/Cargo.toml index dba96a5c..b8f530f9 100644 --- a/crates/benilla-app/Cargo.toml +++ b/crates/benilla-app/Cargo.toml @@ -58,6 +58,11 @@ half = "2" # macro plus a no-dependency runtime shim — it adds nothing to the graph at runtime, and it is the # crate everyone uses for this. `assets/ui` is OUR content (MIT/Apache), not Blizzard's. include_dir = "0.7" +# The 1.12 chat filters are PCRE over shipped DBCs (decision 2077; `text_filter`): 2289 profanity +# expressions and 28 spam ones, compiled once at startup and run over every chat line. `RegexSet` is +# exactly the shape that needs — one automaton over the whole list for the "can anything match at +# all" pass — and the crate is already in the tree transitively. +regex = "1" # `getrusage` — whole-process CPU time (all threads), the perf probes' `cpu_ms`/`cpu_pct` metric # (`perf::process_cpu_secs`). Wall-clock fps is unusable as a regression instrument on a machine # running parallel sessions' builds; CPU-per-frame is, and it is also the number the Mac report diff --git a/crates/benilla-app/assets/ui/OptionsFrame.xml b/crates/benilla-app/assets/ui/OptionsFrame.xml index e1544e23..f5dd916f 100644 --- a/crates/benilla-app/assets/ui/OptionsFrame.xml +++ b/crates/benilla-app/assets/ui/OptionsFrame.xml @@ -295,6 +295,31 @@ end end + -- ── Show Tutorials' SETTER: the reference's own Save arm (decision 2077) ──────────── + -- UIOptionsFrame.lua l.318-327, verbatim in behaviour. Its CheckButtons row is a bare + -- `{ index = 28 }` with no cvar and no uvar, which is why decision 1140's census filed it + -- as an "index-only entry with no store at all" and left it out; that reading is wrong. + -- The store is not in the TABLE, it is in the three special-case arms `UIOptionsFrame_Load` + -- (l.239), `_Save` (l.318) and `_SetDefaults` (l.645) keep for this key — the getter is + -- `TutorialsEnabled()` and the setter is the Reset/Clear pair, because "disable tutorials" + -- in 1.12 literally means "mark every bit of the acknowledged bank", not a CVar (1976; + -- wow-re censused all 210 `CVar::Register` sites and there is no tutorial CVar). + -- + -- The `~=` guard is the reference's and it matters: `TutorialsEnabled()` returns the NUMBER + -- 1 or nil, so re-ticking an already-on row does not re-`ResetTutorials()` — which would + -- re-arm every tutorial the player has already dismissed. + function OptionsFrame_SetTutorialsEnabled(value) + if ( tonumber(value) ~= TutorialsEnabled() ) then + if ( value == "1" ) then + ResetTutorials() + TutorialFrameCheckButton:SetChecked(1) + else + ClearTutorials() + end + TutorialFrame_HideAllAlerts() + end + end + UIOptionsFrameCheckButtons = { }; ------------------- Basic Options ------------------- -- Controls @@ -927,7 +952,12 @@ -- reference's own on-screen order. Its Basic Options Display box is three COLUMNS read -- left to right: A gives Status Text (CheckButton2), B gives Show Cloak → Show Helm -- (31 → 20, sitting under the name toggles that live on our Nameplates page), C gives - -- the 42 → 39 → 66 chain. Help (29) closes the page, as before. + -- the 42 → 39 → 66 chain. The **Help** box closes the page, and since 2077 it is + -- the box's own order rather than its one shippable row: 28 (Show Tutorials), 44 + -- (Show Loading Screen Tips, anchored under 28 there) then 29 (Show Detailed + -- Tooltips). 28 was left out by 1140's census as an "index-only entry + -- with no store at all"; that reading missed the three special-case arms + -- `UIOptionsFrame_Load`/`_Save`/`_SetDefaults` keep for the key, which are its store. -- The target-of-target pair (decision 1576) breaks that left-to-right reading, and -- it has to: 1.12 keeps it in a box this window has no page for — Advanced Options' -- "Raid & Party" — so there is no column order to preserve, only a neighbour to pick. @@ -936,7 +966,8 @@ "RowStatusText", "RowTargetOfTarget", "RowTargetOfTargetMode", "RowShowCloak", "RowShowHelm", "RowInstantQuestText", "RowBuffDurations", "RowAutoQuestWatch", - "RowNewbieTips", + "RowProfanityFilter", + "RowShowTutorials", "RowTipOfTheDay", "RowNewbieTips", }, -- 1.12's Advanced Options **Chat** box (decision 1589, B246 — "no chat section in -- options"). The page was called `Social` and held exactly the two chat-bubble @@ -954,17 +985,17 @@ -- · 51 Auto-join Guild Recruitment Channel — carries **no cvar, uvar or func in the -- reference either** (UIOptionsFrame.lua l.51 is a bare `{ index = 51 }`), so -- it is inert there; a working row here would be an invention, not a fix - -- · 68 Disable Spam Filter — benilla filters no chat text. Unlike 51 this is a REAL - -- omission and not an inert row: `spamFilter` is registered "1" at `0x402e8e` - -- with a change callback, and its one reader is the chat chokepoint `0x49a870`, - -- which drops a `CHAT_MSG_FILTERED` line on a word-list hit unless the type is - -- whisper (§5, wow-re `system/ui/scratch/spam-filter-cvar.md`). The row lands - -- with the filter. + -- Row 68, Disable Spam Filter, **shipped by 2077** — and the note it replaces was + -- wrong twice over, both corrected at the bytes by wow-re's `text-filter-law.md`. + -- The filter is not a word list, it is 28 compiled PCRE patterns from + -- `SpamMessages.dbc`; and it does not drop `CHAT_MSG_FILTERED` lines, it is armed for + -- every type EXCEPT that one (`0x49aad2`'s `jne` skips the disarm, which the older + -- note read backwards). It drops a matching line silently, with nothing in its place. -- 1139's note about the 37 → 46 → 38 gap is closed by this record: 46 is Loot Spam, -- and it has a knob now. Chat = { "RowGuildMemberAlert", "RowRemoveChatDelay", "RowChatBubbles", "RowLootSpam", - "RowPartyChatBubbles", + "RowPartyChatBubbles", "RowSpamFilter", }, -- 1.12's Advanced Options "Action Bars" group, whole (decision 1500 completing 1136). -- Its six rows, the four bar toggles then the grid switch then the lock. That is the @@ -3367,11 +3398,74 @@ "Automatic Quest Tracking", "OPTION_TOOLTIP_AUTO_QUEST_WATCH") - + + + OptionsRow_OnLoad(self, "profanityFilter", "Profanity Filter", + "OPTION_TOOLTIP_PROFANITY_FILTER") + + + + + + + + + + OptionsFuncRow_OnLoad(self, TutorialsEnabled, + OptionsFrame_SetTutorialsEnabled, "1", + "Show Tutorials", "OPTION_TOOLTIP_SHOW_TUTORIALS") + + + + + + + + + OptionsRow_OnLoad(self, "showGameTips", + "Show Loading Screen Tips", + "OPTION_TOOLTIP_SHOW_TIPOFTHEDAY") + + + + + + OptionsGlobalRow_OnLoad(self, "SHOW_NEWBIE_TIPS", "Show Detailed Tooltips", "OPTION_TOOLTIP_SHOW_NEWBIE_TIPS") @@ -3481,6 +3575,34 @@ "Show Party Chat Bubbles", "OPTION_TOOLTIP_PARTY_CHAT_BUBBLES") + + + + + + + + OptionsRow_OnLoad(self, "spamFilter", "Disable Spam Filter", + "OPTION_TOOLTIP_DISABLE_SPAM_FILTER") + self.invert = 1 + +