e436a4e79f43ab894a86cc8d45e5ddf917a136ca
325
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e436a4e79f |
Must be in names its form, and the whole client builds headless
- a cast refused for the wrong shapeshift form names it, "Must be in Cat Form", a two-form spell joined the reference's way, and the combat log reads its own buffer rather than the red line (2280, 2285) - three refusals that never had a combat-log line, totems, reagents and equipped item class, get one; a pet's form refusal names one form (2285) - the game's plugins are one group and the whole client builds headless in 0.12 s, so the schedule is a test subject: three one-shot consumers caught firing into the login drain are gated (2279) - the net drain's parameters are named bundles, not nested tuples (2279) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
8562fb0ef1 |
a crash leaves a report, and the wire's counts are capped
- a panic writes benilla-config/Diagnostics/crash-<time>.txt with the build id, the location, a backtrace and the last 200 log lines, and names the file as its last line, so a bug report can attach it (2266) - every wire-count allocation hint is capped and the compressed update object reads through the cursor, so a malformed packet can no longer ask for gigabytes (2266) - the 23 in-world run conditions are one set, the 45 probe variables one registry, the install-gated tests say when they skip, and every gate is timed (2266) - one workspace-level lint allowance replaces 413 per-site attributes, and the decision corpus gets a lint in the gate (2266) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
8f8fb1e08c |
your own name survives the first login, and four cold pipelines warm
- your character's own name no longer goes missing on the first login of a fresh start, so KLHThreatMeter stops erroring: the four "player" verbs read the login record, as the reference does (2260, 2261, 2263) - four pipelines that compiled live mid-play now warm under the loading screen: the model tile atlas's orthographic view, the minimap composite's quad, the glow combine pair and the indoor pool's liquid layout (2262, 2264) - a hoverable sign seats its tooltip where its template says, at the cursor or in the corner, not by its object type: Brill's signpost still follows the cursor (2259) - three warnings that fired when nothing was wrong are quiet, and the lane-coverage gates walk every crate instead of one (2264) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
66388278d4 |
entering the world no longer crashes on Linux and Windows
- entering the world no longer aborts on Vulkan, which is every Linux build and Windows by default: the world's draw inside the UI pass had opened a second GPU query span, and wgpu allows one at a time (2258) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
60bb2e3d6d |
a nameplate takes a right-click, and four wrong verb rows come off
- a right-click on a nameplate selects and interacts again: the plate registers the right button, as the reference's does (2233) - the verb-events table files each fire site against its function's verified extent, and four rows it had misattributed are gone (2257) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
5c9d919a0c |
signpost tooltips survive the map, and the quest log stops blanking
- a signpost or mailbox tooltip shows with Questie loaded, and after opening the map: the cursor-seated plate carries an owner, so Questie's OnShow hook no longer hides it (2255) - picking up a quest whose template is not cached no longer blanks the quest log or jumps the selection: the missing quest is skipped, not the pass (2256) - the spellbook's skill-line tab flashes when a spell lands in it (2252) - the GPU meter's resolve rides the frame's own encoder, with no submit or poll of its own: −1.8 ms on Intel's DX12 driver when armed (2254) - the audio starvation watch no longer charges a stream's own spin-up as silence (2253) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
f2377ec846 |
every objective line shows, the detail follows the row, and 1.98 lints
- a quest objective that carries both a creature and an item is two lines in the quest log, as the reference's four passes enumerate it: Graverobbers shows its Embalming Ichor (2249) - the quest log's detail follows the live selection inside a frame, so a quest addon's log walk reads the right quest; Questie no longer files a chain quest under its shortest sibling (2247) - a UI tint change is not a material change: a run's colour rides the batch's instance tag, so the PlayerFrame glow no longer re-prepares a material every frame (2245) - the workspace lints clean on rustc 1.98: constant-size chunks become as_chunks, one slice fill, two unused globs - WOW_HOVER_PROBE aims the pick in a headless run, and the inspect card names the tooltip's ladder stage (2248, 2250) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
b91ad0a11c |
learning a spell says so in chat, and the map's backdrop is back
- learning a spell prints "You have learned a new spell/ability/recipe" in chat, and unlearning one prints its line, on the reference's own gates (2243, 2246) - the world map's dark backdrop is back: the screen size is seeded before the interface loads, so BlackoutWorld is sized from the real window, not 1024x768 (2242) - the trainer filter repaints again: the engine fires TRAINER_UPDATE from inside the filter verbs, as the reference does (2244) - the zone channels, the keybinding table and the default language seed at the entry edge, before any addon asks (2241) - WOW_UI_COST=1 counts the frame's UI material asset events and names the first hundred modified (2236) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
b0082b6668 |
the world draws inside the UI pass, and Questie's zone table fills
- the world is the first draw of the UI camera's main pass, not a pass before it: one render-pass boundary fewer, −0.9 ms of GPU on the Air at full render scale (2234) - the world-map catalog seeds at the VM's birth, before any addon file runs, so Questie's Astrolabe builds its zone table instead of raising on every path (2240) - the login's own tutorials wait for the interface, and a cross-map worldport fires PLAYER_LEAVING_WORLD, guarded by the reference's once-per-world latch (2232, 2235, 2239) - WOW_PROBE_BGQUEUE makes "log in while queued for a battleground" reproducible (2237) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
16abf643b1 |
the world gets its own Lua state, and the trainer follows the spell
- entering the world builds its own Lua state instead of adopting the character screen's, so a login one-shot fired into the frameless glue VM is spent again against the interface (2226) - after training, the trainer's detail pane moves on: the selection is the service's spell id, re-found by scan, and a filtered row is hidden, not removed (2231) - a spell's miss or resist floats in spell gold, and a travelling spell's word waits for the projectile; only a white hit's miss is white (2229) - a press that lands on a nameplate is the plate's: no freelook, no camera turn, the plate's own click slot (2233) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
37e55168c2 |
right-click works on a nameplate, and the honor tab names your rank
- right-clicking a nameplate acts again: both buttons read the press pick, as the reference picks once on the down edge and never re-picks on release (2230) - the honor tab's Highest Rank and title name the rank: a rank title's team digit is the race, not the faction group, so a GM-flagged character keeps its rank (2227) - a raid's party feed watches only its members' descriptors, and the empty 2D opaque pass is skipped: ~0.7 ms a frame in a crowd (2225) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
0cc11b66a0 |
names are a session, Martin Fury fires, and Windows gets its clocks
- player and pet names are a world session, not a file: the reference never persists them, so a character created after a server wipe no longer wears a deleted character's name (2223) - Martin Fury and every item whose spell targets where you stand raise the cursor and cast: the targeting word is a mask, not one bit (2218) - the guild line prints ahead of the realm's welcome lines by declared order, as the reference's chat latch paints it (2221) - the performance journal's CPU clocks answer on Windows, and a run with no install no longer panics on the cinematic narration (2219) - SetInventoryItem's nameOnly argument builds the reference's compact tooltip (2224) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
b44c3923e4 |
the guild MOTD prints at login, and a maximize no longer crashes
- the "Guild Message of the Day:" line prints in chat at login: our own guild id arriving is not a guild change, and the guild feed waits for the interface it fires into (2214) - maximizing or resizing the window after entering the world no longer crashes the client: the dismissed loading tip asks for a re-shape (2212) - the vendor's compare plate is the worn item's full tooltip with one gray "Currently Equipped" line first, its name in its quality colour (2216) - the login chat drain waits for the chat frame it prints into, so a realm's welcome line is never lost one login in six (2220) - the GPU meter never resolves a query set nothing has stamped yet — the Vulkan device loss and hang the lab met (2211) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
f958f800dd |
no hover compare, UnitIsPlusMob answers, and $parent names land right
- the shift-hover item compare is gone: 1.12.1 compares only from the vendor and auction rows, and the plate those seat picks its side so it never slides back over its own tooltip (2210, 2207) - UnitIsPlusMob is implemented, off the flag bit and not the creature rank, so an addon that calls it no longer raises (2209) - a top-level frame named $parentX with a parent= attribute is published under that parent's name, so ClassIcons loads (2208) - a parent= that resolves to nothing leaves the frame parentless and logs it, as the reference does, instead of falling back to the enclosing frame (2213) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a255b93504 |
a chest fades out, a held key survives an alt-tab, the blits go
- a looted chest fades out over two seconds on the reference's own smoothstep, from the alpha it is showing, instead of blinking away; every destroy and out-of-range exit takes the fade (2198, 2203) - opening a chest goes through the cast ladder, so mashing right-click no longer cancels the running cast bar with "Another action is in progress" (2199) - a held key resumes after an alt-tab: a repeat is a key we already have down, not the OS repeat bit, as the reference classifies it (2204) - both upscaling blits are skipped: the world's combine and the UI's gamma decode write their camera's target themselves, pixel-identical, and the costliest pass on the lab's RTX is gone (2206) - WOW_GPU_PASSES prints the journal's per-pass GPU split beside each row (2205) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d41ebdd642 |
eighteen no-op writes gated, and the dead-gate finder
- eighteen per-frame systems now write only when their inputs moved: the equipment resolve, the skills, language and bind-location feeds, quest markers, shadows, the ambience seat and the weapon trail (2197) - a still remote mover writes no transform, so a city's idle crowd no longer re-propagates every model subtree each frame, and the WMO liquid latch no longer holds a city's visibility walk open (2197) - the bags are walked once a frame for every reagent and item slot instead of once per slot, and fourteen per-frame environment reads become one read each (2197) - the ffx blur chain is skipped where the combine multiplies it by zero, the audio pump compares before set_volume, and the QoS latch sits beside bevy's own exclusive system (2197) - WOW_RES_CENSUS counts on how many frames each resource read as changed, noisiest first — the finder that named these gates (2197) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
46673c3f08 |
loot rows wear their art, W holds through chat, and food greys in combat
- loot rows show their Quickslot border, depress on click and light up under the cursor: the stock `<LootButton>` is parsed by the Button loader, as the reference's vtable has it (2195) - holding W keeps you running through Enter to chat and M to close the map: a UI frame eating a key never releases a held movement binding (2196) - food, drink, bandages and mounts grey out on the action bar in combat: an ITEM slot runs its on-use spell's usable walk, and its cooldown gate is the item-keyed on-hold record (2200, 2201) - re-clicking the character you already have selected keeps its facing instead of snapping it square (2194) - the shift-compare plate seats beside the tooltip and is owned by the engine, so a stale plate never rides over the next hover (2202) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
1116efbb68 |
the map opens full screen again after an addon windowed it
- the world map opens full screen again on a character that once ran Cartographer's windowed map: a saved frame position or size outlives the addon only while the frame is movable or resizable (2193) - the layout cache gates both the write and the apply on `userPlaced AND (movable|resizable)`, the reference's four sites, where benilla had only the setter's (2193) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
3e92b4f015 |
empty tooltips hide, the map opens on your zone, Questie's arrow lands
- Questie's arrow points at the turn-in, not 100 yards off: the map selection sits on your zone from the moment you enter the world, as the reference's does, so Astrolabe reads the right sheet (2192) - an area the map has no row for sends the selection to your continent, not the world view; the reference fails its zone lookup and its continent lookup separately - a tooltip shown with no lines hides itself instead of drawing an empty plate at the last hover's size, as Questie's tracker did on some quests; each fresh hover restores full alpha, so a plate an addon dimmed does not stay dim - Questie's minimap button turns the quest icons back on: a nil handed to a colour setter stores zero and carries on, as the reference does, where benilla raised and jammed Questie's event queue from login (1973) - MonkeyDev loads without three red dialogs at login: an unknown frame type in an addon's XML is logged and skipped, as the reference does; only a script creating a frame of a bad type still raises (2191) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a8d0ee80f3 |
a body at the waterline draws on both sides, and its gear follows
- a creature spawning or coming into range in water no longer punches a body-shaped hole in the surface at the start of its fade-in: a model crossing its water plane draws on both sides, each half clipped at the waterline (2188) - the same split covers your own body on login while swimming, stealth and ghost form in the water; Crystal Lake's murlocs streaming in were the scene that showed it (2188) - helms, shoulders, weapons and hung spell kits clip at their wearer's waterline too, so the fade no longer looks wrong whenever the surface crosses the armour (2190) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
9caacad153 |
brightness saves, the glue box holds still, and Questie's notes hover
- the Brightness slider in the options window changes the picture and keeps its value; it was writing to no setting at all, so every reopen read 50% again (2186) - the login, realm and character screens share one letterboxed frame, so clicking down the character roster no longer slides the backdrop and every panel over it; at 4:3 nothing changes (2187) - Questie's world-map notes show their tooltip on hover: the note hands the tooltip a frame where an anchor name goes, which benilla refused with a script error and the reference reads as the default anchor (2176) - with OmniCC installed, a warrior in a stance sees the countdown on action bar 1 again: raising that bar's buttons by script carried their cooldown sweep up over the count (2189) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
fcb159c151 |
camera rows land in Options, brightness arrives, /reload loses nothing
- fourteen settings get their switch on the Options window: the Camera box from Follow Terrain and Head Bob to Water Collision and Smart Pivot, plus Attack on Assist, Auto Clear AFK, Auto Self Cast, Enhanced Tooltips, Player Guild Names and Show Target Damage (2180) - the Graphics page gains Weather Intensity, scaling rain, snow and mist, and Brightness, applied as a final pass over the whole finished frame; GetGamma and SetGamma answer in the slider's unit (2181, 2182) - hovering a disabled button fires no OnEnter, no OnLeave and no highlight, as the reference's does, so AtlasLoot's unset QuickLook buttons stop throwing a Lua error on every hover (2183) - a chat window dragged, resized, recoloured or renamed just before a /reload keeps the change, and the meeting stone's minimap icon comes back after a /reload while you are still queued (2184) - swimming at the surface, the camera stops snapping into your character every couple of seconds: the water leg of the camera trace is a bare ray, as the reference's is, so the boom stops on the plane rather than a probe radius short of it (2185) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
6d663299f8 |
the video options window goes stock, and water collision returns whole
- the reference's own video options window loads hidden, so pfUI's video skin and any addon reaching for its sliders and check buttons by name finds real frames; our own options window is BenillaOptionsFrame now, and ESC still opens it (2177) - GetScreenResolutions, GetCurrentResolution, SetScreenResolution, GetRefreshRates, GetVideoCaps, RestartGx and RestoreVideoDefaults answer off the monitor's own modes, so CT_Viewport loads clean (2177) - three of those verbs were corrected against a second read of the binary: GetRefreshRates answers nothing on a device with no rates, GetVideoCaps always gives a number for triple buffering, and RestoreVideoDefaults writes the ten rows the verb writes (2177) - the camera's water collision is back with both halves: the boom stops at a water surface, and a swimmer's camera keeps a constant 2/9 yd clearance over the waterline whatever the body underneath does (2179) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
eebbcc050f |
NTFS load order, a title-sorted AddOns list, and tooltips at the cursor
- addons load in the order NTFS lists a folder, case-insensitive with an underscore before the letters, the order the vanilla corpus was written against and the one that decides which addon provides a shared library (2178) - GetNumAddOns and the index form of every AddOn verb walk a title-sorted list that hides the Blizzard addons the server says to hide, and the character-select AddOns list is in title order (2175) - SetPoint and SetAllPoints raise the reference's own errors for a frame name that does not exist or an omitted relative frame instead of quietly anchoring to the parent, and an explicit nil means the screen root (2176) - a tooltip owned with ANCHOR_CURSOR follows the mouse, which pfUI's tooltip, xpbar and chat modules, pfQuest's browser and TipBuddy ask for; an omitted or unknown anchor is ANCHOR_LEFT (2176) - a $parent name handed to CreateFrame, CreateTexture or CreateFontString expands as it does in XML, so FonzAppraiser's thirty dropdowns and pfQuest's search icon get the names they asked for (2176) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
5af3a15d0e |
plate text settles, mobs stop sinking, and select goes with Lua 5.1
- a nameplate's name and level stop popping a pixel every other step as the plate slides, and the whole plate no longer jumps 19 px to the top of the screen on a rounding tie; the chat bubble takes the same fix (2172) - creatures and other players stop sinking through the ground while the world is still streaming in, where a Stormwind patroller had been 31 yd under its street: a body our world cannot yet answer for holds the server's pose (2174) - select and the string metatable are gone, as in 1.12's Lua 5.0: pfUI's heal prediction parses its messages with the right format, BuffCheck2's own select wins its fallback, and a method call on a string raises the reference's own error (2171) - the camera's water collision comes back out for now: with the pivot a hair under the plane, a surface swimmer's camera snapped in and out against the waterline, so the boom ignores water again (2173) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
70a8ad9d60 |
dodge, parry and block answer, and the camera boom stops at the water
- GetDodgeChance, GetParryChance and GetBlockChance answer the numbers the character sheet already had, so the addons that ask for them get a figure instead of a nil (2166) - with Follow Terrain on, pressing mouse-look no longer jolts the view: the terrain lean folds into the angle you drag and comes back out on release, and smart pivot holds its bias while a server-driven turn runs (2165) - entering water, the camera's pivot eases down to the model's own swimming height, so the eye no longer sits at a different height for the same zoom (2165) - the camera's water collision is back as what the option actually is: with it on, the camera boom stops at a bare water surface instead of passing through it; the pivot corridor that snapped last time is not rebuilt (2170) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
0a3c0692b1 |
pfUI's hdgraphic runs, the plates settle, and the water camera comes out
- pfUI's hdgraphic module runs: SetWorldDetail and GetWorldDetail are real verbs with the reference's three stops, and the near clip plane is a live setting at 0.100 yd rather than a frozen 0.111 (2163) - nameplates stop drawing a black box on hover or click, stop jittering a frame behind a moving creature, and a unit that walks into range later gets its plate; a unit with no level wears no skull, and the wheel zooms over a plate (2168) - the faint one-pixel box around every letter of a magnified overhead name is gone, each glyph now carrying its own transparent padding; interface text drawn at 1:1 is byte-identical (2169) - the camera's water collision comes back out for now: its pivot corridor dropped the camera a yard in one frame at head depth, which is the snapping reported around the surface while swimming (2165) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
6de042d5fa |
a melee spell's range is in yards, and item tooltips read their data
- a melee spell's tooltip says 5 yd range instead of Melee Range and grows with the reach of whatever you are auto-attacking; Heroic Strike and Bloodrage show no range line at all, as the reference does (2158) - an item's resistances list Arcane first, and its type word comes from ItemSubClass.dbc, so every container names itself: 24 Slot Soul Bag, 8 Slot Quiver, 6 Slot Ammo Pouch (2080, 2158) - weapon damage rounds the client's way, floor on the low bound and ceiling on the high, so Fang of the Mystics reads 38 - 86 not 39 - 86; ammo reads Adds 1.5 damage per second (2158) - an arrow's slot line reads Projectile | Arrow and a bullet's Projectile | Bullet, the word the reference takes from ItemClass.dbc where we printed the type alone (2158) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
ef9af66dc2 |
plates take the mouse, Auctioneer loads, and the damage font is yours
- hovering a nameplate lights its unit and clicking one selects it, pfUI's click-through works, a drag that starts on a plate still turns the camera, and turning plates off with V clears them (2159) - Auctioneer's XML documents open (the reference has no XML namespaces), a .toc line reaching Blizzard_AuctionUI's templates resolves for Auctioneer, BeanCounter and SpecialTalentUI, and a missing include logs rather than raising the red error dialog (2155) - a .lua reached through <Script file=> carries the same Interface\AddOns\ chunk name as a .toc-listed one, so Ace2's debugstack split works and AtlasLoot keys its database; 26 more corpus addons load, 176 of 219 (2155) - the floating combat numbers draw in whatever DAMAGE_TEXT_FONT holds at world entry, so MikScrollingBattleText and pfUI pick the font (2156); a dodged swing prints no line and floats no word, and happiness leech lines print (2157) - an unknown frameStrata in XML logs and keeps the default instead of raising, so EQL3's log window loads; FrameXML_Debug is a real switch, so ImprovedErrorFrame loads (2160) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
afc0731ccc |
nameplates are frames, guild names go overhead, and the camera pivots
- a nameplate is a real frame under WorldFrame, six regions and a health bar in the reference's order, so pfUI, ShaguTweaks and _Nameplates find and restyle plates instead of seeing none; the plate stays out of the mouse's way in this cut (2148) - a player's guild shows under their overhead name in angle brackets, the line an NPC's subname already used, gated by the UnitNamePlayerGuild option at its stock on (2149) - smart camera pivot is on, as 1.12 ships it: a mostly vertical drag with the camera pressed against something tilts the view instead of swinging the arm, easing home on release; in water the pivot rises for a swimmer (2149) - Follow Terrain and head bob are built and ship off, as in 1.12: Follow Terrain leans the camera up or down the slope you are walking onto, and head bob sways the first-person eye in a figure of eight while you move (2149) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
99b55f58ee |
a bad macro fails on its own, and script errors name their frame
- a macro with a Lua error fails on its own and lands in the script error channel instead of aborting the UI function that ran it; RunScript names its chunk by the source text, and a bad or empty argument is a quiet no-op (2136)
- a script error or debugstack frame names its handler as Frame:OnClick instead of a whole CreateFrame sentence, an inline <Script> block is no longer mistaken for the .lua beside it, and a handler's line numbers stop reading one too high (2136)
- GetAddOnInfo and its seven siblings raise the reference's own Usage and out-of-range messages, GetAddOnInfo("2") is the second addon, and assert(a, b) answers one value, as the client's Lua 5.0 does (2139)
- frillDensity and gxApi are real settings: pfUI's hdgraphic module reads world detail through frillDensity, its system tooltip names the live render backend, and the two spellings of the ground clutter knob stay one knob (2151)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
26fb54b402 |
fourteen settings go live, /leave holds, and /assist can swing
- mouse-look speed is cameraYawMoveSpeed and cameraPitchMoveSpeed, so pfUI's afkcam does what it asks and an addon driving the stock Interface Options window runs its load and Defaults walks to the end; the shipped feel does not move (2147) - the eight combat-log range sliders are real settings, so BigWigs' Range plugin and DPSMate read and write them, and the Show Pet Melee Damage and periodic-spell settings genuinely silence what they gate (2147) - the stock Sound Options window loads hidden beside ours for addons to find, and its three check-box settings are real: the listener sits at your character, emote voices can be muted, zone music can loop without its silence gap (2147) - /assist with assistAttack set selects and starts swinging; /leave General survives a relog, a /join puts the channel back in its chat window's list, and SetGuildRecruitmentMode joins and leaves GuildRecruitment - City (2144) - wipe, strsplit, strjoin, strtrim, strconcat and tostringall are gone: no 1.12 client has them, and the addons that call them are multi-client builds whose vanilla path raises on the real client too (2146) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
31371641eb |
the mailbox takes typing again, and events carry their real arguments
- the mail window's send tab takes typing again: the subject, body and money boxes were taking no input while the recipient box swallowed every key, and a sent letter clears its subject and item icon instead of putting them straight back (2145) - seven events fire the way the reference does: UNIT_DYNAMIC_FLAGS fires at all, swapping two identical stacks between bank slots fires PLAYERBANKSLOTS_CHANGED twice, the pet sheet's training points repaint, and ITEM_LOCK_CHANGED loses its invented arguments (2140) - nine widget methods 1.12 addons probe for are in: ShaguTweaks stops recolouring textures the reference leaves alone, pfUI and _Nameplates stop raising on a tooltip's GetAnchorType, and 63 AceEvent addons get RegisterAllEvents (2142) - six post-1.12 methods leave the widget surface (SetSize, SetShown, HasFocus, SetFormattedText and two tooltip verbs), so an addon reaching for a later client's API finds what a real 1.12 client gives it (2142, 2146) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
5432a8bfbd |
a slider snaps to its step, a pushed button releases, and warnings show
- a slider with a value step snaps to it: a stepped drag fires once per row instead of once per pixel, a scrollbar cannot rest between two rows, and one wheel notch on the trainer list reaches the bottom (2133) - setting a step on a live slider moves its value onto the new lattice and runs its handler, which an addon on the real client can count on (2143) - a button pushed from script releases on the next mouse-up, so Tablet-2.0's rows stop staying pressed forever; a release off the button's rect un-presses it, and a locked state holds (2134) - the mail body and the GM ticket box scroll as you type past their bottom, and the Use UI Scale checkbox reads a registered setting (2141) - an engine warning, a call that was accepted and did nothing, reaches the /errors window in grey instead of one terminal line; a text row trimmed mid-character no longer kills the window's repaint (2135, 2138) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
94945e8339 |
two addons that need each other load, and pfUI's memory row fills in
- loading two LoadOnDemand addons that depend on each other loads both instead of killing the client with a stack overflow; each is counted loaded before its own files run, as on the real client (2139) - the memory report gets its second number, so AceAddon-2.0's memory line (36 copies in the corpus) stops raising and pfUI's panel prints a figure where it printed UNAVAILABLE; garbage collection takes a number and answers nothing, like 1.12's (2136) - a disabled addon you have uninstalled keeps its row in AddOns.txt through a logout, and a hand-edited name keeps its spelling instead of taking the folder's case (2139) - a loaded chunk's error lines name it the way the real client does, and a /console argument containing ]] no longer trips a syntax error the 1.12 lexer would raise (2136) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
de9f5edb45 |
zone channels survive a border crossing, and nameplates survive a login
- crossing a zone border prints one Changed Channel line instead of a leave and a join, and General and LocalDefense keep printing in the new zone; walking out of a capital keeps Trade's number and its registration instead of dropping it (2130) - outside a capital the channel numbers are the reference's: a fresh character holds 1 General, 2 Trade (suspended until a city) and 3 LocalDefense, so /2 reaches the same channel it does on the real client (2137) - logging into a character reads that character's zone, not the previous one's, so a login in the Eastern Plaguelands no longer joins and leaves Stormwind's channels first; a chat cache with General saved as a custom name gets its id back (2130) - the Show Tutorials option survives a /reload: it loaded unchecked and clicking it reset every dismissed tutorial account-wide; a world entry no longer switches off nameplates you had turned on (2131, 2132) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a753a8b55d |
an addon's font draws in its own face, and Bartender2 keeps its profile
- text shapes in the face an addon asked for: MikScrollingBattleText draws in its own Porky instead of a system sans, and Arial Narrow and Friz Quadrata are no longer drawn by the Mac's own fonts (2123) - Bartender2 and Cartographer stop resetting their profile at every login: a stack trace opens on the caller, where AceDB reads its addon's folder; a font's reported height is a number before its face resolves, which Tablet-2.0 does arithmetic on (2121, 2129) - a button highlight built from a texture object draws, so Bongos' bar-drag button, _Nameplates' mouseover glow and Quiver's option rows show theirs; clearing a state texture removes it instead of drawing it in every state (2124) - a toc's repeated SavedVariables lines add up, so all 25 of CT_RaidAssist's saved globals persist instead of seven; colour-mapped TGA icons decode, so FonzAppraiser's and FuBar_WeaponRebuffFu's draw (2126, 2128) - MikScrollingBattleText's DoT lines are back with their school tints, and the school word is capitalised; a chat line with no colour stays white, and the short colour-id form of adding a message works (2127, 2125) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
c343d236e9 |
cooldowns survive a relog, the MOTD prints, and lost channels come back
- a cooldown still running when you log out and back in keeps sweeping instead of vanishing, and another character no longer inherits the previous session's cooldowns (2116) - the server's Welcome and Patch 1.12 lines print at login in system yellow, and a character whose General, Trade and LocalDefense had gone silent for good gets them back at the next login (2119, 2120) - the stock Interface Options window loads hidden beside ours, so pfUI's options skin finds the real thing; the Auto-join Guild Recruitment Channel row has a real store, and a /reload no longer trips on its camera dropdowns (2115) - the combat log words a power gain on the display scale, so MikScrollingBattleText shows +1 Rage where it showed +10; a 1.12 predicate answers 1 or nil rather than a Lua boolean, the test ColorPickerPlus makes (2117, 2118) - a Lua error quotes a program element with a backquote the way 5.0 does, so AceLibrary's argument checks report their caller instead of raising inside the error path (2122) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
321bcbb393 |
the cooldown pie survives a /reload, and Bagnon's bags keep their order
- the cooldown pie, the GCD sweep, minimap pings and the map arrow draw again after a logout, login or /reload; they went blank until a restart, which read as OmniCC killing the cooldowns (2113) - an addon's own font on a button label keeps its face, size and outline instead of being undone every frame, MikScrollingBattleText's reported look (2112) - an empty label reads as nothing rather than an empty string, so Cartographer's map label keeps its colour; a slider thumb with no authored size takes its art's own size, so Dewdrop's Look'n'Feel slider moves (2109, 2110) - Bagnon's saved bag list comes back in the order it was written, so the keyring stops jumping to the front after a restart; hovering a Bagnon bag costs a third of what it did (2111, 2114) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
99b5600e25 |
idle sits you down and camps you, and the addons anchor, parse and draw
- five idle minutes sit you down and flag you AFK, thirty log you out through the ordinary countdown; holding a key is idle, moving the mouse is not, and a swimmer stays afloat (2092) - a knockdown no longer wedges: the landing froze the clip that held the base-animation lock, leaving a knocked-down player on their back for the session (2098); the perf cost pill starts hidden (2099) - Lua is exactly 1.12's 5.0 — no vararg expression, no #, no %, the remembered table size — so Cartographer loads without errors and Mik's Scrolling Battle Text shows its text, in its own shipped font now that addon TTFs load (2101, 2102, 2103) - a widget name is a Lua global for SetPoint and its kin, so Bartender2's bars spread out; a button's NormalText disowns its justify, the raise renumbers hidden frames too, and a missing toc file warns instead of erroring (2105, 2100, 2104, 2107, 2106) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
1783660496 |
glue chrome in the box, a knockdown holds, and loot closes on a step
- on a 21:9 display the login, select and create chrome lays out on the boxed scene instead of the black bars beside it; at 16:9 nothing moves (B377, 2091) - a <Model> tile draws only inside its own cell of the shared atlas, so the pet bar's autocast shine no longer bleeds a golden bar onto a bag slot's cooldown (B379, 2093); a slider's first value always fires its handler, so Atlas's options load (2095) - a knockdown plays out: the reference locks the base animation for Knockdown, LiftOff and Land until the clip ends, and benilla re-picked Stand ten milliseconds in (2096) - the loot window closes and releases the corpse on your first step, strafe, turn or jump, the reference's movement-start guard; a distance leash shipped first and was a mislabelled census row (2094 → 2097, B381) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d0f5d62a96 |
afk and dnd work, the stun swirl shows, and the world drop is back
- /afk and /dnd send instead of printing Unknown chat type: the flag sets, <AFK> shows over your head at once, the four echo lines are the client's own, and moving clears AFK under the real autoClearAFK CVar (2082, 2088) - the stun swirl and the other state-kit visuals show — a cache the login map change cleared lost them nine runs in ten — and a state kit's animation id is the base recompute the reference runs, never a play, so the stray Stun one-shot is gone (2085) - dropping an item on the world brings up the destroy prompt again: since the stock WorldFrame landed, the world is a frame, and the drop's gate had been written for the absence of one (2089, B380) - the mouse no longer snaps to the window's centre when the loading cover drops on /logout; the cover hands the pointer back only where it knows it is (2090) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d569261521 |
the loading tip draws, its backdrop holds, and indoor trails go warm
- the loading screen's tip of the day is on screen: it was picked and saved but never painted, and once painted it was wiped by the login round trip (2083, 2081) - the backdrop no longer switches mid-load — logging back in to an expired dungeon held its art for a second and then flipped to the continent's; the art latches at the raise, keyed on the texture, not the map id (2081, 2087) - a weapon trail indoors takes the room's warm light instead of the sky's ambient, the wearer's own light being the reference's term (2086) - the glue dialog moves out of the login screen into the shared glue layer, so the select screen's refusals and the login's errors are one widget (2084) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
fb52a2a98f |
every line is a key, four find their sound, and the ding prints once
- the last app-side lines become GlobalStrings keys — tooltip cells, party, petition, duel, quest, PvP and rest lines read the install's own wording, so a non-enUS chain shows its own text (2045, 2080) - a locked chest says Requires Pick Lock, ammo and thrown weapons drop their invented slot word, a met set bonus reads Set: without the count, and a 100 s cooldown reads 1.67 min as the template prints it - the level-up block and the free-professions line printed twice in chat and print once; a declined invite, a friend coming online, a duel request and a failed quest play the sound 1.12 gives them - Duel cancelled. is the yellow line at the top of the screen, and a trainer refusal or a failed quest with no cached template shows nothing, as on 1.12 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
ecbdf2f716 |
the leader crown updates, the trail darkens, and four dead options work
- the party-leader crown on your target's portrait only ever appeared or vanished when you re-targeted them: `PLAYER_FLAGS_CHANGED` was one of eighteen events the migrated stock windows register that nothing here produced, and the census row naming it said "TargetFrame.lua — the AFK/DND badge", which sent the first look at the wrong window — 1.12 draws no AFK/DND badge on any unit frame and build 5875 has no `UnitIsAFK`/`UnitIsDND` at all (ours are a deliberate invention, 2043; the `<AFK>`/`<DND>` the era shows is the chat line's `arg6`), and the event's sole FrameXML consumer is `TargetFrame.lua:88-95` re-running `UnitIsPartyLeader("target")`, whose descriptor leg is bit `0x1` of this very dword; the handler `0x5ee990` XOR-diffs old against new at `0x5ee9b8` and fires 407 at `0x5eea3d` with no bit test in between and ABOVE the local-player GUID gate at `0x5eea93`, once per unit token naming that GUID through `0x515e50`'s fan-out (`arg1` = the token, no `arg2`, and a zero token count skips the fan-out so a stranger nobody targets signals nothing — free here, since `fire_transitions` only ever runs per token); so the trigger is the RAW dword, `UnitState::player_flags`, the `flags`/`UNIT_FLAGS` pattern one field over, because firing off the two bits the struct decodes would under-announce AFK, DND, GM, PvP-desired, helm, cloak and both play-time bits, and `prev.is_some()` keeps a unit's first snapshot silent as its CREATE runs no notify pass; reading the whole handler found an over-fire that was inherited, not invented: benilla fired `PLAYER_UPDATE_RESTING` on ANY flags delta because wow-re's rested-XP note said in as many words that `0x5eeaf2` fires "on every flags change, not only the resting bit", and the bytes say otherwise — `0x5eead0` `f6 45 fc 20 / 74 26` is `test byte [ebp-4],0x20 ; je 0x5eeafc` and the fire sits inside that arm — so every helm toggle, leadership pass and AFK flip had been announcing a resting change to the whole UI; narrowed to the resting bit's own edge, and the same handler's `0x5eeb65 test ah,0x30` arm becomes `PLAYTIME_CHANGED`, whose consumer `PlayerFrame_UpdatePlaytime` already had all three verbs it reads; the claim is corrected in wow-re by a four-derivation round that confirmed all three arms plus the CREATE question; three tests pin it — the producer with a control on `0x400`, a bit no field decodes; the over-fire regression on the real feed, where a helm bit moving fires neither self event; and the crown itself on the stock `TargetFrame.lua`, leadership passing to a held target lighting it with no re-target and the same event for `arg1 = "player"` not — a fixture that first failed on its opening assertion because `UnitIsPartyLeader`'s second leg is a raw GUID compare with no zero guard, so a default `guid: 0` equalled the zeroed leader of an empty group (verified 1.12: it is why `UnitIsPartyLeader(nil)` answers 1 while solo); the unproduced-events census goes 18 → 16 per window, 31 → 29 whole (2078)
- the weapon swing trail darkens with the scene instead of burning at its authored colour: 2076 shipped it unlit and said why — the draw callback turns lighting ON (EGxRs `0x0e = 1` at `0x6c6847`) over vertex format 7, position + packed colour with no normal, and the state bit alone does not say what fixed-function produces from that; the bytes now do: `0x5a1e30` sets DIFFUSE- and AMBIENTMATERIALSOURCE both to `D3DMCS_COLOR1` off the format's diffuse bit, so the vertex colour IS the material; the normal is explicitly disabled rather than stale (`0x592a60` replaces the format mask instead of OR-ing it, `0x59c100` issues `glDisableClientState(GL_NORMAL_ARRAY)` when the bit is clear, and D3D's format-7 descriptor carries −1 in the normal column), so there is no N·L and the diffuse half contributes nothing; and the global `D3DRS_AMBIENT` (EGxRs id 6) has zero writers image-wide and defaults to 0, an earned zero — leaving `out = (Σ enabled lights' ambient) × authoredColour + inherited emissive`, which is why this does not take the lit emitters' `clamp(ambient + diffuse·max(N·L, 0))` term, a sun the reference does not have; `weapon_trail.rs` multiplies the trail's RGB by `WowLighting.ambient`, folded on the CPU into the vertex colours because a per-draw constant rides the vertex stream on this lane, drawing as `EffectLighting::None` and at the authored colour until the first lighting resolve; two named approximations of the class the fishing line already carries — the scene ambient rather than a per-model light collector, so an interior trail takes the exterior ambient, and no emissive, since `EMISSIVEMATERIALSOURCE` is set nowhere and reproducing it would mean inventing a constant; the other half of 2076's open list was a deviation benilla does not have: it claimed the combat-over-combat fast path (`0x5fe43c` returning at `0x5fe48b`, before the trail latch's only read at `0x5fe48e`) was unmodelled and cost trails starting one play early — both wrong, because `0x60d835` arms a one-slot field with a plain `mov` so a second proc OVERWRITES the first and firing on every request would draw superseded arms with superseded colours on 23 of the 34 type-8 kits, and because the driver's request loop already fast-paths it (0406, `select::is_combat_anim` = `0x5fcc10`'s byte-decoded set) and `continue`s without playing, so the edge never rises; a negative asserted about our own code from having written it rather than looked, shipped to wow-re where it drove a build-it verdict for something already built — now pinned by a test that names both mechanisms; and `benilla-extract charprocs` prints `CharParamOne` beside every trail row: wow-re's note justified "not read by this arm" with "every shipped type-8 row carries 20.0 there", and over the 34 kits the column takes six values (22 at 20, six at 15, two at 25, two at 0, one at 17, one at 22 — Sinister Strike's kit 399 is a 15); nothing here reads it either way, but a census that hides the one column a note asserts about cannot catch the note being wrong, and wow-re's re-measure agreed value for value and found the column live at four sites in `0x60d7c0` for other proc types (2079)
- four options that ticked and did nothing — Show Tutorials, Tip of the Day, Profanity Filter, Disable Spam Filter — get their backing, and two of the reasons they were dead were wrong: none of the four was a row in our window at all; they sat in the transcribed `UIOptionsFrameCheckButtons` declaration table beside thirteen more whose features benilla lacks, and these four are exactly the ones where the feature existed and only the setting was missing; `SHOW_TUTORIALS` is a bare `{ index = 28 }`, which an earlier census read as "an index-only entry with no store at all" — wrong, the store is the three special-case arms `UIOptionsFrame_Load` (l.239), `_Save` (l.318) and `_SetDefaults` (l.645) keep for the key, `TutorialsEnabled()` reading the acknowledged bank and `ResetTutorials()`/`ClearTutorials()` writing it, verbs benilla has had since 1976, so the row was one `func` pair away, and the reference's `~=` guard comes with it because without it a Defaults click on a page where tutorials are already on would `ResetTutorials()` and re-arm every popup the player has dismissed; that census moves out of prose into a test checked both directions, the posture the CVar defaults already hold — a name the reference's table carries that nothing registers and no listed blocker fails, and a listed name that has since been registered fails too, twelve rows listed today with the feature each waits on; the two chat filters are PCRE over shipped DBCs, not word lists: `ChatProfanity.dbc` (2289 rows off `patch.MPQ` — `dbc.MPQ`'s copy is 1512) feeds the masker `0x4a1a60` and `SpamMessages.dbc` (28 gold-seller URL patterns; `dbc.MPQ` has none) feeds the predicate `0x4a1ca0`; Blizzard PATCHED PCRE's escape table (`.rdata 0x812330`) so `\<`/`\>` alias onto `\b`, and an unpatched engine makes them literals and silently kills the whole ASCII half of the profanity list while looking correct; CASELESS folds ASCII only, so pattern and subject are both ASCII-lowercased and matched case-sensitively rather than through `(?i)`, which would match `É` where the reference matches nothing; the masker is in place and length-preserving, one token per byte cycling `!@#$%^&*` from a process-global index never reset for the session, patterns in list order not text order — wow-re's oracle transcript reproduced against the real list, "you are a twat and a faggot" → "you are a &*!@ and a !@#$%^", the later word taking the earlier characters because its row (507) precedes the other's (530); two corrections to what this tree believed: `spamFilter` is armed for every chat type EXCEPT `CHAT_MSG_FILTERED` (`0x49aad2`'s `jne` skips the disarm, which the older note read backwards, so our comments claimed the filter bit only on the one type it is exempt from), and `profanityFilter` gates INSIDE the masker at `0x4a1a66`, covering all thirteen call sites rather than the guild MOTD alone; `CHAT_MSG_FILTERED` (`0x5B`) comes with them — it was on the "never `SMSG_MESSAGECHAT` wire" list and is the server's "your message was filtered" notice `ChatFrame.lua` renders at l.1405, dropped with a warning before and delivered now; the chokepoint runs spam, then mask, then fire, in the reference's order, since a dropped line must not consume mask indices; named rather than faked: the other twelve masker sites (mail, guild, item text, the send path) and their `dl = 1` memo, and the whisper leg's `CMSG_CHAT_FILTERED` report whose body is a wow-re DEFERRED with no vmangos handler; each row sits in 1.12's own seat — Profanity Filter closes the Basic Options Display column, Show Tutorials and Show Loading Screen Tips open the Help box, Disable Spam Filter is the last link of the Advanced chat chain and value-inverted, checked ⇔ `spamFilter == "0"` (2077)
- the loading screen shows the tip of the day: `GameTips.dbc` is 74 records in the 5875 enGB chain, off `patch.MPQ`, ids unsorted (the file opens on 396 and closes on 412), so the index the client persists is a record index in load order, never an id; `gameTip` holds the NEXT index, not the one on screen — the client reads it, shows that row and stores `read + 1`, so on-disk values run 1..=74 and never 0, and the reference's own `Config.wtf` reading `SET gameTip "34"` while showing row 33 is exactly what an off-by-one anchors on; the wrap is a clamp, not a modulo (`if (i < 0 || i >= count) i = 0` at `0x46b682`), the walk is sequential, and both guards — `showGameTips` off and the roster's level-zero flag — jump past the `CVar::Set` as well as the draw, so turning tips off freezes the cursor rather than burning through the table invisibly; it draws only on the glue→world transition, because the setter `0x406630` has exactly one caller inside `EnterWorld` and neither `SMSG_TRANSFER_PENDING` arm reaches it, so the pick hangs off the loading screen's world-entry raise and a portal or worldport screen carries no tip; placement is the reference's: `s = 515/(a·1024)` with `a` = aspect × 0.75 (not W/H, which inflates the wrap width by a third at 16:9, and not the FrameXML-length idiom, which is off by 1.25 at 4:3), the block at `(0.5 − s·0.5, 0.1)`, left-justified, body `0xd7c8c8c8` with an opaque black shadow at `(+0.001, −0.001)`, laid out once per raise between the backdrop and the progress bar; the one term deliberately not applied is `yoff = (1 − a)·0.5`, which wow-re left unreconciled (`0x406a60` already applies the letterbox as a viewport and `yoff` is the same term added again inside it, a possible double count on a display narrower than 4:3) — benilla's loading screen is a 4:3 content box by construction and at 4:3 the reference's own `yoff` is zero, so the tip sits at the reference's layout on the one aspect where the ambiguity cannot bite; the `|cffffd100Tip:|r ` prefix and the trailing CR-LF are in the data and the escapes are interpreted, so the gold "Tip:" is markup and the line is built through the markup tokenizer; the cursor persists through the VM's own CVar table (`write_host_cvar`), since the config file is composed from that table and a host write stopping at the knob would reset it every launch — a live run reads `74 game tips` → `tip 0 of 74` → `tip 1 of 74` with `gameTip = "2"` left in the config, and an earlier live run is what caught a `GameTipSetting` the test harness initialised and the real app did not, a panic no unit test could see (2077)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
cf3189e422 |
a refused login says why, the deep ocean darkens, and the blade trails
- a refused character login left the player on a loading screen with no world behind it and no way off — reported as sitting at character select with no message, and the symptom was worse than the report: `SMSG_CHARACTER_LOGIN_FAILED` (0x41) had a name and no parse arm, so the client never heard it, and it was not at character select when the refusal landed, because the IO thread sends `CMSG_PLAYER_LOGIN` and announces the connection in the same breath (the entry's head start, 0777), so `ClientState::InWorld` was already set and the loading cover was up waiting for a snap the server had just declined to send; the wire half parses the opcode into `ServerPacket::CharacterLoginFailed` / `SessionEvent::CharacterLoginFailed` and carries the byte RAW, since vmangos sends a bare `1` and mangos-classic its own `CharLoginFailReasons`, and a wire layer that interpreted it would be picking a server; the refusal is an entry being REVOKED, not a failure to enter — `Cycle::LoginRefused` runs the same `SessionEnd::LoggedOut` teardown a `/logout` does, the cover cuts to black, `back_on_login_refused` takes the select screen back with the relist's roster underneath, and clearing `pending_pick` is load-bearing: it is 0065's reconnect memory and the relist is auto-answered with it, so keeping it would re-enter the refused character forever from behind a black screen; the byte is a 1-BASED REASON INDEX, not a status code — wow-re read `OnCharLoginResult` (`0x5aad70`): `dec eax; cmp eax,5; ja` into a six-entry jump table mapping 1..=6 onto `CHAR_LOGIN_*` 0x3e/0x3f/0x40/0x42/0x43/0x44 and SKIPPING 0x41 `CHAR_LOGIN_FAILED`, reachable only as the default, so the tempting `0x3d + byte` is right for four rows and wrong for the rest; `char_login_refusal_text` is that table, resolved against the player's own `GlueStrings.lua` and asserted against it (vmangos's `1` therefore reads "World server is down" — the server's dialect, and what the reference would say); the select screen runs the shared `login::drive_dialog` rather than a second copy of the reference's one `GlueDialog`, which found two holes — `to_select_on_roster` closed ANY dialog on an arriving roster while the refusal's own relist produces one a second later, so it would have wiped the message (the original bug one layer up; now scoped to status/queued), and `preflight`'s descriptor latch outlived the session that armed it, announcing "the avatar never streamed in" from character select, now disarmed on any disconnect; a live probe against vmangos pins the three facts this rests on — the byte arrives as 0x01, the roster still serves after it, a retry enters the world on the same socket — and `WOW_REFUSE_LOGIN=1` refuses the first pick of a run by sending a non-player guid, the one guard that needs no server state, so a path no real account can stage by hand is walkable on demand (2071)
- the ocean's depth ramp was never a placeholder, and its deep row is darker than we drew it: four files called the ADT ocean's `V = byte/255` a stand-in "pending its own RE" — the director's report had the sea fading to deep colour about 6x too slowly — on the claim that ocean takes a non-LUT UV path via `0x68d890`, which is the MAGMA vert-fill, as `benilla_adt::LiquidVertex::texcoords` had said by that same address all along; the ocean fill is `0x68d690` and it reads a depth LUT exactly as the river fill `0x68d790` does, `0x68c4c0` building both side by side (`0xc81768 = min(d/42, 1)` river, `0xc7fcd8 = min(d/255, 1)` ocean), the two fills differing in exactly 3 of 246 bytes — one `fld` displacement — so there is no second ocean-only depth term, and wow-re's cross-check found `/255` bit-exact for all 256 entries; the divisors differ because the authored bytes do — a census over every MCLQ block on Azeroth + Kalimdor, each wet vertex's depth byte against its own geometric depth, reads a river at 8.96 byte/yd (reproducing the independently-measured ≈8.5, the control) and the sea at 1.72, 5.2x gentler, so `/255` saturates at ~148 yd and `/42` at ~4.7 yd, the same ramp in yards and not a 6x slower one, while 83.4% of ocean vertices carry byte 255 outright, so the open sea is authored fully deep and the ramp is only a shore band; a test pins both divisors against the raw MCLQ bytes (swapping the ocean onto `/42` fails it), `examples/liquid_depth_census` is the measurement with named shore-band pins, `WOW_OCEAN_DEPTH_DIV` is the A/B, and the alpha-ramp deferral closes with it — `0xc7fbc0`'s `1.6·(i/63)^8` is the sky glare falloff, bound at `0x685257` inside a branch proven dead, so the linear `127 + 2·row` alpha shipped was right; and the finding nobody asked for: `0x68a830` fills the 8×64 swatch as an exact integer accumulator in BYTE space, `row(i) = c0 + floor(i·(c1−c0)/64)`, so the ramp never reaches the deep endpoint (row 63 is ~98.4% of the way), and an ocean-only tail `[0x68a9c0, 0x68aa36)` — gated on last row AND selector 0, river being selector 1 — runs RGB→HSV, `V ×= 0.9` (`0x3f666666` at `0x8102ec`), HSV→RGB and forces that row's alpha to 255, which reduces to `floor(0.9·byte)` per channel (99.03% bit-exact over all 2^24 triples, max 1/255); byte 255 ⇒ `V = 1.0` ⇒ row 63 exactly, so the darkened row IS the open sea, and benilla had rendered deep ocean ~10% too bright over most of the water in the world — an error that survived every regression diff because no capture scenario holds any ocean; `liquid.wgsl`'s `swatch_row` / `swatch_at` port the accumulator, the LINEAR/LINEAR CLAMP sampling (so the darkening ramps in across the final 1/64 of V rather than stepping) and the ocean-only tail, on the ADT lane only — the WMO arms keep the plain lerp, their opacity being a different 256-entry ramp — pinned by a test against wow-re's published byte vectors (row 62 = 12,36,41; row 63 = 11,35,40, green one ABOVE the deep endpoint; after the tail 9,31,36) that also asserts the WGSL still carries the formula; rivers move at most 7/255 from the row quantization (2069, 2074)
- the weapon swing trail — `SpellVisualKit` CharProc type 8, which benilla had dropped on the floor with the rest of the dispatcher's unmodelled cases: 34 of 1772 kits carry it, 27 are reached from a live `Spell.dbc` chain, and 16 of those name NO emitter slot at all, so the ribbon is their entire visual — kit 324 alone reaches 218 spells (Heroic Strike, Overpower, Mortal Strike, Bloodthirst, Rend) and rendered nothing beyond the swing animation, with 506 (Revenge, Riposte, Mongoose Bite), 557 (Sunder Armor), 646 (Hamstring, Wing Clip), 399 (Sinister Strike), 822 (Garrote) and 823 (Feint, Disengage) in the same shape; the proc draws nothing — `0x60d80a` latches a packed colour and a duration on the unit, and the unit's next `PlayAnimation` (`0x5fe48e`, the fields' only reader) hands both to its two weapon-hand trail objects and clears the duration, so an arm fires exactly once and a second proc on a live trail RESETS its ring rather than stacking; each object rings 128 samples of its weapon model's `$WTB`/`$WTT` markers (455 of the 571 weapon models author both) and draws them as a strip that fades from opaque at the OLDEST end of the arc to ≈0 at the blade, the alpha being a clock and not just an opacity; `weapon_trail.rs` transcribes the arithmetic rather than approximating it — the truncating `_ftol` decode (not the small-int idiom every other integer param takes, which would yield colour 0 and no trail at all), `fadeStep`'s low-byte floor (`cmp al,1`, so a ≈768 ms hitch takes a floor of 1 instead of its own huge value), the alpha-derived termination, and the ring's writer/reader modulus mismatch (`& 127` stored, `% 127` read — shipped 5875 behaviour, reachable only by Whirlwind's 10 000 ms spin); the draw state was dispatched rather than guessed and the guess was wrong in three of seven places: the callback's six EGxRs writes say `0x07 = 2` (ordinary SRC_ALPHA / INV_SRC_ALPHA — additive is mode 3, the difference between a ribbon that whites out crossing itself and a coloured smear) and `0x10 = 0` (depth test OFF: the arc draws over the world and over the swinging character, never eaten by his own shoulder), so `EffectDrawSpec::no_depth_test` is a new pipeline-key bit on the shared effect lane with every other producer explicitly false, where the state had only existed as the global `WOW_PARTICLE_NODEPTH` debug lever; the third — lighting ON over a vertex format with no normal — is a verified state that is not yet a verified appearance and ships unlit as a named deviation with the question out; the consume edge is `AnimDriver::started_anim`, not the one-shot alone, because `0x5fe2f0` is the image's SINGLE animation entry point, locomotion included — a unit that simply starts running consumes the arm, which is how Charge (kit 44, 38 spells, anim id −1) trails at all; kit 324's 600 ms duration is on screen for 1250 ms at 60 Hz, since `fadeStep` is `trunc(dt·alpha/300)` and shrinks with the alpha it decays, twice wow-re's own estimate; the warm pass gets the depth-test-off pipeline as the one combination that ships (alpha, unlit, no rasterizer settle) rather than as another factor of the cross product — 36 more warm draws per camera for pipelines nothing asks for — so the first Heroic Strike does not compile one live; and `benilla-extract charprocs` grows the trail census that found the 34/27/16 split (2076)
- a zero injury column plays nothing: benilla walked down the wound-grunt family when the selected column was 0 — crushing to critical to ordinary — on a comment with no citation ("crushing rows are often 0 in data"), a true observation about the data and a false inference about the client; `0x623490` tests the selected id once (`0x6234e6 test ebx,ebx ; je 0x62350e`, the shared epilogue) and no fallback is even reachable — the row pointer dies at `0x6234e4`, so neither the bus pick `0x623b10` nor the play `0x458890` ever sees the row to re-read a column from, and the CGPlayer twin `0x62f880` is identical; it mattered because the class-2 chance roll had just landed beside it (2073): a crushing blow skips the roll (class 9 carries threshold 100) AND fell through to the ordinary kit, so it was louder than an ordinary hit on the same creature by two routes; `sound/combat.rs` now plays the selected column or nothing — crushing → column 5, critical → 4, ordinary → 3 — and a crushing blow on a creature with no crushing kit, which is most of the 406 rows (`Skeleton`, `Silithid`, `MountainGiant` among them), is silent, the reference's behaviour rather than an omission (2075)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
1d7252aec2 |
unselectable units take no target, quieter wounds, a realm-list dialog
- a NOT_SELECTABLE unit takes no target: Stratholme's Baron Rivendare, pre-event, is spawned by vmangos with `UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_SPAWNING`, and where the reference can neither damage nor target him benilla refused the damage (`CanAttack` already read bit 25) and took him as a target anyway — most visibly through the ATTACKERSTATEUPDATE self-defence acquire, which hands you your attacker the moment he opens on you with no click and no hover involved, and every other writer (left-click, right-click, TAB, `TargetUnit`/`/target`/`/assist`, the attack auto-acquire) had the same hole; the reference's gate is the third early-out of `SetSelection` `0x493540` (`0x4935ee`/`0x4935f3`): the resolved object's `+0x58` vcall to `0x60be60` `IsSelectable` = `!(UNIT_FIELD_FLAGS & 0x02000000) || UNIT_FIELD_CREATEDBY == your guid`, sitting BEFORE the dedup so a refusal is a complete no-op — no `CMSG_ATTACKSTOP`, no `CMSG_SET_SELECTION`, the target already in hand survives — and skipped entirely for an unresolved object, which is what keeps an out-of-range party member selectable off the roster; `target::relations::is_selectable` transcribes it whole, the CREATEDBY clause (your own totem stays clickable, somebody else's does not) and the xor-eax base stub every non-unit vtable carries at `+0x58` included, and `scan::commit` runs it first behind a mandatory `target_store` parameter so none of its eight call sites can forget a gate it does not compute; the hover is the SAME predicate at a second site, byte-verified by the wow-re round this dispatched: the hover grader `0x4828d0` calls slot 21 directly on the pick's winner at `0x482982`, and a false answer jumps to `0x482090(0,0)` + `ResetCursor` `0x523d30`, skipping the publisher `0x492890` that holds the mouseover globals' only two writers image-wide — so no tooltip, no cursor, no emissive brighten and no `mouseover` token, all from one rule; it is a GRADER, not a filter, and the difference is observable — a census over the pick itself (`0x480a50`, `0x480d90`, `0x713cb0`, `0x481190`, `0x480df0`) finds zero reads of the unit flags against four inside `CanAttack`, so the flagged unit wins the trace and is then thrown away, which `Hovered::refused` carries with the pick's distance kept so a trigger stalker in front of a chest takes the pick and the chest behind it does not inherit the mouseover; graded at `update_hover`'s publish rather than in a system of its own, because `drive_mouseover_tooltip` is ordered only after the net stage and a second system would have bought a one-frame name plate for a unit that must never have one; the V-plate suppression turns out to be load-bearing, since a plate hover publishes the mouseover directly (`0x7cb869 call 0x492890`) with no grading at all; and a left-click on a refused unit no longer clears what you had — the grader had dropped it into `select_on_click`'s arm beside "clicked the sky", where the reference's deselect lives in the terrain and NOTHING legs only: the down-edge pick `0x481f00` still found the object, so the release takes the object leg `0x4925d0` whose tail hits `SetSelection`'s early-out and changes nothing, the reasoning the corpse guard beside it already carried and which gets its first test here (2060) - three things a landed hit showed that the reference does not: a lootable corpse took blood, flinch, impact sounds and a floating number — the victim dispatcher `0x624530`, which owns every victim-side consequence of a swing, opens with `test byte [[victim+0x110]+0x224],1` (`UNIT_DYNAMIC_FLAGS` bit `0x1`) and jumps past all four — but the obvious fix, gating the victim, is wrong: benilla fans that dispatcher out into one message emitted on three occasions and the reference gates the DISPATCHER, and an image-wide census of the number emitter `0x6243e0` (exactly three call sites, zero tail-jumps, zero address-takes, earned against a positive control) puts `0x624566` inside the gate but the `SMSG_ATTACKSTOP` flush `0x624ea7` and the supersede flush `0x625893` outside it, so a lootable victim still floats a number for a superseded record; gated: the impact-tag dispatch (record still consumed first, as `0x6247d0` clears the GUIDs before calling) and the unresolved-attacker fallback `0x625a6d`; ungated: both flushes and the whiff slow-down, `0x624ca0` being its own function past the dispatcher's end; the flush's own predicate `0x625e40` reads an unnamed `[rec+0xac]` and stays unbuilt rather than guessed (2066); a crit played a full CombatCritical clip on a fighting unit — vmangos sends `SMSG_EMOTE(EMOTE_ONESHOT_WOUNDCRITICAL)` to the victim of every damaging crit (`Unit.cpp:1601`), `Emotes.dbc` resolves it to AnimID 10, and on the director's 90 s brawl trace that was 7 one-shots plus 9 fast-path entries on the warrior cutting its own swing (`fastpath cur=87 req=10`), 19 across all units; the reference's shared emote player `0x5fcd20` refuses at `0x5fcd96` when `0x60ecd0` is true — `UNIT_FIELD_FLAGS` bit `0x800` OR an auto-attack target `[+0xc48]` — and 1469 had built the flag half alone, dormant on vmangos (its `0x800` is `PET_IN_COMBAT`; a fighting player or creature carries `IN_COMBAT 0x80000`, a bit the client never tests), so `emote_anim::play_eligible` takes `engaged` and both producers, `SMSG_EMOTE` and the chat gesture, pass `Has<Engaged>` through one `PerformerQuery`: a crit on a fighting unit shows only as the wound overlay, and the wound trace lines carry `unit=` (2067); and an ending effect's particles popped — the teardown `0x6203e0` that both the completion callback and the same-slot replace reach hides the node and queues it rather than freeing it, and whether that is visible turned on a half no wow-re note covered, dispatched rather than assumed: the draw path's own admission test is the live-particle count (`0x7b4b46 mov eax,[esi+0x64]`) and the model enqueues onto two scene lists on two fields — MESH on the visible flag (`0x719207`), PARTICLE on the aggregate `CM2Model+0x3d8` (`0x71922c`), set while any particle lives and the same word `0x61f680` frees on — so for `Strike_Impact_Chest` a node destroyed at 0.10 s still shows ~30 particles at 0.20 s, gone by 0.334 s, and benilla cut up to 0.30 s of a 0.334 s effect; the three points where an effect ENDS — expiry, the same-slot replace, the reap's immediate destroy — now hand their emitters to the drain by the instance root they already carry as anchor (`drain_instance_emitters`, `ParticleEmitter::drain_on_owner_loss`) and the root still despawns, the reference dropping the mesh the same frame; flipped at the ending rather than set at spawn because the other way an owner vanishes is the model dtor (gear change, display swap, stream-out), where the reference frees synchronously and draining that case is what stranded ghost clouds in the air (0826/0833), and the collateral path still frees (2070) - a creature whose template carries `DO_NOT_PLAY_WOUND_ANIM` takes no flinch and no parry, and the wound grunt is rolled: the creature template's `type_flags` carries the bit at `0x8`, benilla consumed the two bits either side — `0x10 NO_FACTION_TOOLTIP` in the unit tooltip, `0x20 MORE_AUDIBLE` in the parked-event gate — with neither reader naming its bit, and `wound.rs` carried the gap in a doc comment claiming "no template cache" that had been false since the cache landed; the reference refuses the flinch inside `0x60ea70` itself (`0x60ea9f`, so every trigger is covered) through the getter `0x6125f0`, whose null-record leg fails OPEN, so `names::type_flags` names all eight bits (a call site could say `& 0x10` and look right — that is what let it be wrong) and the wound trigger refuses a flagged victim as its first gate, keyed off the descriptor's `OBJECT_FIELD_ENTRY` the way `0x60b160` keys the cache; animation only, since no creature-type mechanism suppresses the blood spurt — a flagged creature bleeds (2068); the vocal half was dispatched rather than built, because wow-re's published "makes no pain sound" called the flag's second consumer `0x60ec00` a pain-sound dispatcher while three of its own notes said otherwise, and the cross-check came back with all seven questions VERIFIED: `0x60ec00` is an ANIMATION dispatcher — `GetWeapon(0,0)`, the mainhand subclass through the 18-entry remap `0x60ec98` and jump table `0x60ec84` to Parry1H/2H/2HL/Unarmed, handed to `0x5fe2f0` = `PlayAnimation`, whose 40 call sites push literals in `[16, 202]` and which reaches no sound band — so the flag gates two animations and no sound, and the parry now rides it (victimState 3 only; Dodge 30 and Block 24 reach `PlayAnimation` directly from `0x624a90`/`0x624a74`, and our subclass map agrees with the raw remap on all 18 rows); nothing suppresses the injury vocal — of the fourteen functions in the wound-vocal chain the only one dereferencing `[unit+0xb30]` is `0x623b70`, testing bit 5 for a bus — but the ordinary grunt IS rolled: `0x623490` runs the class chance roll at `0x8626d4[2] = 60` for a creature and `0x86424c[2] = 30` for a player, by the VICTIM's type, while classes 3 (critical) and 9 (crushing) carry 100 and always sound, so `INJURY_CHANCE_CREATURE`/`INJURY_CHANCE_PLAYER` thin the grunt under sustained melee where benilla had played all three every time — 40 grunts per 100 too many on a creature, 70 on a player — and a crushing blow's class 9 punches through a server-pushed object sound's suppression, which stops at class 8 (`0x6234bb`/`0x6234bf`/`0x6234c4`); a pet gets a template record at last, since `NameCache::resolve` routes a `HIGHGUID_PET` guid to the pet-NAME query and a tamed unit had none — 18 of the 471 flagged templates on the world DB carry a `pet_family` — so the create arm also asks by the descriptor's entry, the reference's own key (`[[unit+8]+0xc]`); 2068's claim that templates are queried lazily is corrected, the create arm having warmed the cache for every streamed unit all along, at the reference's own timing (`0x60afb0` → `0x60b157`, on the create path) rather than as the convenience its comment called it; and the skeletons of the report still flinch, and should — neither vmangos nor cmangos flags them (2 of 62 templates in each), `Skeleton.m2` authors CombatWound and CombatCritical, so what changes for them is the grunt's rate, not its existence (2073) - the realm list is a dialog, not a screen: the first live run of 2056's realm selection reported no hover highlight, Cancel and the X throwing you out of the session instead of back to character select, the character screen gone from behind it, and then a login that hung on "Connecting" forever with nothing in the log — three of the four are one mistake, since `GlueScreenInfo` names all seven glue screens and `RealmList` is not among them: `RealmList.xml` is a `frameStrata="DIALOG"` frame with a full-screen 75%-black quad that `Show()`s over whatever screen is up and `RealmList_OnCancel` only `Hide()`s it, while 2056 had built it as a `ClientState`, so Cancel had to pick somewhere to go, the screen behind was torn down, and — the one that mattered — a roster arriving while that state was up moved nothing because `to_select_on_roster` only ever leaves `Login`; Okay looked inert while the IO thread walked on to the character park, the next Cancel answered a park two ahead of the thread, and every later login queued behind a `pick_rx.recv()` that was never coming, silently, reproduced with a scripted walk before anything changed; the realm list is a `shown` flag now, served in place by the character park over `select!` — refreshing on the realmd socket the cycle still holds, since `RequestRealmList` (`0x46b8d0`) begins `COP_GET_REALMS` on a socket closed only at world entry (`0x46b70c`) and only `ConnectToRealm` (`0x46b210`) drops the world connection — and leaving only when a realm is picked, `HeldLogon` and the resumed cycle gone with it; Cancel sends one `Abandon` and the park that hears it decides, which is the reference's own shape: `RealmListDialogCancelled` (`0x46ed20` → `0x46b810`) compares the current screen name against "login" and returns immediately when it differs, tail-jumping `CLoginMgr::Cancel` (`0x5b3320`) only from the login screen; the hover was never a realm-list oversight — `Hilight` was "the owning screen's to drive", four screens drove it, two folding selection into the same expression and one scoped so the `GlueCloseButton` X on every panel could never light, and the realm list made five by having none — so one owner now, `glue_hilights`, lit by hover or `LockHighlight` and walking UP to the nearest enclosing button because a modal dialog's root is itself a button, with `art_swaps`, `glue_button_visuals`, `glue_hilights` and `sync_outlines` registered once in `GluePlugin` instead of hand-copied per screen; the IO thread names each park it stops at, a logout comes back through the same park a first login does, so the policy ladder puts the realm the player is currently on ahead of the persisted `realmName`, which benilla writes only at world entry, the reproduction is now a smoke leg (Change Realm → Okay → Change Realm → Cancel → Okay against the live server) that fails on the old code by construction, and two divergences are stated: the X abandons like Cancel because our thread parks on the question rather than polling for it, and Change Realm shows the list already in hand at once rather than waiting a round trip behind a status dialog (2072) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
38e9daf668 |
the fire layer sounds, heartbeats blend, and freezes refuse the flinch
- the burning city was silent: the director, at a Stratholme pin (map 329, `3471.91 -3366.89 136.85`), reported the burning-building flame layer missing — on the reference it swells as you approach a building — and that is the ambient emitter pool's signature exactly, one channel per sound id positioned at whichever of its emitters is nearest the listener (1867): 88 placements of `StratholmeFireSmokeEmberM/S.m2`, WMO props of `stratholme_b.wmo` with zero render batches, each authoring one `$DSL(6437)` StratholmeFireSmokeEmberSLoop; measured at the pin, the pool's four channels were held by UndeadCampfireSmall / CauldronLoop / TorchLoop / SlimeWaterfall, every one past its own DistanceCutoff, 0 sounding, the fire the fifth entitled entry and withheld by the cap, on a frame reporting 1,004 parked anim hosts each still holding a registration; two independent defects behind one line: (1) `doodad_events::fire_doodad_anim_events` scanned every resident host — no distance, frustum or portal gate — while the four channels are arbitrated by ascending entry index, claim order, so a surplus registration is not harmless but silence; the reference's event scan `0x719370` is reached only from `0x7074b0`'s walk of `[CM2Scene+0x20]`, a worklist emptied every frame (`0x707680`) and refilled by `0x710b90(model, 1)` from the terrain drain `0x683f80`, which walks only the bucket the scene-walk cull `0x683700` appended to — frustum, horizon occlusion, and the radius-tiered horizontal fade whose `alpha ≤ 0` is a hard cutoff — so a culled doodad's `$DSL` never fires and it never takes one of the pool's 32 entries; our prose — at four sites — had read wow-re's "linkage" as "loaded", and the scanner now honours `DoodadAnimHost::active`, benilla's one spelling of that membership; which made the pin MORE silent, because `gate_doodad_anim`'s meshless branch built its own `EmitterFade { instance: None, room: None }` on the reasoning that a particles-only model is not a building's prop — Stratholme's fire is 88 of them — so it fell to `ExteriorGate::admits_sphere`, and a sealed room is `Windows([])`, which admits nothing; a placement now has ONE draw-set gate, built once by `spawn::fx::emitter_fade` and handed to its emitters, ribbons, glow lights and anim host alike (a transport's props pass `None` and get `EmitterFade::sphere`, the single spelling of the bare form), so a meshless WMO prop's bones, particles and sound freeze and resume together under its building's portal PVS — which wow-re then CONFIRMED: a WMO `MODD` prop takes the same drain as an ADT `MDDF` prop (`0x684155`), behind a per-frame portal gate (`0x6838f0` runs only for the groups the traversal reaches); (2) the RE round that fix dispatched came back with a correction: we counted the cap on ENTITLEMENT, an out-of-range entry keeping its slot because FMOD was supposedly still playing it attenuated to nothing, and the binary says otherwise — `0x461b40` returns `[+0xE04] != 0 && 0x7a5810(ch) && !0x7a5870(ch)`, and `0x7a5870` is bit `0x100000` of `[ch+0x38]`, the DistanceCutoff verdict maintained by a second system the pump never names: `0x7a5ca0` registers the channel into a cull list only when the cutoff is non-zero, and `0x7a5000`, run immediately before `FSOUND_Update`, stops it out of range and re-issues `FSOUND_Stream_PlayEx` back in — so a far, inaudible ambience holds none of the four, neither does one whose start failed, and a cutoff of 0 is never range-culled at all; `admitted()` becomes `cap_step()`, one step of the reference's own fold over ascending entry index — Skip / Service / Retire — with the counter advanced only by a channel read back live from the mixer (`source_kit_playing`), and the pump may service up to all 32 entries looking for four live ones, which is what keeps an out-of-range ambience positioned to start the instant it comes into range; the census names WHICH ids the cap withheld, an edge like any other — "1 withheld" was a count, and *which* is the only question a missing-layer report asks — and reports three states, `serviced [out of range]` costing the cap nothing versus `withheld`, never reached; and the event scan forgets its cursor across a park, since `0x719370`'s window is one frame wide off a clock that never stops and has no persisted cursor, so a culled doodad's missed markers are lost, never replayed — carrying the memory would have burst every `$DSO`/`$SND` the park skipped; retested at the pin: five entitled entries, four out of range, 6437 SOUNDING, nothing withheld, hosts in the animate set 28 → 184, and the log shows the entry claimed by a distant fire coming into view then following to the nearest record 150 ms later — the swell the director described; the Goldshire forge control is unchanged, BellowIN/BellowOut alternating through one entry, 1 sounding; `$DSO`/`$SND` one-shots from culled doodads stop too, equally faithful; and the variation re-roll stays ungated on purpose — gating it would re-roll a whole field's lightning on the frame you turned back, a look for the director to weigh (2059, 2065)
- a poured particle is born already aged: the spawn kernels' third argument is the SUBSTEP dt, not the lifespan — the burst loop pushes a literal 0 (`0x7b5600`), both continuous loops push dt (`0x7b5779` interpolated, `0x7b57e2` plain), and the kernels store `particle.age = U01 · w` (`0x7b88c4`/`0x7b88c7`, byte-identical across the plane, sphere and spline kernels) — and benilla birthed everything at 0.0, so the births sharing one frame arrived in lockstep; `birth_age` now seeds a poured particle at a random fraction of the frame it was born in, which is why a steady stream does not pulse at the frame rate, while a burst's N particles keep one clock and age as one body; read as the LIFESPAN instead, `w` would scatter a burst over `[0, lifespan)` — half the integrated brightness, half the mean radius, half every steady pool's population — and an audit here proposed exactly that reading, which wow-re's own measured count (N = rate × lifespan = 300, confirmed) had already ruled out and the bytes refute, so `a_burst_births_every_particle_at_age_zero` pins it; one named approximation: the reference substeps at a hard 0.1 s (`[0x81d828]`), bounding its dt by construction, and benilla does not substep, so the frame delta is clamped at 0.1 s in `birth_age` instead — identical below 0.1 s, which is every frame that is not a hitch
- the wound-flinch gate is the freeze node, and the swing report stays open: the director's report of a warrior in a many-mob brawl whose swings read as more suppressed and cut short by incoming impacts than the reference's had survived a full re-read of the victim side with every mechanism matching, and one reference gate benilla did not model had turned up on the way — the wound trigger `0x60ea70` refuses the flinch while any CEffect node on the victim's `+0xb4` list carries `+0x2c & 0x4` (`0x60eab6`); wow-re's cross-check pinned the bit's one setter image-wide, `0x6201d0`, the node the kit CharProc applier `0x60d7c0` creates for CharProcType 11: it saves the owner's playback rates (mount root, body key-bone 4, body root), overrides them with `CharParamZero` via `0x712910` and ORs the bit in, and the teardown `0x6203e0` restores them — the freeze node 0889 already models as `AuraNodes::head_anim_rate`, seen from the other end; while it lives every flinch is refused — melee, spell, missile, `$HIT`; in shipped data 17 kits carry a proc 11, 15 at rate 0.0, all referenced only as state kits — Freezing Trap, Ice Block, Petrify, Entangle, web wrap, the frozen-in-place family, and not the stuns (kits 349 / 33 carry none) — and the gate is the node's presence, kit 3071's rate of 1.0 closing it exactly like 0.0; a level-60 warrior brawl spawns none of them — Bloodrage, Berserker Rage, Enrage, Death Wish, Battle Shout, Demoralizing Shout, Sunder Armor, Heroic Strike, Rend, an incoming Renew or Power Word: Shield, the creature Strike/Cleave/Thunderclap family, a mage's Frost Nova (state kit 285) — so this gate does not explain the report; the lead is dead, verified, and the report stays open with the move trace (`WOW_MOVE_TRACE_TAGS=fct,anim`) now carrying every wound trigger, evict and expire beside every swing play and fast-path, so the per-swing flinch count and timing can be read off one run instead of guessed at; the driver refuses the wound while `AuraNodes::head_anim_rate()` is `Some` — the node's presence, not its rate — traced as `wound trigger id= REFUSED (a proc-11 rate node is attached)`; `KitPlay::wound` runs the kit tail's `[8,10]` branch for a discrete play and not for the impact hand-off's state stage (`0x60f383`: a state kit runs the base recompute only); 2058's `0x6ea280` hostility-classifier decode is CONFIRMED (`Targets & 0x100 → 1`, `& 0x80 → 2`, else the per-effect implicit-target tables `0x6ea338`/`0x6ea378`); tests: a rate-0 node and a rate-1.0 node both refuse the flinch and no node flinches, an instant harmful `SMSG_SPELL_GO` lays exactly one wound per hit target with a state kit naming CombatWound adding nothing, a helpful one lays none, and a missile arrival wounds regardless of hostility; named and not done: an effect model's own `$HIT` event flinching the unit it is attached to (`0x61f6f0`), and the reflect impact on the caster (`0x6e8cb0`) (2063)
- tag `0x26` is the teleport's, not the heartbeat's: wow-re's cross-check of the relay family — one client handler `0x603bb0` → `OnUnitMoveEvent 0x601580`, thirty opcodes — confirmed 2061's teleport claim and corrected an attribution this client had rested on since 0601: the queued move-event node's tag that `0x619030` (facing interp) and `0x619090` (position reconcile) both bail on (`cmp [eax+0xc], 0x26` at `0x61904b`) belongs to `MSG_MOVE_TELEPORT`, and the heartbeat's is `0x25`; benilla had excluded the heartbeat from both blends for two years and blended the teleport — which it never parsed, so nothing contradicted it; checked on this side before acting: `push 0x26` occurs at exactly two addresses in the movement region, `0x6186bd` and `0x618736`, inside functions whose only callers are `0x602f90` and `0x602fb0`, and `0x602fb0`'s other branch pushes `0xc7` = `MSG_MOVE_TELEPORT_ACK`; it was most wrong exactly where it mattered most — the heartbeat is the ~500 ms pulse a moving player sends, and a mover running straight sends nothing else carrying position (0617), so a watched player running in a straight line had their position snapped at 2 Hz instead of blended, a second cause, of our own, for the "2 Hz height staircase" 0626/1545 were built around (the ground clamp stays: our floor and the server's genuinely differ, and no blend fixes a missing collider); `reconciles()` is now `verb != Teleport`, and the three opcode-derived booleans this was heading toward are one closed `RelayVerb` enum — `Pose` / `Heartbeat` / `Teleport` / `Root(bool)` — so every receiver has to say what it does with each — nothing had forced a reader to enumerate what an opcode could mean, which is how the tag mistake lived as long as it did; two more corrections from the same cross-check: `MSG_MOVE_ROOT`/`MSG_MOVE_UNROOT` are opcode-authoritative — after the merge the client runs `SetRoot 0x7c7340` (`or 0x1000`, then the one-shot motion wipe `& 0xffe07f00`) or `ClearRoot 0x7c7370` unconditionally, the flags word getting no vote; vmangos always sends a word that already agrees (`MovementHandler.cpp:1070`), so it changes nothing today and stops the root depending on the server continuing to be careful — and a relayed flags word is MERGED, not assigned (`new = old ^ ((old ^ wire) & 0x75a07dff)` at `0x618de7`), which the self lane already did and the remote lane did not; still consequence-free, since nothing reads the one client-owned bit, ON_TRANSPORT, off `RemoteMotion::flags`, but lifted to `move_flags::merge_server_authored` so both lanes share one implementation; pinned both ways — the teleport skips, Heartbeat / Pose / Root all arm, and a deliberately contradictory `MSG_MOVE_ROOT` whose word says running roots the mover and wipes the direction bits anyway; open from the same round: the transport re-anchor (`0x618b30 → 0x7c6900`), which benilla reaches by a different route and is worth proving equivalent, and `MovementInfo +0x04`, which the reference neither parses nor zeroes and whose readers were not censused (2064)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
eacf343a55 |
the player picks the realm, and a harmful spell flinches its victim
- the player picks the realm: benilla connected to whichever realm the auth server listed first — not a policy but the absence of one — with the reference's Change Realm button drawn permanently disabled and the character screen's banner reading "Connecting…", a string 1.12 does not have, invented because the realm only ever arrived as a passenger on the character list (`CharacterSelect.lua` l.66 ends that ladder with `CharSelectRealmName:Hide()` — no name, no banner); `read_realm_list` had read the flags byte, the category byte and the realm id into `_` locals and stringified the population on arrival, and all four are load-bearing; the IO thread gains a third park — logon → which realm? → world handshake → which character — publishing `SessionEvent::RealmList` and blocking on `RealmRequest::{Enter, Refresh, Abandon}` exactly as at the other two, `Enter` carrying the realm's name and not its index since the list is re-requested every 5 s (`RealmList.lua`'s `REALM_LIST_REFRESH_TIME`) off a realmd socket `Logon` now keeps; Change Realm hands the logon forward (`HeldLogon`) so a different realm costs a world dial, not a re-authentication, and a deliberate ask arms `Realms::forced` for exactly one list, because the realm remembered from last time is precisely the realm you are standing on and asking to leave — without it the button re-entered the same realm and appeared to do nothing; the auto-answer ladder is a pure `auto_answer` — `WOW_REALM`, then the remembered `realmName` CVar (which `set_realm_name` had poked into its slot in place, never reaching `cvar_changes`, so the persisted CVar whose whole job is "the last realm connected to" was absent from disk forever; it writes through `set_from_engine` now), then an unattended run takes the first realm that is up, every arm requiring the realm to be up — and the screen is `RealmList.xml` rebuilt on the same 640×512 HelpFrame plate the AddOns list uses, eighteen rows at the authored 20 px pitch, four sortable columns; the Population word is a BAND, not the float: `realm_load_stats` (0x46e510) takes the mean and `sqrt(Σ(pop − mean)² / (n − 1)) · 0.6`, `realm_load_classify` (0x46ec60) reads the sentinels first (0x20 → Recommended, 0x40 → New, 0x80 → Full) then strict `pop < mean − stddev` → Low, `pop > mean + stddev` → High, else Medium — so the same realm reads High on a quiet list and Medium on a busy one, and a lone realm is banded against the `n ≤ 1` short circuit's literal 1.0, so a local vmangos realm at 0.06 reads Low, not Medium; then wow-re's cross-check of `RealmList.cpp [0x46e3bf, 0x46fa05)` confirmed 0x01 = invalid / 0x02 = offline and that the real client does auto-connect by `realmName` without raising the list (`0x5ab800` resolves the stored name against the fresh list, its success leg calling no `SetStatus`), and corrected four things the first cut shipped: the statistics are GLOBAL — `0x46e510` walks the flat all-categories array unconditionally (`0x46e5ee fadd [esi+0x12c]`), the per-category bucketing in the same loop a side effect and never a bound, so scoping them to the tab made the same realm read a different word per tab; Recommended/New/Full never travel as flag bits at all — the parser recognises magic populations by bit pattern and rewrites them, 600.0 → 0.0 + 0x20, 200.0 → 0.001 + 0x40, 400.0 → 8.0 + 0x80, and it has to happen in `read_realm_list` before anything averages, since one realm advertised Recommended arriving as 600.0 drags the global mean past every other row; pvp/rp is a `Cfg_Configs.dbc` join on the type dword at `[realm+0x04]`, and the shipped rows make types 3 and 5 PvP and 7 RP where the 1/6/8 match had all three Normal; and the default sort is `[characters, load, name, mode]`, all ascending, written once per process by `0x46e300` — a four-key fallthrough where "ascending" characters means higher count first, a column click being move-to-front (`0x46e9b0`) that keeps the column's direction unless it was already in front — with the reference's non-antisymmetric characters comparator (its tie-breaking `strcmp` result clobbered one instruction later at `0x46e846`) deliberately not reproduced; `RealmWizard`, the `REALM_IS_FULL` confirm and the category tab strip are deliberately not built, each for a stated reason (2056, 2062)
- a re-played effect REPLACES the same record at the same attach point: the director's report that the reference draws far fewer impact effects when many mobs beat on one warrior — and named the star burst on both hands on every crit — is not a limiter but a replace, recorded in wow-re for weeks: `CEffect::AddEffect` (0x61fdd0), the path every kit slot and the melee blood spurt take, opens with `0x6208e0(owner, rec, tag)`, which walks the owner's `+0xb4` list and destroys every node carrying the same `SpellVisualEffectName` record at the same attach tag (bounded `[0x6208e0, 0x62092c]`), skipping `tag == -1`; benilla replaced only persistent instances, on the narrower `(spell_id, class)` key of the spell-id reap `0x614150`, and pushed every one-shot unconditionally — a gap seen and scoped to one caller four times (0850, 0927, 1149, 1518) without being generalised — so five attackers landing swings on one body held five blood spurts at `(UnitBlood, 0xf)` where the reference holds one, linear in the attacker count on additively-blended emitters where the reference's is flat, and near-identical in a 1v1, which is why it survived; the sharpest case is Flurry (12966–12970), applied on every critical strike, whose visual 2759 hangs record 416 — `Spells\Strike_Impact_Chest.mdx`, the gold chest-impact flare reused at the hand tags 0x15/0x16 — on both hands via cast kit 3010 over a persistent `BloodLust_State_Hand` glow from state kit 3009, and every crit stacked another pair; `spell_fx::replace_same_slot` now runs per slot at every Begin for persistent and self-terminating instances alike, keyed on the RECORD id threaded through the fx lane (`FxSlot { tag, effect, path }`, the hardcoded map becoming name → (id, path)) and not the path, because two rows may name one .mdx and the reference lets those coexist, with both exclusions kept — the world plant and an already-decaying node — and four tests pinning the key's two halves and both; the other half of the report, that the burst is too large and too long, is a separate mechanism and is not touched — and the instrument that would have measured it was lying: `m2part` read a burst emitter's `peak_rate()` as its particle count, while the reference fires on the rising edge of `enabled != 0 && rate > 0` sampled on one clock, and `Strike_Impact_Chest.m2`'s gold flare steps its gate 1 → 0 on the very keyframe its rate steps 0 → 50, so the two are never true together and that emitter emits NOTHING; the tool printed "burst of ~50 particles, life 0.50s" and a diagnosis started 2.7× over on count and 1.7× over on duration off that one line; `EmitTiming::first_burst` walks the slot's keyed span at 60 Hz and returns the first instant the predicate holds or `None`, the dump prints the real count and time or `NEVER FIRES`, and a real-asset test pins that model's emitter #0 as never and #1 as exactly 30 (2057)
- a harmful spell's impact flinches its victim: benilla had one spell-side wound path, `play_kit`'s `[8,10]` branch — the kit player's own `0x60f3ad` test — carrying the KIT's anim id, so a spell whose impact kit names no wound anim, which is nearly every one (Fireball, Frostbolt, Shadow Bolt, Sunder Armor, a mob's Strike), twitched nothing, and a kit naming CombatCritical played 10 where the client plays 9 or 8; `0x60ea70` has six callers, not the three an earlier sweep found (`grep "call 0x60ea70"` over the full objdump was the one command it never ran): the missile hand-off `0x61dc50` lays the flinch before the impact kit for every living target (`0x61dc74`, HEALTH > 0; the already-dead arm `0x60ea30` plays Death/SwimDeath instead), the instant-hit ImpactKit loop `0x6e8bf0` lays it after the kit when `0x6ea280(SpellRec) == 2` (`0x6e8c89`), the reflect kit `0x6e8cb0` does the same on the caster, and every spell-side call pushes severity 0, so the id is always `0x60ea70`'s own `(severity, engaged)` pick — CombatWound(9) engaged, StandWound(8) otherwise — never the kit column; `0x6ea280` is the spell's hostility class and `== 2` ⇔ the spell targets enemies: Targets bit `0x100` → never, `0x80` → yes, else `EffectImplicitTargetA[i]` then `B[i]` for effects 0..3 indexed into the byte tables `0x6ea338`/`0x6ea378`, whose case-0 ids `{2, 6, 15, 16, 24, 28, 53, 54}` are exactly the modern enum's `*_ENEMY` set; so `WoundAnim { entity }` loses its id and the driver resolves every spell edge as `wound_anim(0, engaged)`, `play_impact` takes an `ImpactPlay` with `flinch` — the instant hits pass `SpellDisplay::is_harmful()`, a missile arrival passes true — `SpellDisplay` gains `effect_implicit_target_a/b` (columns 82–84 / 85–87) and `is_harmful()`, and the flinch is laid as the same secondary-blend overlay as a melee wound, over a cast, a swing or a run, never replacing them; pinned against the real 5875 `Spell.dbc` — Fireball, Charge and Sunder Armor harmful through A, Frost Nova through B alone, Renew, Healing Touch, Arcane Intellect and Battle Shout not — and the driver never picks CombatCritical for a spell edge; `WOW_MOVE_TRACE` gains `fct wound trigger/evict/expire` lines, since the whole flinch lifecycle was invisible in a trace; and the report this was chased under — the warrior's swings reading as cut short by incoming impacts in a many-mob brawl — stays open, with one reference gate found on the way that benilla does not model: `0x60ea70` aborts while any attached CEffect on the victim carries `+0x2c & 0x4` (`0x60eab6`), and which kit-spawned nodes carry that bit is the question dispatched to wow-re (2058)
- other players' roots, levitation and blinks now relay to onlookers: a report that a nearby player getting rooted, water-walking or Blinking slid or stood in the wrong place until their next movement packet was exactly right — a movement mode has three legs and benilla carried two, the mover's own acked handshake (`SMSG_FORCE_MOVE_ROOT → CMSG_FORCE_MOVE_ROOT_ACK`, 0866) and the server-driven `SMSG_SPLINE_MOVE_*` twelve (1780), while the third, what observers are told once the mover acks (vmangos `MovementPacketSender.h:30-60`, broadcast by `SendMovementFlagChangeToObservers` / `SendTeleportToObservers`), fell through `parse_server` to `ServerPacket::Other` and was dropped — so a rooted player kept sliding for the ~500 ms to their next heartbeat, a Levitate on someone else was never rendered, and a Blink left them standing at the old spot; six opcodes — `MSG_MOVE_ROOT`/`UNROOT` (236/237), `MSG_MOVE_HOVER` (247), `MSG_MOVE_FEATHER_FALL` (688), `MSG_MOVE_WATER_WALK` (689), `MSG_MOVE_TELEPORT` (197) — all the ordinary `[packed guid][MovementInfo]` shape and all sharing the client's one relay handler `0x603bb0` with the 22 already carried (wow-re's opcode-handler table has thirty rows on it; the remaining two are cheat opcodes vmangos never constructs), so admitting them to `is_movement_relay` is the whole fix for five: apply/unapply rides the flags word rather than the opcode, since vmangos runs `SetHoverReal` &co. before the broadcast and the word on the wire already carries the bit's new state, and `apply_move` already commits it wholesale into the union the ground resolve reads for hover's offset and the water-walk plane — the pose the packet carries beside the mode is half the value, a rooted player's stopping place being news too, and the root arrives already post-wipe with `MOVEFLAG_ROOT` forced back on, so no wipe of ours is invented; the teleport is a relay in shape and a discontinuity in meaning, so `RelayMove::reconciles()` excludes it from the pre-fire reconcile beside the heartbeat, for the opposite reason — the heartbeat because the dead-reckon has already converged, the teleport because there is nothing to converge to, and lerping toward a Blink's destination would drag the mover across the twenty yards the Blink exists to skip, sweeping the shared capsule through every wall between — while it still rides the unit's relay chain rather than snapping at arrival, because replay is paced against the sender's own stamps and applying it early would put the player at the destination while their walk to the launch point was still replaying; a `tp` tag joins `hb`/`tr` on the `rly` trace line; and parse and decode of all six are pinned against golden bodies asserted four bytes shorter than the counter-carrying `MSG_MOVE_TELEPORT_ACK` form, so a counter is provably not being read (2061)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
8584b89274 |
guild lines are message ids, mail sends again, and the shadow fades in
- the guild lines are message ids: `ui_guild/lines.rs` carried 34 English constants and two hand-rolled fill helpers and pushed composed text onto the chat log — 2045's largest ratchet row and the one file its rule had no route for, because `UiError`'s doc claimed the 1.12 formats use at most one `%s` and one `%d` and the type was built to match, while `ERR_GUILD_PROMOTE_SSS` is "%s has promoted %s to %s." — a wrong sentence in a doc had become a wrong type, and the wrong type had made a file's worth of drift structurally necessary; `CGGameUI::DisplayError` (`0x496720`) is cdecl varargs — `add esp,4` bare, `add esp,8` with one string, `SMSG_GUILD_INVITE` pushing two with the stack check exact at `0x30 + 0x60 = 0x90`, and `SMSG_GUILD_EVENT`'s emitter tail `0x5e745f` passing one, two or three off `strCount` — so `UiError` carries an ordered heterogeneous `Vec<FillArg>` (`S(String) | D(i64)`, since `ERR_USE_LOCKED_WITH_SPELL_KNOWN_SI` is String-then-Integer) behind four constructors naming the reference's call shapes (`key`, `s`, `strings`, `args`), twenty sites migrated; what the catalog knew and composed text could not carry: `ERR_GUILD_NAME_INVALID`/`ERR_GUILD_NAME_EXISTS_S` are kind 2 — the red line — and went to chat, `ERR_GUILD_CREATE_S`/`ERR_INVITED_TO_GUILD_SS` carry the LEVELUP cue and `ERR_GUILD_PERMISSIONS` (type_tag `0x3e`) is one the reference speaks (1815), all three silent; the default arm was missing outright — `0x5e745a` pushes `0x69` = `ERR_GUILD_INTERNAL` for `0x09` and every id past `0x0d`, catalog row 105 the whole time, so `TABARD_CHANGE` had been silent under a comment calling the key unsettled; a short `strCount` is passed SHORT (0 and ≥ 4 pass zero strings) so a starved specifier reads "…promoted Furor to %s.", not "…to ."; `/ginfo` deliberately stays off the queue — `GUILD_NAME_TEMPLATE`/`GUILD_INFO_TEMPLATE` are not catalog rows, `0x5e6fb0` resolves each token through the VM and emits chat itself, and a non-row key through `Shown::keyed` would turn a chat line red — so it waits on the guild feed and goes out unkeyed, the enUS month-day-year swap with it; the `_S` arity is asserted from the key names, 22 of 22; the ratchet row is deleted, 208 over 31 files remain (2054) - a unit's blob shadow asks the UNIT for its alpha: the lane gathered live `RenderFade`s off a unit's part entities and read "no part is fading" as 1.0 — true of a settled unit and exactly backwards for arrival, where a streamed unit holds `PendingAppearFade` with no `RenderFade` anywhere until the world is shown, so its parts were deliberately invisible while the shadow drew fully opaque; measured on a probe login: alpha 1.000 from t 0.61 to the arm at t 3.51, then 0, then the ramp — 2.9 s of dark oval under no creature, the symptom `model_render_alpha`'s own "pending ⇒ 0" law (0827) already named for emitters and ribbons; `model_fade::UnitRenderAlpha` is the one door, composed from the ROOT where `UnitAppearFade` tells pending from settled, published as one question rather than its three inputs so a caller cannot reassemble the mistake, and `DespawnFade::armed()` retires the `-1.0` sentinel from every caller; the world API wall goes 177 → 178; and wow-re settled what the shadow's alpha IS, four questions VERIFIED: it reads `CM2Model+0x180` through `0x710ca0`, not `+0x19c`; that slot carries the appear and despawn ramps, the self fade AND the CharProc-14 aura — `0x60d180` drives the same `StartAlphaFade` the appear fade does, so a stealthed unit's shadow now dims with its body — and not the per-batch M2 colour/weight tracks; and the reference draws nothing under a not-yet-shown object either (`+0x180 = 1.0 · 0.0`, written 30 bytes before the read), so this is fidelity, not taste; three module-doc claims corrected against it: the dead `0x683ea5` gate, the registration handoff (GameObjects and DynamicObjects never cast; units, players and corpses always do), and 1277's `InheritedVisibility` gate, which the reference lacks and stays ours on purpose (2055) - the mail stationery list was empty for the whole session, and every send with it: the five `dropping command — not connected` lines at login, once named, were `ItemQuery` for all five `Stationery.dbc` rows — `feed_mail` carried no run condition and asked from the login screen before the socket existed, the asks evaporated in the io thread, and `Items::template` had already latched all five in its ask-once `pending` set, cleared on disconnect and never on connect, so they were never re-asked and the stock `SendMailFrame_Reset`'s row-1 selection left every send silently unsent; the list now waits for a self player, and `release_ask_once_latches_on_enter` clears the pending sets at world enter, the counterpart the disconnect teardown never had — a redundant re-ask costs one packet, a wrong latch costs a dead feature nobody can see is dead; and three more log lines answer for themselves: a control character is answered before the shape — a newline is a line break the markup parser consumes, not a missing glyph — so the warn stays meaningful for a glyph a face genuinely lacks; the blend-check's one-frame run is the specialization tick catching up with a material swap, a real login showing four entries clear 26 ms later, so the warn waits for a run to SURVIVE the tick and a one-frame run is recorded at debug; and the audio starve line carries the wall span it covered beside the time it counted and the position it saw advance, because a 1.0 s window still closed 0.756 s of wall after the stream started on `Time<Real>` — if they disagree the caller's clock is still wrong, if they agree the starvation is real Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |