diff --git a/docs/architecture/retail-divergence-register.md b/docs/architecture/retail-divergence-register.md index 5586a14f..86b2f37c 100644 --- a/docs/architecture/retail-divergence-register.md +++ b/docs/architecture/retail-divergence-register.md @@ -491,6 +491,7 @@ equivalence argument (promote to AD/AP) or a fix. | UN-6 | Fixed 200 ms sleep between ConnectRequest and ConnectResponse; retail inserts no delay. Annotated only as "with 200ms race delay"; the 2026-06-04 audit flagged it, the follow-up refuted "forbidden workaround" but wrote no fuller rationale back | `src/AcDream.Core.Net/WorldSession.cs:484` | Presumed ACE port+1 listener race guard — four words, no citation | Every login eats a flat 200 ms; if the race needs longer on a loaded server, the handshake fails intermittently (ConnectResponse ignored → CharacterList never arrives, exit-29 shape) with no retry — a timing constant masking an unconfirmed root cause | (none recorded) | | UN-7 | Outdoor OBJECT point lighting uses `calc_point_light` (wrap/norm + per-channel cap, `~1/d²`) for ALL meshes including static buildings, but retail's object path is unconfirmed — `config_hardware_light` (0x0059ad30) sets D3D-FF point lights (`Diffuse=color×intensity`, `Attenuation=(0,1,0)`⇒`1/d`, `Range=falloff×1.5`, `material.diffuse=white`) yet that math would blow walls WHITE while retail stays DIM, so static buildings may instead use the `SetStaticLightingVertexColors` bake. Model + the brightness-scaling factor both UNRESOLVED (issue #140 / Fix D) | `src/AcDream.App/Rendering/Shaders/mesh_modern.vert` (`pointContribution`); `src/AcDream.Core/Lighting/LightManager.cs` (`SelectForObject`) | Fix A/B ported calc_point_light + per-object selection for objects without confirming retail uses that model for static buildings; cdb captured the D3D-FF path but it contradicts the observed dim result | Outdoor buildings blow out warm near torches (the #140 meeting-hall symptom); whichever model is wrong, the object torch contribution is too strong | `config_hardware_light` 0x0059ad30; `SetStaticLightingVertexColors` 0x0059cfe0; `rangeAdjust=1.5` 0x00820cc4 — see docs/research/2026-06-18-lighting-a7-fixABC-shipped-fixD-handoff.md | | CT-1 | Transcript truncation uses ONE character threshold (10,000) where retail uses two — it beheads to ~7,500 (`0x1D4C`) on passing 10,000 (`0x2710`), so its buffer oscillates between the two. acdream also cuts at whole LINES rather than searching for a newline near a byte offset | `src/AcDream.App/UI/Layout/ChatTranscriptRenderer.cs` (`MaxTranscriptCharacters`, `FirstLineWithinBudget`) | Retail's hysteresis exists to avoid re-trimming an ACCUMULATING buffer on every append; we rebuild the visible list from the log each time, so there is nothing to damp and a second threshold would only make the oldest visible line jump around as messages arrive. Whole-line cutting is what retail's newline preference is trying to achieve — our unit already is the line | acdream shows up to ~2,500 characters more scrollback than retail at the moment retail has just trimmed. Visible only as a slightly longer history; no state, wire or memory effect (ChatLog's own entry cap still bounds the model) | `ChatInterface::TruncateChatLog @0x004F4290`; threshold read at `RecvNotice_DisplayFinalStringInfo @0x004F4640` | +| CT-2 | No client-side chat word filtering. Retail runs every transcript line through a taboo table when the `FilterLanguage` option is on and SUBSTITUTES matches; acdream performs no substitution at all. The option itself is kept and still stores/ships its bit to the server exactly as retail does | `src/AcDream.Core.Net/GameEventWiring.cs` (no filter in the AddText path); option at `src/AcDream.Runtime/Gameplay/CharacterOptionTable.cs` | DELIBERATE PRODUCT DECISION by the user, 2026-08-21: "I do not want any censoring." Not an oversight and not a porting gap | A player who enables FilterLanguage expecting retail's behaviour sees unfiltered text. No state, wire or server-visible effect — the option bit is still sent, so anything the SERVER gates on it behaves normally | `PlayerModule::FilterLanguage` + `TabooTableAdaptor::CheckCensorsW @0x00682A30` inside `ClientSystem::AddTextToScroll @0x00563C50`; matching at `TabooTable::CreateCheckString @0x00681570` / `StringMatchesFilter @0x00681600` | --- diff --git a/docs/plans/2026-08-21-chat-text-tag-campaign.md b/docs/plans/2026-08-21-chat-text-tag-campaign.md index 7b109d0f..cd7ab07c 100644 --- a/docs/plans/2026-08-21-chat-text-tag-campaign.md +++ b/docs/plans/2026-08-21-chat-text-tag-campaign.md @@ -95,12 +95,33 @@ Nothing is user-visible until A4. input to `@tell {LastTeller}, ` on the space keypress (`HandleTextReplacements @0x004F50D0`). The commands already work; the visible expansion does not exist. -- **CT-B3** `FilterLanguage`: retail runs chat text through a taboo table and - substitutes (`PlayerModule::FilterLanguage` + `TabooTableAdaptor:: - CheckCensorsW` inside `AddTextToScroll`). We store the option, ship the bit, - show it in Options — and never filter. A decorative toggle. +- **CT-B3** ~~`FilterLanguage` word filtering~~ — **DROPPED by user direction + (2026-08-21): "I do not want any censoring."** acdream keeps the option + itself, which still stores and ships its bit to the server exactly as retail + does, but performs no client-side substitution. Registered as CT-2 rather + than left as an implicit gap, since it IS a knowing departure from retail + (`PlayerModule::FilterLanguage` + `TabooTableAdaptor::CheckCensorsW + @0x00682A30` inside `AddTextToScroll`). + + Worth keeping on record, because the attempt established two things that + would otherwise be rediscovered if this is ever revisited: + + 1. The table's dat id is not readable from the decomp — `CheckCensorsW` + reaches it through `DBObj::GetByEnum` with the arguments elided by Binary + Ninja. The portal master enum map (`0x25000000`) has 22 categories, with + category 3 (`0x0E010001`, `0x0E010002`) and the single-entry categories 8 + and 11 the plausible candidates. + 2. Chorizite.DatReaderWriter declares a `TabooTable` type but does NOT decode + it — only `DBObjType` and `HeaderFlags`. The format would have to be + decoded here first. + + And the matching is an algorithm, not a word list: + `TabooTable::CreateCheckString @0x00681570` normalises a candidate before + `StringMatchesFilter @0x00681600` compares it, which is how retail catches + obfuscated spellings. - **CT-B4** The plain-text session chat log (`ClientSystem::s_pLogFile`). We - write none. Path and rotation are UNKNOWN — needs research or a live check. + write none. **Research-blocked**: path and rotation are UNKNOWN and are not + in the decomp — needs a live check or a dat/filesystem probe. ### Group C — chat GUI