From 03c70a7035d7be8d258b86be3d85bcc8e42cc769 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 31 Aug 2026 20:17:25 +0700 Subject: [PATCH] the bag windows are the real 1.12 files, and /walk actually walks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - the bag windows are the reference's own `ContainerFrame.xml` running off the player's patch chain — decision 1751 makes the stock 1.12 UI off the install the end state and `assets/ui` scaffolding that retires file-by-file (86 files against the 99-file stock corpus, 72% of the 1128-function global surface already built) — via one ordered manifest, `benilla.toc`, where a bare name is a file we ship and an `Interface\FrameXML\` path is the player's own file; the windows on screen are `ContainerFrame1..12`, the bank's six copy-pasted popouts fold into them at ids 5..10, net −750 lines, and the swap forced real engine verbs into being rather than stubs (`SetBagPortaitTexture` with its id-0 no-texture arm, `GameTooltip:AppendText`, `SetButtonPulse`, and a `` whose file is the cooldown indicator materializing as the native sweep, which three corpus addons inherit) - the 1.12 walk toggle lands: `TOGGLERUN` latches one bit with `ToggleRun`'s own silent refusal chain (dead, rooted, on a live server spline), and the walk animation was never missing at all — the flag reaches it through exactly one channel, the speed (`0x5fd100` picks Walk over Run on `speed > 2 × walkSpeed`); pinning it caught our remote extrapolator with the two min rungs backwards — `min(walk, run)` runs BEFORE the backward min, so a walking backpedaller moves at 2.5 yd/s where we would have played them the Run clip at 4.5 — and one shared `current_speed` now keeps the local controller and the extrapolator from ever disagreeing about it - the instance and raid lockout messages exist — six packets that were dropped as unknown opcodes now land, four of them as the CHAT_MSG_SYSTEM lines the client composes itself, which is why no Lua handler ever surfaced them — plus `IsInInstance`, `ResetInstances`, and the unit popup's "Reset all instances" row behind the reference's own predicate; where the binary contradicts vmangos: the ownership flag means "any instance bind" but vmangos only ever names raid binds, so the row was dead for every character without a raid lockout — term 1 is now also satisfied by our own eyes, walking out of a party dungeon the server itself bound us to - opening the world map showed 3D world at the sheet's margins: `BlackoutWorld` was parented to the very `UIParent` a fullscreen panel hides, and three more frames had crossed the same boundary — the shared dropdown lists (so the map's continent and zone pickers answered a click with nothing at all), the master-looter menu, and the screenshot confirmation, which could never appear during a cinematic; `frame_flag_gate` now checks the parent seat against the reference both ways a frame acquires one (the attribute, template-inherited included, and `` nesting), and its first harvest took 30 divergences down to three accepted ones Co-Authored-By: Claude Fable 5 --- crates/benilla-app/assets/ui/ActionBar.xml | 18 +- crates/benilla-app/assets/ui/BagFrame.xml | 1409 +---------------- crates/benilla-app/assets/ui/BankFrame.xml | 991 ++++-------- .../assets/ui/ContainerFrameAdapters.xml | 152 +- crates/benilla-app/assets/ui/Cooldown.xml | 37 +- crates/benilla-app/assets/ui/LootFrame.xml | 6 +- crates/benilla-app/assets/ui/QuestFrame.xml | 18 +- crates/benilla-app/assets/ui/RaidFrame.xml | 32 +- .../assets/ui/ScreenshotStatus.xml | 23 +- .../benilla-app/assets/ui/UIDropDownMenu.xml | 13 +- crates/benilla-app/assets/ui/UIParent.xml | 9 + crates/benilla-app/assets/ui/UiPanels.xml | 275 +++- crates/benilla-app/assets/ui/UnitPopup.xml | 23 +- .../benilla-app/assets/ui/WorldMapFrame.xml | 14 +- crates/benilla-app/assets/ui/benilla.toc | 74 +- crates/benilla-app/src/addon_harness/mod.rs | 38 + crates/benilla-app/src/bindings.rs | 58 +- crates/benilla-app/src/bindings/commands.rs | 183 ++- .../src/creature_anim/select/tests.rs | 50 + crates/benilla-app/src/lib.rs | 7 + crates/benilla-app/src/net.rs | 157 ++ crates/benilla-app/src/net/apply.rs | 28 + crates/benilla-app/src/net/io.rs | 1 + crates/benilla-app/src/net/motion/remote.rs | 31 +- crates/benilla-app/src/net/motion/tests.rs | 36 + crates/benilla-app/src/player.rs | 6 +- crates/benilla-app/src/player/controller.rs | 60 +- crates/benilla-app/src/player/flags.rs | 95 ++ crates/benilla-app/src/player/move_trace.rs | 29 + crates/benilla-app/src/player/movement_net.rs | 137 ++ crates/benilla-app/src/player/state.rs | 25 + crates/benilla-app/src/player/walk.rs | 108 ++ crates/benilla-app/src/player/wire_in.rs | 8 + crates/benilla-app/src/ui_instance.rs | 1056 ++++++++++++ .../src/ui_script/action_bar_tests.rs | 184 +-- crates/benilla-app/src/ui_script/addons.rs | 58 +- crates/benilla-app/src/ui_script/bag_tests.rs | 564 +++---- .../benilla-app/src/ui_script/bank_tests.rs | 148 +- .../src/ui_script/bottom_hud_tests.rs | 9 + .../src/ui_script/cinematic_tests.rs | 47 + crates/benilla-app/src/ui_script/content.rs | 6 +- .../src/ui_script/delete_item_tests.rs | 97 +- .../src/ui_script/dressup_tests.rs | 124 +- .../benilla-app/src/ui_script/escape_tests.rs | 150 +- .../src/ui_script/frame_flag_gate.rs | 180 ++- .../src/ui_script/game_menu_tests.rs | 103 +- .../src/ui_script/instance_tests.rs | 226 +++ crates/benilla-app/src/ui_script/manifest.rs | 133 +- .../src/ui_script/merchant_tests.rs | 150 +- crates/benilla-app/src/ui_script/mod.rs | 5 + .../benilla-app/src/ui_script/quest_tests.rs | 6 +- .../benilla-app/src/ui_script/reference_ui.rs | 291 ++-- crates/benilla-app/src/ui_script/test_ui.rs | 180 +++ .../src/ui_script/tooltip_compare_tests.rs | 92 +- .../src/ui_script/world_map_tests.rs | 64 + crates/benilla-formats/src/maps.rs | 39 +- crates/benilla-protocol/src/events.rs | 22 + crates/benilla-protocol/src/events/decode.rs | 16 + .../benilla-protocol/src/messages/instance.rs | 168 ++ crates/benilla-protocol/src/messages/mod.rs | 5 + .../benilla-protocol/src/messages/opcode.rs | 30 + .../benilla-protocol/src/messages/packet.rs | 31 + crates/benilla-protocol/src/messages/parse.rs | 22 +- .../src/world/writer/instance.rs | 30 + .../benilla-protocol/src/world/writer/mod.rs | 2 + crates/benilla-protocol/tests/instance.rs | 172 ++ crates/benilla-ui/src/loader/mod.rs | 32 +- crates/benilla-ui/src/script/container.rs | 67 +- crates/benilla-ui/src/script/instance.rs | 112 ++ crates/benilla-ui/src/script/mod.rs | 2 + crates/benilla-ui/src/script/model.rs | 12 + crates/benilla-ui/src/script/tooltip/mod.rs | 7 +- crates/benilla-ui/src/script/tooltip/verbs.rs | 46 +- 73 files changed, 5561 insertions(+), 3278 deletions(-) create mode 100644 crates/benilla-app/src/player/walk.rs create mode 100644 crates/benilla-app/src/ui_instance.rs create mode 100644 crates/benilla-app/src/ui_script/instance_tests.rs create mode 100644 crates/benilla-app/src/ui_script/test_ui.rs create mode 100644 crates/benilla-protocol/src/messages/instance.rs create mode 100644 crates/benilla-protocol/src/world/writer/instance.rs create mode 100644 crates/benilla-protocol/tests/instance.rs create mode 100644 crates/benilla-ui/src/script/instance.rs diff --git a/crates/benilla-app/assets/ui/ActionBar.xml b/crates/benilla-app/assets/ui/ActionBar.xml index 86e8da3b..d6c434e2 100644 --- a/crates/benilla-app/assets/ui/ActionBar.xml +++ b/crates/benilla-app/assets/ui/ActionBar.xml @@ -290,9 +290,9 @@ if show then button:Show() else button:Hide() end end -- Losing the last key with the keyring open would strand an orphan window; the ref - -- can't reach this state (its latch is one-way), so this is ours to decide. - local frame = getglobal("BenillaKeyRingFrame") - if frame and not show and frame:IsShown() then frame:Hide() end + -- can't reach this state (its latch is one-way), so this is ours to decide. The window + -- is an ordinary ContainerFrame since 1751, so this is the reference's own CloseBag. + if not show then CloseBag(KEYRING_CONTAINER) end end -- ── The bonus-bar slide (decision 1524; ref BonusActionBarFrame.lua:1-98) ────────────── @@ -1262,12 +1262,11 @@ -- `< MAX_PLAYER_LEVEL`, unwatched on `== MAX_PLAYER_LEVEL`, which is the reference's own -- asymmetry and only differs above the cap, where nothing can go. -- - -- ONE GUARD ADDED, at the tail: `updateContainerFrameAnchors` is defined by - -- ContainerFrameAdapters.xml (manifest 206, below this file), and a harness that shows this - -- bar without it would take a nil call on a line that only ever runs on a visibility flip. - -- The `if then` shape is this codebase's own subset-load idiom (CharacterFrame.xml's - -- `if UpdateMicroButtons then`). `UIParent_ManageFramePositions` needs no such guard: - -- UIParent.xml is manifest 42, above every consumer. + -- The tail used to call `updateContainerFrameAnchors()` itself, guarded, because that + -- global was a benilla no-op standing in for a body that had no windows to anchor. + -- Decision 1751 gave it the reference's real body and put the call where the reference + -- puts it — the end of `UIParent_ManageFramePositions` (UIParent.lua:1774) — so this + -- caller gets it for free, along with every other one. function ReputationWatchBar_Update(newLevel) newLevel = newLevel or UnitLevel("player") local name, reaction, rankMin, rankMax, standing = GetWatchedFactionInfo() @@ -1308,7 +1307,6 @@ end if wasShown ~= ReputationWatchBar:IsShown() then UIParent_ManageFramePositions() - if updateContainerFrameAnchors then updateContainerFrameAnchors() end end end diff --git a/crates/benilla-app/assets/ui/BagFrame.xml b/crates/benilla-app/assets/ui/BagFrame.xml index f7cc7950..cc863396 100644 --- a/crates/benilla-app/assets/ui/BagFrame.xml +++ b/crates/benilla-app/assets/ui/BagFrame.xml @@ -1,57 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - + + + + SAME resolution the slot kit above uses for every other container. --> + + + - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - - - - - - - - - - - - - - - - - - - - - - - - - - - BenillaBagFrame_OnLoad(self) - BenillaBagFrame_OnEvent(self) - BenillaBagFrame_OnShow() - BenillaBagFrame_OnHide() - - diff --git a/crates/benilla-app/assets/ui/ContainerFrameAdapters.xml b/crates/benilla-app/assets/ui/ContainerFrameAdapters.xml index ccaa7997..00e0e1f1 100644 --- a/crates/benilla-app/assets/ui/ContainerFrameAdapters.xml +++ b/crates/benilla-app/assets/ui/ContainerFrameAdapters.xml @@ -1,16 +1,26 @@ - - - diff --git a/crates/benilla-app/assets/ui/Cooldown.xml b/crates/benilla-app/assets/ui/Cooldown.xml index b78bad5a..d106f15b 100644 --- a/crates/benilla-app/assets/ui/Cooldown.xml +++ b/crates/benilla-app/assets/ui/Cooldown.xml @@ -19,18 +19,22 @@ -- -- THE ONE FORK, and why it is two faithful branches rather than a guard. The reference's -- body arms a Model (`this.start = start … this:SetSequence(0)`); ours arms our native - -- widget, which is where 0263 put that machine. Both kinds really do reach this - -- function: our own windows pass a , and an addon inheriting the template below - -- passes a , because an XML instance is created from ITS OWN tag and every real - -- caller writes the reference's ``. + -- widget, which is where 0263 put that machine. -- - -- Calling SetCooldown unconditionally is what shipped, and it raised on exactly that case: - -- a Bagnon slot holding an item with a live cooldown died on - -- `attempt to call method 'SetCooldown' (a nil value)` — and, because !OmniCC wraps this - -- very function, it took OmniCC's countdown down with it. A Model has no sweep for this - -- engine to arm (`SetSequence`/`AdvanceTime` are not bindings here), so that branch shows - -- and hides the frame and nothing more: the addon's own cooldown child stays inert, which - -- is a missing visual, not a broken window. + -- **Since decision 1751 the fork is almost never taken, and that is the fix.** The loader + -- now materializes a `` whose file IS the cooldown indicator as a real `` + -- (`loader::frame_kind_of`) — the file is the thing's identity, and this engine draws that + -- sweep natively. So ``, which is what every + -- real caller writes (the reference's own ContainerFrameItemButtonTemplate, its action + -- buttons, three corpus addons), arrives here as a Cooldown and sweeps. + -- + -- The `if this.SetCooldown` guard stays for the case that remains: a Model built with + -- some OTHER file, or a plain frame handed in by an addon. Calling SetCooldown + -- unconditionally is what shipped, and it raised on exactly that: a Bagnon slot holding an + -- item with a live cooldown died on `attempt to call method 'SetCooldown' (a nil value)` + -- — and, because !OmniCC wraps this very function, it took OmniCC's countdown down with + -- it. That branch shows and hides the frame and nothing more, which is a missing visual, + -- not a broken window. function CooldownFrame_SetTimer(this, start, duration, enable) if ( start > 0 and duration > 0 and enable > 0 ) then if ( this.SetCooldown ) then @@ -44,11 +48,12 @@ ]]> - + diff --git a/crates/benilla-app/assets/ui/QuestFrame.xml b/crates/benilla-app/assets/ui/QuestFrame.xml index 41b3cd91..cab3d730 100644 --- a/crates/benilla-app/assets/ui/QuestFrame.xml +++ b/crates/benilla-app/assets/ui/QuestFrame.xml @@ -475,7 +475,7 @@ -- Arm the write-on (ref l.538-551): objectives/rewards invisible and Accept dead -- until the description has finished writing itself onto the parchment. - getglobal("QuestDetailTextAlphaFrame"):SetAlpha(0) + getglobal("TextAlphaDependentFrame"):SetAlpha(0) getglobal("QuestFrameAcceptButton"):Disable() local panel = getglobal("QuestFrameDetailPanel") panel.fading = 1 @@ -503,10 +503,10 @@ if not getglobal("QuestDescription"):SetAlphaGradient(panel.fadingProgress, QUEST_DESCRIPTION_GRADIENT_LENGTH) then panel.fading = nil if QUEST_FADING_DISABLE == "0" then - UIFrameFadeIn(getglobal("QuestDetailTextAlphaFrame"), QUESTINFO_FADE_IN) + UIFrameFadeIn(getglobal("TextAlphaDependentFrame"), QUESTINFO_FADE_IN) else -- instant: the block snaps on, no fade (ref l.561-564) - getglobal("QuestDetailTextAlphaFrame"):SetAlpha(1) + getglobal("TextAlphaDependentFrame"):SetAlpha(1) end getglobal("QuestFrameAcceptButton"):Enable() end @@ -1093,8 +1093,16 @@ QuestFrame.xml l.553): 1.12 SetAlpha overwrite-cascades into the child item buttons/coins (wow-re propagation.md, CORRECTED), so the whole block hides while the text writes - and fades in as one. --> - + and fades in as one. + + **The reference's own bare name.** This was spelled + `QuestDetailTextAlphaFrame` until decision 1757, with the + citation above already naming what it should have been — + the slip 1189 describes and `BlackoutWorld` paid for: a + published global spelled to our taste is a global the + reference has and we do not, and the reference's own + QuestFrame.lua indexes this one by hand (l.543/562/564). --> + diff --git a/crates/benilla-app/assets/ui/RaidFrame.xml b/crates/benilla-app/assets/ui/RaidFrame.xml index 968b7e9b..f7553390 100644 --- a/crates/benilla-app/assets/ui/RaidFrame.xml +++ b/crates/benilla-app/assets/ui/RaidFrame.xml @@ -42,7 +42,10 @@ `PromoteToAssistant`, `DemoteAssistant`, `DoReadyCheck`, `ConfirmReadyCheck`, `RequestRaidInfo`, `GetNumSavedInstances`, `GetSavedInstanceInfo`, `SetRaidRosterSelection`/`GetRaidRosterSelection` — all in `benilla-ui/src/script/party.rs` - beside `GetRaidRosterInfo`, which already existed. The events are `RAID_ROSTER_UPDATE`, + beside `GetRaidRosterInfo`, which already existed. Decision 1748 added the lockout family's + own three (`IsInInstance`, `CanShowResetInstances`, `ResetInstances`) in + `benilla-ui/src/script/instance.rs`; the CONFIRM_RESET_INSTANCES dialog at the foot of this + file is their one caller, raised by UnitPopup's SELF menu. The events are `RAID_ROSTER_UPDATE`, `READY_CHECK` and `UPDATE_INSTANCE_INFO`, fired by `ui_party::feed`; the `raid1`..`raid40` unit tokens the rows target and hover are fed there too. --> @@ -69,6 +72,10 @@ GROUP = GROUP or "Group" -- l.2029 EMPTY = EMPTY or "Empty" -- l.1433 UNKNOWN = UNKNOWN or "Unknown" -- l.4443 + CONFIRM_RESET_INSTANCES = CONFIRM_RESET_INSTANCES + or "Do you really want to reset all of your instances?" -- l.851 + YES = YES or "Yes" -- l.5463 + NO = NO or "No" -- l.2794 -- ── The counts (ref RaidFrame.lua l.2-5) ──────────────────────────────────────────────── -- Published globals, not local constants: `MAX_RAID_MEMBERS` alone is named by a large @@ -615,6 +622,29 @@ StaticPopup_Hide("ADD_RAIDMEMBER") end, } + + -- ── "Reset all instances" (ref StaticPopup.lua l.23-33; decision 1748) ────────────────── + -- Raised by UnitPopup's SELF menu, and registered HERE because this file is the instance + -- house — the same rule that keeps the pet dialogs in PetActionBar.xml. `ResetInstances()` + -- is the only call in the client that sends `CMSG_RESET_INSTANCES`; everything else in the + -- lockout family is the server talking. + -- + -- The answer is per instance rather than one verdict, and it arrives as CHAT_MSG_SYSTEM + -- lines the engine composes: an `SMSG_INSTANCE_RESET` per dungeon that reset, and — on + -- the group path only — an `SMSG_INSTANCE_RESET_FAILED` per dungeon that would not. + -- Nothing back at all is the ordinary answer for a character with nothing resettable. So + -- there is nothing to show here and no result to wait for. + StaticPopupDialogs["CONFIRM_RESET_INSTANCES"] = { + text = CONFIRM_RESET_INSTANCES, + button1 = YES, + button2 = NO, + timeout = 0, + whileDead = 1, + hideOnEscape = 1, + OnAccept = function() + ResetInstances() + end, + } ]]> - + diff --git a/crates/benilla-app/assets/ui/UIDropDownMenu.xml b/crates/benilla-app/assets/ui/UIDropDownMenu.xml index ea43e3bc..39e6a468 100644 --- a/crates/benilla-app/assets/ui/UIDropDownMenu.xml +++ b/crates/benilla-app/assets/ui/UIDropDownMenu.xml @@ -1119,8 +1119,15 @@ it is ONE library file replicated, and only that one of its two sites is unguarded (the other is `info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10`). Writing a literal here would have been a silent fidelity divergence, not a fix. --> - - -