05e204de1052579b1012c0e27f71eb254a8ebbbf
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a21fb2750a |
The stock video options window opens, saves, restores defaults and cancels clean: its CVars are registered, spellEffectLevel drives the particle and shard rates, and the video pairs, frame enumeration and client queries are defined (#565)
The stock video options window (`OptionsFrame`, off the player's chain) now opens, saves, restores defaults and cancels with no Lua error, as on 1.12.1. - The CVars it reads are registered at the reference's defaults: `SmallCull` "0.04" (`0x68854a`), `shadowLevel` "1" (`0x6885bc`), `baseMip` "0" (`0x6887aa`), `DesktopGamma` "0" (`0x402d4d`), `spellEffectLevel` "2" (`0x688900`), plus `doodadAnim` and `texLodBias`, which the new getters read. `SetWorldDetail` keeps `SmallCull` in step (`0x488e56`), and the wrong comment that called the getter its only reader is gone. - `spellEffectLevel`'s handler (`0x689510`): the value is clamped to 0-2, "Spell effect level set to %d." is printed, the particle emission scalar is set to 0.33/0.66/1.0, and the shard emitter's rate follows the level (`0x6eb95e`). - The 21 functions #337 lists: the six video getter/setter pairs (`0x488ec0`-`0x489300`), `GetNumFrames`/`EnumerateFrames` in creation order (`0x705f00`, `0x705f60`), and the client queries, including `GetDebugStats` and `OpeningCinematic`'s empty `CMSG_OPENING_CINEMATIC` (0xf9, `0x48c8c9`). Verified: a headless test walks the stock window's 18 boxes and 9 sliders, then Okay, Defaults and Cancel, with no error (it fails on main at `OptionsFrame.lua:146`), plus unit tests for each binding and handler; 12 mutations each fail a test. A live run opened the window, saved, restored defaults and cancelled with no Lua error. `scripts/gates.sh` green. Built on macOS; no platform seam touched. Fixes #548 Fixes #337 Refs #329 (benilla's own options window has no Spell Detail row yet) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
fd386e75ae |
Comments in benilla-ui: one line of fact each, no history, no record numbers (#143)
Part of #41: the comments of `benilla-ui` (the Lua UI engine, its FrameXML loader and its widgets) are rewritten to the rule in `docs/METHOD.md`, which is what the code does and the reference fact behind it, in a line. 43,140 comment lines become 15,161. - **The mechanical strip.** The citations that were only a private record number go first, and each edit is shown to be a pure removal. - **Wrong facts corrected.** The rewrite corrects the comments that stated wrong facts. Among them: - `0x64a480` is the case-sensitive compare (a byte `repz cmpsb`), and `0x64a4c0` the case-insensitive one. - A frame's id sits at `+0xb0`, not `+0xb4`. `EnableKeyboard`/`IsKeyboardEnabled` are `0x776ec0`/`0x776f90`. - A region's unpinned edge has no fallback to its owner's rect: the owner supplies only the scale. - `$parent` expands to the nearest named ancestor, or "Top" when none is named (`0x76c5b0`), not simply to the parent. - A StatusBar fills from its internal normalised fraction, not from `GetValue()`. - The addresses of `StartDuel` and `StartDuelUnit` were swapped. - Many "untraced" notes now give the traced reference fact: the drag threshold, the per-grip sizing edges, the empty-`autoFocus` skip, and `SetTexCoordModifiesRect`'s default. - Stock FrameXML line citations are checked against the stock 1.12 files and corrected. `ref-` file names become the stock file names. - **Deviation labels.** "Deviation:" now marks only a choice with a reason. A surface that exists only for the retired Era addon target says so plainly: it is not 1.12. - **Verification.** Every file strips to identical code, and `cargo fmt --check` is clean. Nine second readers compared every file old against new, restored the facts the rewrite had dropped, and checked each new citation against the code, the stock files, vmangos and the reference. Behaviour differences the rewrite surfaced are filed as their own issues (#131–#142), and more are being validated. The comments here state what the code does. String literals are untouched; they are #92. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
8952d590e6 |
comments cite the reference by address, not by private note (#30)
Comments that pointed into the maintainer's private reverse-engineering notes (a note by name, a path, a section or finding id, the analysis's own name for a client function, a process word) now carry the fact itself, cited by the reference client's address, by vmangos file and line, or as "the reference". Nobody outside could follow those pointers. Comment text only, plus the test-assert and log strings that carried the same pointers. No claim changes: a comment the notes have since corrected keeps its wording here, and correcting it is separate work. The two reference generators, `scripts/gen-reference-globals.py` and `scripts/gen-reference-verb-events.py`, named the private notes' layout to find their inputs. They now take the input files as arguments (`--capture`, `--framexml`, `--names`, `--extents`, `--disasm`). Run on the same inputs, both write the committed tables row for row; only the two header lines that named the old environment variable change. Checked per file: - the code is identical: each file with its comments stripped compares equal before and after; a changed string literal is compared under a mask that proves only literal text moved and every literal kept its line count; - no client address the old text cited was dropped; - a second reviewer checked every added address against its derivation; - a detector for the notes' names, paths, ids, function names and process words finds none left; - `scripts/gates.sh` is green. Co-Authored-By: Claude Opus 5.5 (1M context) <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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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>
|
||
|
|
7e68267395 |
the raid and reputation panes go stock, and a faction header folds
- the raid and reputation panes are the reference's own files: two manifest lines replace our `RaidFrame.xml` (83 of 84 frame names were already the reference's; the tear-off pullouts arrive) and one replaces our `ReputationFrame.xml`; the raid swap surfaced a loader defect (a font object inherited one level down was the 26 unexplained warnings), rehomed `RaidFrame_LoadUI` and two popup dialogs, and reproduces one reference DEFECT: an emptied lockout list keeps its last row painted (1874); the reputation swap moved the WATCH BAR out of `ActionBar.xml`, where it would have shadowed the chain's own, and exposed an ENGINE gap: `CollapseFactionHeader`/`ExpandFactionHeader` fire `UPDATE_FACTION` (`0x4d5dab`) and ours fired nothing, so with the stock pane repainting on that event alone, a fold painted nothing and the header kept its minus — invisible while our own file repainted itself (1875) - a wanted poster is a questgiver on the wire as a creature is, and benilla never asked about one; the RE round came back in two halves: the reference DOES send `CMSG_QUESTGIVER_STATUS_QUERY` for a GameObject, gated on `GAMEOBJECT_FLAGS` bit 2, seen in 20 of 62 sniffed sessions — and it can never render the answer (the status handler's typemask excludes a GameObject, its status slot lies past the object's end, and no poster, sign or plaque carries attachment 18); vmangos DOES answer, so the sweep gains a GameObject arm on the reference's own gate and the apply side refuses a non-unit guid, without which a gold `!` would hang over a poster no 1.12 client draws; two shipped claims fall with it (`0x5eb3c0` is the FULL re-query sweep; a status never suppresses a GameObject's minimap dot), and `WOW_PROBE_GOQUEST` at the Goldshire wanted poster reads the server's 1 then 5, both refused (1872) - the money entry comes off the chain: Trade, Mail and Auction switch to the reference's `MoneyInputFrameTemplate` and its verbs, and our `BenillaMoneyInput_*` kit retires — it was the exact answer while benilla fired `OnTextChanged` synchronously inside `SetText`, and the engine now raises it deferred and coalesced, matching `0x77d3e0` (1831), so the reference's `expectChanges` guard works and our bracket flag was a duplicate; most of the 430 deleted lines are verbatim art — all three windows carried an inline copy of the template's three edit boxes, AuctionFrame a whole second copy; one visible change: TradeFrame now makes the reference's own `MoneyInputFrame_SetMode(this, "compact")` call, which tightens the trade money boxes (Gold 58→56 wide, Silver's offset 26→22, Copper's 16→11), and two stale claims in the kit's comments are corrected, and a verb nothing called goes (1882) - the `UIFrameFlash` family is transcribed — six FrameXML names from `UIParent.lua`, which we do not load — unblocking SpellBookFrame and HelpFrame, which called it into silence; re-arming a flashing frame is a RETURN and `-1` flashes forever (1879); UIParent is recounted — `UpdateNameplates` and the `*_Show`/`*_Hide` family around it are FrameXML, not engine, missed by a survey that skipped the LoadOnDemand addons — so its engine surface is four verbs, not a wall: `GetLocale` answers `enUS`, `IsMacClient` answers nil (the whole verb on the PC build), and `CheckReadyCheckTime` and `RequestBattlefieldPositions` are the two it waits on (1880); and `BasicControls.xml` comes off the chain by pure deletion — ours differed by nothing but line-wrapping and one comment — with `FailedAddOnLoad` and `UIParentLoadAddOn` moving to `UIParent.xml`, their reference home, below their four callers (1881) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
b45bce8184 |
bindings answer the reference's shapes, and the panel kit goes stock
- four return shapes were wrong — `UnitPowerType` returns ONE value in 5875 (the Era `(type, "RAGE")` pair does not exist, and its miss arm pushes the NUMBER 0, which `UnitFrame.lua:122` indexes `ManaBarColor` with), `UnitName` returns `(name, server)`, `GetTexCoord` returns EIGHT (ours four — a shape that exists nowhere, with zero call sites in FrameXML, so only the binary could have caught it), `GetLootMethod` answers `freeforall` ungrouped — the fifth right-name-wrong-arity finding in two days, so wow-re's `binding-shapes.tsv` (1722 rows over all 82 registrar tables) is vendored and a gate probes every binding's arity against it: 313 probes, eight divergences (seven global, one widget); `GetBuildInfo` pushed a fourth value no 1.12 client does (458 corpus sites take one, the four that destructure a fourth read nil on the real client), `GetAddOnInfo` RAISES on a numeric index, `Model:GetFogColor` is a packed `0xAARRGGBB` dword with no unset state, and the five miss branches are the reference's exact tuples - the panel-template kit is the reference's own `UIPanelTemplates` pair (our 18 templates were a strict subset — `TabButtonTemplate` and the `ScrollingEdit_*` family arrive, which unblocks the macro window and HelpFrame), and the swap found two structural facts: `FauxScrollFrameTemplate` is a `<ScrollFrame>` while every instance we declared was a `<Frame>` (fifteen elements across twelve files), and an instance `<OnLoad>` REPLACES the template's — four FriendsFrame lists set `updateFunc` in their own OnLoad, so `ScrollFrame_OnLoad` never ran and guild/friends/ignore/who had been silently painting nothing behind a `frame.offset or 0` - the options widget kit (`OptionFrameBoxTemplate`, `OptionsButtonTemplate`, `OptionsCheckButtonTemplate`, `OptionsSliderTemplate`) comes off the chain too, giving back the reference's own per-widget hover; one template of ours stays because `UIOptionsFrame.xml` is not built here, and the lesson is general — when a file SHRINKS rather than dies, every harness that named it gains the chain entry beside it, not instead of it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
acbae000a6 |
an addon loop reports instead of hanging the whole survey
- every addon VM runs under an instruction bound, so a non-terminating loop becomes a report — and the bound promptly caught a landed fix that had been left switched off - an unrecognised unit token raises the client's own "Unknown unit name" error instead of answering nil - GetBindLocation answers from a real bind point, and RequestTimePlayed round-trips with TIME_PLAYED_MSG — both halves or neither Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
251daa14c5 |
addons come alive: Bagnon draws, hovers and clicks
- Lua 5.0's generic-for and nested long strings are restored in a forked VM — 60 corpus addons stopped dying on one deleted opcode - a day of demand-driven carving takes the 218-addon corpus from 24 addons surviving a session start to 114, with 144 loading without a single error - Bagnon draws a real bag and answers real gestures — hover tooltip, pickup, use, drag — because our frames wear the reference's names, and the reference's own ContainerFrame.lua runs off the player's install instead of being transcribed - the physics broad phase leaves: nothing in the client reads a contact, and it was measured at up to 41% of main-thread samples in real sessions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b5bc569156 |
the addon arc: the AddOns folder opens
- benilla loads real 1.12 addons from Interface/AddOns — TOC, XML and Lua through one loader, with per-addon saved variables, Bindings.xml and the lifecycle events addons expect - both AddOns screens are in: the character-select list with per-addon enable state, and the ESC menu's in-game list - the API surface is measured, not guessed — a corpus harness runs hundreds of real 1.12 addons and ranks exactly which globals, templates and verbs they demand - the Lua dialect is the client's own, read off the binary — 5.0 semantics with the 1.12 additions, and UI source files are bytes, not UTF-8 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |