Commit Graph
20 Commits
Author SHA1 Message Date
SamandClaude Fable 5 14bd5ea1a4 the bank is the reference's own window, and far sight freezes your body
- the bank window is the reference's own `BankFrame.xml` run off the player's chain — our 890-line copy is deleted whole; putting bags into the bank's bag slots works (the two verbs its buttons are wired to now exist), the purse is a real `SmallMoneyFrameTemplate` splitting 987654321 copper into three coin buttons instead of one string, `BANKFRAME_OPENED` loses the argument the real client never fires, and the bank stops auto-opening your bags while the vendor and mailbox keep doing it; the empty-slot click still plays the bag sound, because the reference's own line plays it on every click the cursor did not consume — named as faithful rather than quietly fixed
- underneath it, the bank's inventory band is a VIEW over the container feed, not a second copy — inventory ids 40..69 had answered nil because the doll array stops at 24, so the stock file swapped in would have drawn an empty bank; the six bank bag slots become real inventory slots (64..=69) fed off the player descriptor, the three bag verbs are carved from the binary (`PutItemInBackpack` IS `PutItemInBag(0xFF)` through a ten-byte thunk, the occupied-by-an-ordinary-item leg auto-stores with no destination slot at all, and the return is the Lua number 1 or nil — the nil being the whole reason a plain left-click opens a bag), and the swap caught `BankButtonIDToInvSlotID`'s bag arm six slots wrong: it took a bag number 1..6 where the reference passes the button's own id, which is the container id
- far sight freezes your own body while the view is out — the fifth conjunct of the movement predicates' shared precondition, joining the health term so the walk, the turn and the follow teardown go down together; both halves are load-bearing: the `IsActivePlayer` half is what keeps a Mind Control victim walking (possession rides the same PLAYER_FARSIGHT field), and the latch half is the RESOLVED engage rather than the raw field — and the camera is untouched, you still look around freely, which is the whole point of the spell
- the reset offer no longer outlives the character that earned it — log out after walking out of the Deadmines and your next character was offered a reset the first one had earned — and the one lockout leg no probe can ever reach (vmangos writes a last-instance map only from raid binds, which the client's handler discards as not-a-party-dungeon) is now covered end to end through the real system, its module doc saying plainly: tested and never observed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:18:51 +07:00
SamandClaude Fable 5 8ae42cc7ab 71 more key commands, and the quest windows wear the reference's names
- the binding registry goes 130 → 201 of the client's 228 live commands: a coverage gate makes registered ∪ recorded-absent exactly the 1.12 surface, each absence naming the Lua globals whose arrival refutes it — which is how 37 rows whose mechanism had already landed came home (the keyring, the pet book, the raid tab, the six action-bar pages, both vertical multibars) — and then four mechanisms bring 71 more: the five camera views with the reference's default table and its sixteen camera CVars read out of the binary (NextView/PrevView do NOT wrap), self-cast riding UseAction's third argument with autoSelfCast a real CVar at last, the friendly target cone / assist / last-hostile as one cycler with a side (the two sides use different deadness tests on purpose, and assist neither requires an assistable target nor swings), and REPLY2 — reply to the last person you told; the friendly cone also stops borrowing the enemy side's in-combat score bonus, which would have shoved a healer targeting you to the head of every cycle
- the key names close their gaps: NUMPADEQUALS, F13-F24 and BUTTON6+ were keys the binding window listed and the file saved that the dispatcher could never press — named both ways now, with the namer and the codec structurally unable to disagree again; platform= becomes the OS gate it really is (off a Mac build the iTunes-remote category never even exists), and the Mac 1.12 slice settles that its F13 IS print-screen while F14/F15 map to UNKNOWN on purpose and stay unbindable; and the last-enemy stamp gains the four conjuncts it shipped without — you resolve, are not dead, not a ghost, not mounted, and the new target is alive-or-feigning — so TargetLastEnemy can no longer land somewhere the real client's never would
- the quest windows wear the reference's names: ~40 of the quest window's globals were ours (the reference's name usually sitting in the comment beside them), its two six-item reward pools merge into the reference's single ten-item run with the update function ported line-for-line, the four panels and the quest log take REAL scroll frames (the thumb drags now), the gossip window gets its greeting panel, the two mail panes' inert painted-at-rest scrollbars become real ones, the Skills detail pane nests as the reference has it, and nine private constants take their real names; the one that broke a feature detect: our QuestLogCount — a name 1.12 doesn't publish — made pfUI conclude it was running on TBC and die in that branch
- an EditBox is born with its constructor's five regions (the text, three selection quads and the caret), so GetRegions answers the reference's own count and authored regions start at index 6 — and a bare <NormalTexture/> now builds a live blank texture, since the element is what creates the region, not its file=; OpacityFrame lands, its first customer having arrived; and the equip / auto-equip / use bind confirms complete the soulbind arc — three different predicates with no quality leg (borrowing the loot arm's would have silenced the confirm on every white bind-on-equip item), Accept re-issuing the original action with the reference's suppress flag because 1.12 ships no confirm packet, and the soulstone use going through the same gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:16:49 +07:00
SamandClaude Fable 5 542c2ac04b being summoned is a dialog, and a soulstone raises you where you fell
- being summoned becomes the dialog it should have been: the summon request was a name-table entry and nothing else, so a warlock's ritual, a meeting stone and a GM's summon all ended with the summoned player seeing nothing — now the three-field question raises CONFIRM_SUMMON and Accept sends the one guid back; the bytes settled three things a reasonable guess gets wrong: the refusal gate is dead OR ghost and lives in the handler (a ghost's wire health is 1, so the health leg alone lets one through — and refusing before the latch means an ill-timed summon can't silently overwrite a live question), the event carries no arguments because the popup re-reads all three getters every frame (the only way the summoner's name can appear after a cache miss), and there is no decline — Cancel, ESC and the clock running out are all silence plus the server's own two-minute timer; exercised end to end by a two-client live probe, the only thing that can, whose final assertion is that you land in the zone the dialog named
- self-resurrect is one private field and one bodyless opcode: PLAYER_SELF_RES_SPELL carries the stored spell and CMSG_SELF_RES spends it; HasSoulstone answers the Spell.dbc NAME of that spell, because that is where Blizzard put the button text — "Use Soulstone", "Reincarnation" and "Twisting Nether" are the spells' own names — and UseSoulstone sends on the death dialog's second button; a --self-res probe runs the whole arc on the live wire and measured the thing that matters: the field arrives BEFORE the health-zero flush, which is what makes the dialog's OnShow read safe
- the decode's fold-in corrected three claims we were resting on: HasSoulstone has a dead gate that runs FIRST, so a released ghost (wire health 1) loses the button at release rather than the dialog merely hiding; a zero field is not the empty answer — the client walks your carried inventory (gear, bags, backpack, keyring; no bank, no buyback) for an item whose on-use spell self-resurrects, labels the button with the ITEM's name and uses the item instead of sending, the two legs exclusive; and an unresolvable spell id labels the button "UNKNOWN" rather than hiding a self-res the server is holding for you

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:16:13 +07:00
SamandClaude Fable 5 164b0a7a44 names persist, the GM notice is a toast, and the target reads Dead
- the name cache persists to `benilla-config/cache/<realm>.tsv`, because the reference's `namecache.wdb` / `petnamecache.wdb` do and that is why it never sees the races we lost every time — unstabling a pet raised `Usage: SetText("text")` off an unresolved `UnitName("pet")`; the header carries magic, format, build, locale and realm and any mismatch discards the file (no checksum, no TTL: eviction is explicit only, via `SMSG_INVALIDATE_PLAYER`, decoded now and never sent by vmangos), negatives persist too, written on a 10 s debounce and at exit; a stable list also seeds the pet-name cache from the names it already carries
- `SMSG_NOTIFICATION` is the red UIErrorsFrame toast, not a chat line — `.gm on` printed twice because vmangos sends both a system message and a notification and both were rendered as chat; the stand-in dated from before the errors frame existed; `SMSG_AREA_TRIGGER_MESSAGE` moves with it on the yellow arm (its handler ends `xor edx,edx` — flag 0 — where the notification's is flag 1)
- the target frame's dead text is the GlobalString `DEAD` = "Dead" resolved through `text=` like the target-of-target frame, not the key typed into `SetText` in caps, and it takes `UnitIsConnected` so a disconnected player does not read as dead; a shipped-script sweep now refuses any key-shaped literal handed to a text sink; and the Help window is one click deep — Home's button opens the ticket text box, Auto-Unstuck sits beside it, and a ticket files as category 0, which a GM's queue names "Unknown" (a guard added days earlier refused 0 on reasoning from the enum rather than from the function that reads it)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:23:05 +07:00
SamandClaude Fable 5 6a8df87219 edit boxes take focus the way 1.12 does, and the stable shows its pets
- the caret was a wedge in the line: it sat in flow, four units wide, so focusing a login box shoved its text right by one caret and a caret parked mid-word opened a gap; it is a zero-width seam now with the bar drawn as an overlay (a 0×26 seam and a 5×26 bar at the same x, off a node probe), the way the reference anchors its caret quad over the FontString; a blurred box collapses its selection so only the box holding the keyboard shows one; and a dialog answers only keys pressed while it was already on screen — ENTER on an empty form used to open the error dialog and close it in the same frame
- `autoFocus` defaults ON in the reference (the ctor leaves flags = 1, and every one of the ten `autoFocus` attributes in the shipped chain is an opt-out), showing an autoFocus box focuses it after its `OnShow`, and hiding the focused box releases the keyboard — the "never focuses on show" note we had transcribed came from a `call`-only census that missed a tail `jmp`; the loader's flag loop could only ever turn a flag on, so `autoFocus="false"` was a no-op, fixed before the default flipped or it would have grabbed exactly the ten boxes the reference exempts; and the EditBox does fire generic `OnChar` with the spliced string, on every typed or pasted character and never on `SetText`
- the stable master's portrait was a black disc (its session was missing from the `"npc"` token chain — the third window to ship that way, so the test is now exhaustive over every `impl NpcSession` and names the one you forgot) and its model pane draws the selected pet: a stabled pet is a database row with no world entity, so a `PortraitStandIn(display_id)` — an entity that exists only to be mirrored — feeds the existing booth code unchanged; plus the registrar's two service rows were hidden by an inherited attribute, a charter's tooltip carries the guild name and master on line 3, and the Help window drops three strings pointing at a company that stopped answering

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:22:27 +07:00
SamandClaude Fable 5 a5cb3cf746 guild charters: the registrar, the charter, and the twelve verbs
- founding a guild: fourteen opcodes, eight goldens (four mutation-checked), twelve engine globals, `GuildRegistrarFrame` and `PetitionFrame` — `CMSG_PETITION_BUY` is a 72-byte frame the server reads two fields of and drops in silence if short, `allowedGender` is the family's one u16, a signature is a 12-byte stride not 8, and `MSG_PETITION_DECLINE` writes the charter guid and reads the decliner's — same width, opposite meaning
- two sessions, not one: the registrar is an NPC session (closed by walking away — its show event is one of the fourteen callers of the interact latch, so the registrar turns to face you) and the charter is bound to an item guid you carry across the city; right-clicking a charter in your bags opens it, keyed on template flag `0x2000` (item 5863 has no on-use spell and no quest, so every existing item-use arm declined it)
- the byte carve came back and rescored six named guesses — three confirmed, two corrected, one refuted: `PETITION_SHOW` is deferred until every signer name has resolved (the window never paints blank rows), `ClosePetition` on somebody else's charter sends `MSG_PETITION_DECLINE` ("sends nothing" had been chosen on principle and was wrong half the time), and founding a guild is silent — no `ERR_GUILD_FOUNDER_S`, the reference emits no text at all; the four success ids go to chat and the five refusals to the red error frame, three paraphrased strings are now the shipped ones (a sweep asserts all fifteen), and the `npc` unit token had never been fed — the registrar's name banner was blank; `WOW_PROBE_CHARTER=1` drives gossip → buy → open → rename → destroy live, 10/10

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:21:00 +07:00
SamandClaude Fable 5 034c48f2cb raid tab art is back, set bonuses fit, and 12 voices bound the mix
- the mix is bounded the way the reference's is: FMOD gave 1.12 exactly twelve software channels and nothing else limits a priest buffing five people — ported as a 12-voice ceiling (a probe capture read 42 live voices at +13 dBFS, the limiter pumping 13 dB to hold it), plus same-kit copies started in one frame capped at two, since five sample-aligned Fortitudes are one sound +14 dB; `$WOW_SOUND_PROBE` records the mix before and after the limiter with a timeline, F9 stamps the moment
- the raid tab draws its window art again — its four corner textures were written with single backslashes, which Lua drops silently, and a sweep now reads every archive path a shipped Lua chunk names; a drag whose release never arrives (pointer left the window, a second press) ends instead of gluing the frame to the cursor for the rest of the session, and `WOW_PROBE_DRAG` drives any UI drag headlessly in a live client
- the item tooltip fits its set bonuses again: an emptied line kept its last measured height forever (a pooled cell with no way to say "empty"), and the two blank rows above the set block are the reference's own literal (a space and a newline) — a whole row each, not the empty string
- an equipped BoE or BoP piece reads Soulbound: the bind line reads the item's own flags through the client's bound predicate instead of the template's bonding, one predicate shared with the enchant cursor's bind confirm

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:25:07 +07:00
SamandClaude Fable 5 dddf16e963 the auction house opens, the Honor tab lands, and a day of fixes
- the auction house end to end: right-clicking an auctioneer opens Browse/Bids/Auctions on the server's reply — search, the category tree from your own DBCs, the reference's 50-a-page pager, multi-key sorting (directions corrected at the bytes), bid/buyout, the sell slot with deposit and duration, cancel with its fee popup; prices sit on the reference's own money-frame kit in lined-up columns, the twenty auction messages split refusals-red / outcomes-to-chat, and a won or sold auction reads as a proper mail receipt — the window's Lua re-worded in our own terms after the overlap ratchet caught the first cut leaning on the reference's text
- the PvP honor system whole: the Honor tab and the inspect page over a real wire model, with current rank and highest-ever rank correctly two different fields
- a day of reported fixes: WASD survives a /logout re-entry, addon settings save on a window close and Cmd+Q (exactly once — a mac close could fire the tail twice), clams open again, random-enchant items name themselves on every surface, the loot window's rows hold their seats with legible counts, idle players stop sinking through building floors, the shooter re-pulls between Auto Shots, portraits loosen ~19% to the client's own aspect-1.0 matrix, and big creatures thump the camera off the CameraShakes table
- character select clicks like 1.12 — captions whiten on hover, buttons fire on release, Humans face straight ahead off the stage bone's real yaw, the facing is per-character, and hunter/warlock pets stand beside you at their family-ramp size with their own emitters (the imp's flames), the Voidwalker's sequence-hidden shackles culled
- the smaller player-facing set: nameplate on/off rows in Options with the CanAttack category gate (emissaries stop plating), the bonus bar slides up with igBonusBarOpen, the camera's framing height glides on a shapeshift, the open letter evicts the centre seat, the far-band fog hull stops printing a pale horizon stripe at low view distance, the guide arrow is gold with per-source rim art, error text fades through its shadow too, and /convertraid converts the party
- README: the auction house and PvP honor move out of "not built yet"

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 19:04:27 +07:00
SamandClaude Fable 5 312e123fb7 windows take turns, the gossip page waits, the shot bar counts down
- the UIPanel registry is re-derived from the reference's bytes: the readable-item page finally registers, so a note or letter closes when a gossip window opens instead of interleaving with it line for line; the character sheet takes its real pushable-2 seat (an NPC window slides it over instead of replacing it), and the spellbook, quest log, talents and character sheet open for dead players again — a refused open now says "You can't do that when you're dead." instead of doing nothing
- the gossip window waits for its greeting: the first packet carries only the options and a text id, and we used to show the frame with a blank page for the round trip the text needed — the menu now exists only once the text has answered, a mid-flight click is refused, and a revisit is instant off the cache
- a bag slot whose stack count changes on the server now fires `ITEM_LOCK_CHANGED` just ahead of its `BAG_UPDATE` — the one signal 1.12 hunter addons use to detect a spent arrow — so Quiver's auto-shot bar drains per shot instead of pinning at 100%; a swap or create deliberately does not fire it, so rearranging bags can't read as a shot
- the outdoor minimap tiles' gamma byte reaches the screen exactly once — the ordinary decode arm learns the same skip the fast path already had

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:17:03 +07:00
SamandClaude Fable 5 74c3b47a7f event-driven UI feeds, and the character window's cost lets go
- the eight heaviest UI feeds — spellbook, party, character, bags, talents, units, pet, player — rebuild only when an input moved instead of every frame: 216 → 12 µs a frame parked
- the character window's cost settles once it closes: enchant countdowns feed by the second instead of firing an inventory event into all 20 slots every frame, the paper-doll booth parks with its camera, and a window hidden under the cursor fires OnLeave so its tooltip goes with it — the reference's hover-hide law
- the walk stops paying for finished work: the loading-screen tally's per-placement walk latches off once the world is ready, the settled placement spawner is one integer compare, and billboards stop dirtying every card's transform
- never-rendering hierarchy nodes — rig anchors, joints, doodad hosts — keep the hide chain but leave the per-camera visibility sweep: 25,198 → 18,026 swept entities at Goldshire

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:01:11 +07:00
SamandClaude Fable 5 d99435beb8 the performance hunt, day one: the frame sheds 1.85 ms
- UI layout solves what moved, not what exists — hovering a full bag no longer re-solves the whole interface
- world albedo textures stop keeping a second copy of themselves in RAM
- collision gets a coarse grid for oversized slabs (32x fewer triangles tested), idle units stop re-asking the ground every frame, and anchors spawn on first consumer instead of by the thousand
- aura and loot watchers scan when the store changes rather than on the clock, and static-transform tracking and plate reaping join the sweep

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:49:54 +07:00
SamandClaude Fable 5 b990a5a048 script errors reach the player, and the bars stop lying
- an addon error shows the red script-error dialog the reference shows, and a runaway load loop can no longer freeze world entry
- food and drink show stack counts from the first login, and a paladin's aura bar lights the aura that is actually on
- logging out no longer erases the character from saved-bag addons: the player's absence is no data
- MPQ patches are discovered the way the client discovers them, and a slow arrival holds in place instead of falling through the world

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 19:32:44 +07:00
SamandClaude Fable 5 7d826e673a the UI is built per login, and stray beams stay in their rooms
- the in-game UI ends at the character screen and is rebuilt at the next login, so addons that read the character at file scope stop being frozen on whoever logged in first
- everything the host remembers about a UI is keyed on that VM's identity — keybinds, macro icons and every feed survive the rebuild instead of silently pushing nothing
- a ribbon trail rides the room its model is drawn by: Caverns of Time's ninety energy trails stop burning through 200 yards of rock
- the visibility census gains the sky and ribbon lanes it could not see, and the logout leak probe measures after the release instead of accusing every run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 19:27:39 +07:00
SamandClaude Fable 5 56d515a374 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>
2026-08-14 19:02:01 +07:00
SamandClaude Fable 5 44ff435304 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>
2026-08-11 18:18:31 +07:00
SamandClaude Fable 5 bfb3e3addc the player build: one binary that carries its content
- a player build ships beside the dev one — dev chords and probe surfaces go dark, and a gate enforces what a player can still reach, by medium not by module
- the binary carries its own shaders and its shipped UI, finds the WoW folder by itself, and keeps its local state in one benilla-config folder
- the glue screens get a capture shutter, and the engine stops depending on the protocol crate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:18:02 +07:00
SamandClaude Fable 5 bdef9cd790 benilla-world: the engine becomes its own crate
- the world engine splits from the game into a benilla-world crate — 112 files, and the wall is ratcheted to zero names of the game inside the engine
- the engine's public doorway is counted and gated at 32 items, and the render materials, shaders and asset cache move down to benilla-assets
- the game's files leave the engine's asset root — game:// is its own space — and a spike binary boots the engine with no game attached
- weather rides along: snowfall emission is denominated in the reference's frame cap, and a long teleport retires the stranded precipitation field instead of leaving it behind

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:13:44 +07:00
SamandClaude Fable 5 6c6a0c9b88 quest timers, honest interiors, and snow rebuilt from the bytes
- timed quests get their countdown — a Quest Timers box under the minimap and a Time Remaining line in the quest log, kept against the server's own clock
- interiors go honest: footsteps stop crunching the terrain's snow through a building's floor, and tavern voices are authored dry, so the fake cave echo is gone
- snow is the reference's again — point-sprite flakes at the era's pixel size, and a spawn slab that leans into your run so a runner no longer outruns the field
- Stormwind stops drawing Elwynn through its walls, a looted quest crate's lid settles, cold zones puff visible breath, and the collect-quest toast fires only on a real advance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:00:02 +07:00
SamandClaude Fable 5 d16d33dfca world books open, and anvils stop offering a cursor gear
- clicking a book in the world opens it and turns its pages: letters and world books share one reader
- the cursor's object rules are the client's own 31-row strategy table now, so decorative objects stop pretending to be usable
- trainer and tradeskill windows draw each row's icon by the reference's own law, and the trainer's filter dropdown toggles again
- water color follows the zone's light blend, so lakes stop snapping between area tints

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 16:03:35 +07:00
SamandClaude Fable 5 3b6975fdef the pet gets its frame, flooded rooms fill, and macros really fire
- the pet gets its own unit frame beside yours, and an Attack order no longer latches as the standing command
- five rooms that always read bone dry hold their water now, the Deeprun Tram's flooded stretches among them
- macros fire through the client's own chat door, and the macro window fits its tabs and scrolls its icon chooser
- the options window grows a Nameplates page and its first dropdown, and the name-display switches apply live in the world

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 19:03:43 +07:00