From e70654ac010299491d861c9d026a4c46576f0309 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 31 Aug 2026 20:14:48 +0700 Subject: [PATCH] the select-screen ghost is four mechanisms, and a click raises windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - the select screen's ghost is four mechanisms off one roster-row bit, and the rest of them land: the FFX pass swap — the reference builds TWO pass pairs, world and glue, and a ghost row installs the glue DEATH pass over the whole diorama while the character list and buttons composite clean above it; the ghost-gated sun — the scene's light gather is wiped and one hardcoded overhead directional injected, its colours turning out to be Light.dbc's death preset (diffuse (94,153,198), ambient (26,56,85)) rather than the live capture we had parked them as, with the sign settled at the bytes (an authored light already carries one negation, so reusing that convention lights the ghost from underneath); and three glow weights corrected — the glue screens pin 0.30 login / 0.40 living select / 0.15 ghost where we rendered a flat 0.5 everywhere, so login and create get slightly less glow too, a fidelity correction to a value we had never verified - a press brings its window to the front: the mouse-DOWN handler raises the capture-or-hover frame unguarded, the toplevel gate living inside the worker — which is what makes a click on a child raise the window that owns it — and the release never raises; behind it, a frame-by-frame diff against the reference put back what the transcription dropped: toplevel on 47 frames (without it every raise trigger was a silent no-op across the whole interface), the mouse on 16 window bodies (a click on the bank's or merchant's own background was turning the camera or dropping your target), and id= on 81 frames — the slot index a 1.12 addon reads, where GetID() answered 0; a new gate reads our flags off the LOADED engine against the reference's, both directions with a reason each, so the next drift can't hide behind renamed templates - the jump stops being frame-rate dependent: the fall step becomes the reference's closed form (the mean of the endpoint velocities is the exact displacement rate, and both our movers had the error in opposite directions), taking the apex from 1.668 yd at 144 fps and 1.844 at 20 to a flat 1.640 against the analytic 1.640 — a live run apexed at 1.6410; and the knockback's freeze is its PLANTED direction bit, not a velocity test — air control opens exactly while the direction nibble is clear, the launch plants forward whatever its speed, and the bit now rides the wire, which we had never sent at all - the walk-away leash belongs to the OBJECT: the reference's watchdog overwrites the opener's stored range on the player typemask bit alone with (10+4)², so a player-shared quest panel is leashed at 14 yards — not at the 5.56-yard NPC reach, and not never, as two earlier readings had it — while a census of all 14 arming sites confirms every other NPC window already closed at the right distance; the walk-away also sends strictly LESS than the button: an NPC panel closes silently while a share still owes its decline Co-Authored-By: Claude Fable 5 --- crates/benilla-app/assets/ui/ActionBar.xml | 26 +- crates/benilla-app/assets/ui/BagFrame.xml | 2 +- crates/benilla-app/assets/ui/BankFrame.xml | 2 +- .../benilla-app/assets/ui/CharacterFrame.xml | 51 +- crates/benilla-app/assets/ui/ChatFrame.xml | 6 +- crates/benilla-app/assets/ui/DressUpFrame.xml | 2 +- crates/benilla-app/assets/ui/ErrorsFrame.xml | 2 +- crates/benilla-app/assets/ui/FriendsFrame.xml | 2 +- .../benilla-app/assets/ui/GameMenuFrame.xml | 8 +- crates/benilla-app/assets/ui/GossipFrame.xml | 2 +- .../benilla-app/assets/ui/GroupLootFrame.xml | 34 +- crates/benilla-app/assets/ui/HelpFrame.xml | 7 +- crates/benilla-app/assets/ui/HonorFrame.xml | 25 +- crates/benilla-app/assets/ui/ItemRef.xml | 2 +- crates/benilla-app/assets/ui/LootFrame.xml | 2 +- crates/benilla-app/assets/ui/MailFrame.xml | 8 +- .../benilla-app/assets/ui/MerchantFrame.xml | 2 +- crates/benilla-app/assets/ui/MicroMenu.xml | 12 +- crates/benilla-app/assets/ui/MultiBars.xml | 8 +- crates/benilla-app/assets/ui/PartyFrame.xml | 8 +- crates/benilla-app/assets/ui/PetActionBar.xml | 22 +- .../assets/ui/PetPaperDollFrame.xml | 36 +- crates/benilla-app/assets/ui/PetStable.xml | 5 +- crates/benilla-app/assets/ui/QuestFrame.xml | 2 +- .../benilla-app/assets/ui/QuestLogFrame.xml | 16 +- .../benilla-app/assets/ui/QuestTimerFrame.xml | 2 +- .../benilla-app/assets/ui/ReputationFrame.xml | 23 +- crates/benilla-app/assets/ui/SkillFrame.xml | 38 +- .../benilla-app/assets/ui/SpellBookFrame.xml | 2 +- crates/benilla-app/assets/ui/StanceBar.xml | 22 +- crates/benilla-app/assets/ui/TaxiFrame.xml | 2 +- .../benilla-app/assets/ui/UIDropDownMenu.xml | 2 +- crates/benilla-app/assets/ui/UnitFrames.xml | 12 +- .../benilla-app/assets/ui/WorldMapFrame.xml | 4 +- crates/benilla-app/assets/ui/ZoneText.xml | 4 +- crates/benilla-app/assets/ui/benilla.toc | 6 +- crates/benilla-app/src/net/motion/remote.rs | 11 +- crates/benilla-app/src/net/motion/tests.rs | 11 +- crates/benilla-app/src/player/arc.rs | 56 +- crates/benilla-app/src/player/controller.rs | 7 + crates/benilla-app/src/player/flags.rs | 91 +++ crates/benilla-app/src/player/mover.rs | 397 ++++++++++- crates/benilla-app/src/player/state.rs | 32 + crates/benilla-app/src/player/swim.rs | 8 + crates/benilla-app/src/portrait/glue_booth.rs | 226 ++++++- crates/benilla-app/src/portrait/mod.rs | 2 + crates/benilla-app/src/ui_quest.rs | 25 +- .../src/ui_script/frame_flag_gate.rs | 632 ++++++++++++++++++ .../src/ui_script/group_loot_tests.rs | 20 +- crates/benilla-app/src/ui_script/mod.rs | 5 + .../src/ui_script/shipped_xml_tests.rs | 89 ++- crates/benilla-app/src/ui_session.rs | 221 +++--- crates/benilla-app/tests/world_api_wall.rs | 13 +- crates/benilla-ui/src/script/mod.rs | 3 + crates/benilla-ui/src/script/model.rs | 11 + .../benilla-ui/src/script/object/toplevel.rs | 2 +- crates/benilla-ui/src/script/pointer.rs | 42 ++ .../benilla-ui/src/script/tests/toplevel.rs | 174 +++++ crates/benilla-world/src/ffx_glow.rs | 322 ++++++++- 59 files changed, 2439 insertions(+), 370 deletions(-) create mode 100644 crates/benilla-app/src/ui_script/frame_flag_gate.rs diff --git a/crates/benilla-app/assets/ui/ActionBar.xml b/crates/benilla-app/assets/ui/ActionBar.xml index 72f59b5f..86e8da3b 100644 --- a/crates/benilla-app/assets/ui/ActionBar.xml +++ b/crates/benilla-app/assets/ui/ActionBar.xml @@ -1715,7 +1715,7 @@ - + @@ -1956,51 +1956,51 @@ - + BenillaActionButton_OnLoad(self, 1) - + BenillaActionButton_OnLoad(self, 2) - + BenillaActionButton_OnLoad(self, 3) - + BenillaActionButton_OnLoad(self, 4) - + BenillaActionButton_OnLoad(self, 5) - + BenillaActionButton_OnLoad(self, 6) - + BenillaActionButton_OnLoad(self, 7) - + BenillaActionButton_OnLoad(self, 8) - + BenillaActionButton_OnLoad(self, 9) - + BenillaActionButton_OnLoad(self, 10) - + BenillaActionButton_OnLoad(self, 11) - + BenillaActionButton_OnLoad(self, 12) diff --git a/crates/benilla-app/assets/ui/BagFrame.xml b/crates/benilla-app/assets/ui/BagFrame.xml index d2977057..4bf6846e 100644 --- a/crates/benilla-app/assets/ui/BagFrame.xml +++ b/crates/benilla-app/assets/ui/BagFrame.xml @@ -1856,7 +1856,7 @@ the bar. (MainMenuBarArtFrame is defined in ActionBar.xml, which the loader loads before this file; the anchor resolves by name.) --> - + diff --git a/crates/benilla-app/assets/ui/BankFrame.xml b/crates/benilla-app/assets/ui/BankFrame.xml index e67a7455..835cbb14 100644 --- a/crates/benilla-app/assets/ui/BankFrame.xml +++ b/crates/benilla-app/assets/ui/BankFrame.xml @@ -296,7 +296,7 @@ - + @@ -1449,23 +1452,23 @@ the loader resolves a key-shaped `text=` through the shipped strings, so the row is localized like the reference's. (Tabs 1/4 carried the enUS literals from 0437; same words either way in enUS, and now the same mechanism.) --> - - - - - @@ -1474,7 +1477,7 @@ exactly fill the parent instead of the ref's setAllPoints="true" — the same effect (see this file's header: frame-level setAllPoints was a no-op when this was written and is wired now; the explicit size is equivalent, so it stays). --> - + @@ -1632,7 +1635,7 @@ filled from Lua exactly like the ref (PaperDollFrame_OnLoad / _SetStats — see the former's header comment); instances declare no regions of their own, same as the ref's. --> - + self:EnableMouse(true) @@ -1640,7 +1643,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -1648,7 +1651,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -1656,7 +1659,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -1664,7 +1667,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -1778,7 +1781,7 @@ - + @@ -1791,7 +1794,7 @@ - + @@ -1804,7 +1807,7 @@ - + @@ -1817,7 +1820,7 @@ - + @@ -1830,7 +1833,7 @@ - + diff --git a/crates/benilla-app/assets/ui/ChatFrame.xml b/crates/benilla-app/assets/ui/ChatFrame.xml index 3064ddc8..ac926578 100644 --- a/crates/benilla-app/assets/ui/ChatFrame.xml +++ b/crates/benilla-app/assets/ui/ChatFrame.xml @@ -1412,7 +1412,7 @@ one script here that is genuinely ChatFrame1's rather than the dock's, so the template carries the gate rather than the registration. --> - - - + @@ -1270,14 +1270,14 @@ - + getglobal(this:GetName().."Text"):SetText("Send Money") SendMailRadioButton_OnClick(1) - + getglobal(this:GetName().."Text"):SetText("C.O.D.") @@ -1414,7 +1414,7 @@ - + diff --git a/crates/benilla-app/assets/ui/MerchantFrame.xml b/crates/benilla-app/assets/ui/MerchantFrame.xml index 41a769cc..d83c8228 100644 --- a/crates/benilla-app/assets/ui/MerchantFrame.xml +++ b/crates/benilla-app/assets/ui/MerchantFrame.xml @@ -776,7 +776,7 @@ - + diff --git a/crates/benilla-app/assets/ui/MicroMenu.xml b/crates/benilla-app/assets/ui/MicroMenu.xml index 115dc280..7a42ab9f 100644 --- a/crates/benilla-app/assets/ui/MicroMenu.xml +++ b/crates/benilla-app/assets/ui/MicroMenu.xml @@ -23,10 +23,14 @@ the action bar behind it, and an unguarded call would abort the rest of that OnShow. Same posture as UiPanels.xml's `CloseMenus and CloseMenus()` and the `if GameTooltip` guards. - Structure: the buttons are TOP-LEVEL frames anchored by name into MainMenuBarArtFrame - (this engine has no cross-file `parent=` attachment — SkillFrame.xml's header comment), then - seated one frame level above the art by BenillaActionBarArt_SeatAbove (ActionBar.xml) so the - bar plate doesn't paint over them. Same shape the bag bar next door already uses. + Structure: the buttons are declared at this file's top level and carry + `parent="MainMenuBarArtFrame"`, which really does attach them to the bar art — the loader + reads a cross-file `parent=`, resolving the name by global lookup at load (decision 1734), + so the art must already exist when this file loads, which the manifest order gives it. They + are anchored into it by name as well, and seated one frame level above it by + BenillaActionBarArt_SeatAbove (ActionBar.xml) so the bar plate doesn't paint over them — + both kept as they are, because that is the row the bar was built and approved against. Same + shape the bag bar next door already uses. SCOPE / real-client divergences (noted, not bugs): - EVERY button now opens something. Help was the last "art only, wired the day the panel diff --git a/crates/benilla-app/assets/ui/MultiBars.xml b/crates/benilla-app/assets/ui/MultiBars.xml index 8ce393a7..1161df20 100644 --- a/crates/benilla-app/assets/ui/MultiBars.xml +++ b/crates/benilla-app/assets/ui/MultiBars.xml @@ -278,7 +278,7 @@ them (its HorizontalMultiBar1/2 templates carry it too, l.36/l.151), and the shipped state a character with a zero toggle byte lands in. MultiActionBar_Update is the only thing that opens one. --> - + @@ -336,7 +336,7 @@ - + @@ -416,7 +416,7 @@ RIGHT_ACTIONBAR_PAGE = 3 (actions 25..36). Geometry from ref-MultiActionBars.xml: a 38x500 frame, button 1 at TOPRIGHT, each next TOP-to-BOTTOM of the previous at -6. --> - + @@ -473,7 +473,7 @@ - + diff --git a/crates/benilla-app/assets/ui/PartyFrame.xml b/crates/benilla-app/assets/ui/PartyFrame.xml index 1c935b11..2857e589 100644 --- a/crates/benilla-app/assets/ui/PartyFrame.xml +++ b/crates/benilla-app/assets/ui/PartyFrame.xml @@ -420,16 +420,16 @@ - + - + - + - + diff --git a/crates/benilla-app/assets/ui/PetActionBar.xml b/crates/benilla-app/assets/ui/PetActionBar.xml index 5da5e3d3..ef099474 100644 --- a/crates/benilla-app/assets/ui/PetActionBar.xml +++ b/crates/benilla-app/assets/ui/PetActionBar.xml @@ -476,7 +476,7 @@ - + - + BenillaPetActionButton_OnLoad(self, 7) - + BenillaPetActionButton_OnLoad(self, 8) - + BenillaPetActionButton_OnLoad(self, 9) - + BenillaPetActionButton_OnLoad(self, 10) diff --git a/crates/benilla-app/assets/ui/PetPaperDollFrame.xml b/crates/benilla-app/assets/ui/PetPaperDollFrame.xml index d793c0a6..196a8e3b 100644 --- a/crates/benilla-app/assets/ui/PetPaperDollFrame.xml +++ b/crates/benilla-app/assets/ui/PetPaperDollFrame.xml @@ -6,8 +6,12 @@ `ref-CharacterFrame.lua` for the tab dispatch). **Its own top-level file, loaded straight after `CharacterFrame.xml`** — the SkillFrame.xml - precedent: this engine reads no XML `parent=` attribute, so a page ships as a sibling pinned - to `CharacterFrame`'s TOPLEFT by name, and `BENILLA_CHARACTERFRAME_SUBFRAMES` (which + precedent. It carries the reference's `parent="CharacterFrame"`, and that attaches for real: + the loader does read a cross-file `parent=`, resolving the name by global lookup at load + (decision 1734), which is why the load order matters — an unresolvable name is not an error, + it warns and falls back to the enclosing element. The page is still sized and pinned to + `CharacterFrame`'s TOPLEFT by name, which gives the identical rect and is what the page was + built and approved against, and `BENILLA_CHARACTERFRAME_SUBFRAMES` (which this page joins as entry 2) is what hides it when the whole window closes. **Almost none of the page's Lua lives here, and that is the point.** The reference's own @@ -327,8 +331,10 @@ ]]> - + @@ -488,7 +494,7 @@ (its tooltip lists what it eats), not a happiness readout; the happiness face that does move lives on the pet unit frame (decision 1005/0990). Shown for hunter pets only. --> - + @@ -568,7 +574,7 @@ - + self:EnableMouse(true) @@ -576,7 +582,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -584,7 +590,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -592,7 +598,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -600,7 +606,7 @@ GameTooltip:Hide() - + self:EnableMouse(true) @@ -689,7 +695,7 @@ - + @@ -702,7 +708,7 @@ - + @@ -715,7 +721,7 @@ - + @@ -728,7 +734,7 @@ - + @@ -741,7 +747,7 @@ - + diff --git a/crates/benilla-app/assets/ui/PetStable.xml b/crates/benilla-app/assets/ui/PetStable.xml index 509d49e6..8629999a 100644 --- a/crates/benilla-app/assets/ui/PetStable.xml +++ b/crates/benilla-app/assets/ui/PetStable.xml @@ -42,8 +42,9 @@ and l.161-162 and it is transcribed verbatim rather than guarded: the window's current pet slot cannot paint without it, and a guard here would hide a missing binding instead of reporting it. - - `parent="UIParent"` (xml l.72) is dropped: this engine reads no XML `parent=` attribute - (`PetPaperDollFrame.xml`'s header). The frame's own `` are kept verbatim even + - `parent="UIParent"` (xml l.72) is ours too, and it attaches for real: the loader does + read a cross-file `parent=`, resolving the name by global lookup at load (decision + 1734), and the frame below declares it. The frame's own `` are kept verbatim even though `ShowUIPanel` re-`SetPoint`s it into the left slot — they name the same TOPLEFT (0,-104) the slot manager writes, so the two agree (ItemTextFrame.xml keeps its reference anchor for the same reason). diff --git a/crates/benilla-app/assets/ui/QuestFrame.xml b/crates/benilla-app/assets/ui/QuestFrame.xml index f553b537..9052680b 100644 --- a/crates/benilla-app/assets/ui/QuestFrame.xml +++ b/crates/benilla-app/assets/ui/QuestFrame.xml @@ -868,7 +868,7 @@ - + @@ -1564,14 +1564,14 @@ - - - - - - + + + + + - + diff --git a/crates/benilla-app/assets/ui/QuestTimerFrame.xml b/crates/benilla-app/assets/ui/QuestTimerFrame.xml index 1d8b9c35..37b7bfe5 100644 --- a/crates/benilla-app/assets/ui/QuestTimerFrame.xml +++ b/crates/benilla-app/assets/ui/QuestTimerFrame.xml @@ -151,7 +151,7 @@ - + diff --git a/crates/benilla-app/assets/ui/ReputationFrame.xml b/crates/benilla-app/assets/ui/ReputationFrame.xml index 04070c1f..79e27a91 100644 --- a/crates/benilla-app/assets/ui/ReputationFrame.xml +++ b/crates/benilla-app/assets/ui/ReputationFrame.xml @@ -13,10 +13,15 @@ addon-visible contract and neither is ours to vary. A CHILD PAGE of `CharacterFrame` (ref l.211: `parent="CharacterFrame"`, `id="3"`), shown and - hidden by `CharacterFrame_ShowSubFrame` — but a SEPARATE top-level file, the SkillFrame.xml / - PetPaperDollFrame.xml shape: this engine reads no XML `parent=` attribute (only physical - `` nesting creates a real parent), so the page is pinned to `CharacterFrame`'s own - TOPLEFT by NAME and loaded right after it so it paints on top (later file = higher z). + hidden by `CharacterFrame_ShowSubFrame` — a SEPARATE top-level file, the SkillFrame.xml / + PetPaperDollFrame.xml shape, and it carries the reference's `parent="CharacterFrame"` for + real: the loader does read a cross-file `parent=`, resolving the name by global lookup at + load (decision 1734). That name must exist by the time this file loads — an unresolvable one + warns and falls back to the enclosing element rather than erroring — which the manifest order + gives it. The page is still pinned to `CharacterFrame`'s own TOPLEFT by NAME and still loaded + right after it so it paints on top (later file = higher z): that arrangement produces the + identical rect and is what the page was built and approved against, not a workaround for + something the engine cannot do. `CharacterFrame.xml`'s `CharacterFrame_OnHide` hide-loop over `BENILLA_CHARACTERFRAME_SUBFRAMES` is what closes it with the window; joining that table as entry 3 is all this page has to do to get that. @@ -584,10 +589,12 @@ `character_tests.rs` pins every page's id against its slot in BENILLA_CHARACTERFRAME_SUBFRAMES. --> - + diff --git a/crates/benilla-app/assets/ui/SkillFrame.xml b/crates/benilla-app/assets/ui/SkillFrame.xml index ea8c72fb..151f9392 100644 --- a/crates/benilla-app/assets/ui/SkillFrame.xml +++ b/crates/benilla-app/assets/ui/SkillFrame.xml @@ -14,12 +14,14 @@ physically nested `` the way PaperDollFrame is: PaperDollFrame is declared INSIDE CharacterFrame.xml's own `` tree (a real engine parent/child), while this page is a SEPARATE file's top-level `` (CharacterFrame.xml is shared-tree with another session - this pass, so only its tab machinery is touched here — not its frame tree). `parent=` is - transcribed for fidelity but is a NO-OP in this engine (grepped `benilla-ui/src/loader`: the - XML `parent` attribute is read nowhere — only physical `` nesting creates a real - parent). Position instead rides `` (a NAMED - lookup, works regardless of tree position, the same mechanism every sibling-anchor in this - codebase already uses) — loaded right after `CharacterFrame.xml` in the load list so it + this pass, so only its tab machinery is touched here — not its frame tree). `parent=` really attaches + (decision 1734; the loader resolves the name globally at load and it wins over the enclosing + element — `shipped_xml_tests::every_declared_parent_really_attaches` asserts it on the loaded + tree). The line above used to say the attribute was read nowhere, which was true once and had + outlived itself. Position still rides `` — a NAMED + lookup that works regardless of tree position, the same mechanism every sibling-anchor in + this codebase uses, kept because it is the geometry this page ships with — loaded right after + `CharacterFrame.xml` in the load list so it paints ON TOP of it (later file = higher z, the established house convention every top-level window already relies on implicitly). Because a true engine Hide-cascade doesn't reach a non-child, `CharacterFrame.xml`'s own `CharacterFrame_OnHide` was extended (its own @@ -687,20 +689,20 @@ - + - - - - - - - - - - - + + + + + + + + + + + diff --git a/crates/benilla-app/assets/ui/StanceBar.xml b/crates/benilla-app/assets/ui/StanceBar.xml index 059ffb52..75933e7b 100644 --- a/crates/benilla-app/assets/ui/StanceBar.xml +++ b/crates/benilla-app/assets/ui/StanceBar.xml @@ -267,7 +267,7 @@ - + @@ -320,43 +320,43 @@ - + BenillaShapeshiftButton_OnLoad(self, 1) - + BenillaShapeshiftButton_OnLoad(self, 2) - + BenillaShapeshiftButton_OnLoad(self, 3) - + BenillaShapeshiftButton_OnLoad(self, 4) - + BenillaShapeshiftButton_OnLoad(self, 5) - + BenillaShapeshiftButton_OnLoad(self, 6) - + BenillaShapeshiftButton_OnLoad(self, 7) - + BenillaShapeshiftButton_OnLoad(self, 8) - + BenillaShapeshiftButton_OnLoad(self, 9) - + BenillaShapeshiftButton_OnLoad(self, 10) diff --git a/crates/benilla-app/assets/ui/TaxiFrame.xml b/crates/benilla-app/assets/ui/TaxiFrame.xml index f7918fb8..afbebfe3 100644 --- a/crates/benilla-app/assets/ui/TaxiFrame.xml +++ b/crates/benilla-app/assets/ui/TaxiFrame.xml @@ -406,7 +406,7 @@ - + diff --git a/crates/benilla-app/assets/ui/UIDropDownMenu.xml b/crates/benilla-app/assets/ui/UIDropDownMenu.xml index 17382700..ea43e3bc 100644 --- a/crates/benilla-app/assets/ui/UIDropDownMenu.xml +++ b/crates/benilla-app/assets/ui/UIDropDownMenu.xml @@ -951,7 +951,7 @@ world map is FULLSCREEN strata — DIALOG would render the list underneath it (the strata escalation later reference versions added to ToggleDropDownMenu, applied statically here since our customer set is known). --> -