Files
benilla-octo/crates/benilla-app/assets/ui/BasicControls.xml
T
SamandClaude Fable 5 e665b0bfc4 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

164 lines
9.6 KiB
XML

<Ui>
<!--
Interface\FrameXML\BasicControls.xml, re-expressed — the reference's second file, right
after Fonts.xml, and one of the smallest in FrameXML. It carries four things an addon can
reach and we had none of:
TEXT(text) the identity function 1.12 wraps every displayed string in. **26 corpus
addons call it**, because half the shipped FrameXML does and they copied
the idiom. Missing, it is `attempt to call global 'TEXT'`.
message(text) the client's "show the player this" dialog. Its own popup, not a chat
line. Present in 64 corpus files — but read the line before ranking it
(1207): 55 of those are copies of `Dewdrop-2.0.lua`, and the genuine
callers are about ten addons.
_ERRORMESSAGE what `message` is implemented in terms of, and the reference's default
error handler. Two corpus addons replace it outright (ImprovedErrorFrame
is one), which they cannot do to a name that does not exist.
ScriptErrors the dialog both of the above put text into, plus DialogBoxFrame and the
DialogButton*Texture trio it is built from — three of which the corpus
also inherits from directly (`inherits_demand`, 2 addons each).
The three fonts this needs — GameFontRedLarge, DialogButtonNormalText,
DialogButtonHighlightText — are already in Fonts.xml, so this file is self-contained
against the one that loads before it, exactly as it is in the reference's own toc order.
-->
<Script><![CDATA[
-- ── _ERRORMESSAGE / message (ref BasicControls.xml l.5-15) ─────────────────────────────
--
-- COMPLETE, including `debuginfo()`. That line was guarded here when this file landed,
-- because `debuginfo` was an engine global we lacked and whose behaviour was uncarved —
-- and declaring a no-op under a real 1.12 name is exactly the "capability absent without a
-- failure" class 1203 named. wow-re has since carved it (2026-08-11): `0x7027f0` is
-- `33 c0 c3` — `xor eax,eax; ret`, three bytes, no call, no memory write. It genuinely
-- does nothing and returns nothing, and five of its `debug*` siblings are byte-identical.
-- So the no-op in `stdlib.rs` is the REFERENCE's no-op, the guard was measuring our own
-- ignorance rather than a real branch, and it is gone.
function _ERRORMESSAGE(msg)
debuginfo()
if not ScriptErrors:IsVisible() then
ScriptErrors_Message:SetText(msg)
ScriptErrors:Show()
end
return msg
end
function message(text)
_ERRORMESSAGE(text)
end
-- ── seterrorhandler(_ERRORMESSAGE): the reference's closing line, now transcribed ──────
-- This file withheld exactly this line from when it landed until decision 1305, because
-- the engine's error channel (`UiScript::errors()`) was the only place a Lua fault was
-- visible to any instrument and a modal would have blinded it. That trade is dissolved,
-- not decided differently: the engine now records every caught script error on the host
-- channel FIRST and then dispatches it to whatever `geterrorhandler()` answers
-- (`dispatch_script_errors_to_handler`, 1305) — so the harness's blocker tables read
-- exactly what they always read, and the player gets what the reference always gave them:
-- an addon that errors puts the red ScriptErrors dialog on screen instead of failing
-- somewhere only a terminal can see (B271's report was debugged entirely off WARN lines).
-- An addon that installs its OWN handler still wins outright, exactly as in 1195.
seterrorhandler(_ERRORMESSAGE)
-- ── TEXT (ref l.22-26, verbatim) ──────────────────────────────────────────────────────
-- "This function is used to translate text (actually it's already translated as-is)" is
-- the reference's own comment. It really is the identity function: 1.12 shipped one
-- localisation per client and the hook was never used.
function TEXT(text)
return text
end
-- ── UIParentLoadAddOn (ref UIParent.lua l.638-647) ────────────────────────────────────
-- The on-demand loader every "open the auction house / tradeskill / talent panel" path
-- goes through, and the one 5 corpus addons name — FuBar_MCPFu, Fubar_RareTrackerFu, MCP,
-- MikScrollingBattleText, SpecialTalent: five separate addons, not one library replicated
-- (1207/1240).
--
-- Every piece was already here and only the join was missing: `LoadAddOn` answers the
-- reference's own `(1, nil)` / `(nil, reason)` pair, `message` and `TEXT` are directly
-- above, and the `ADDON_*` reason words come from the real `GlobalStrings.lua` we RUN off
-- the patch chain rather than copy (1234).
--
-- **`FailedAddOnLoad` is the reference's own latch, and it is not decoration.** Without it
-- an addon that retries the load from a handler raises a modal on every attempt; with it
-- the failure shows once per addon name per session. It is exactly the detail this would
-- have lacked had it been reconstructed from the name instead of read.
--
-- Every reason our `LoadAddOn` can answer resolves to a string: MISSING, DISABLED,
-- NOT_DEMAND_LOADED, DEP_MISSING and DEP_DISABLED all have an `ADDON_..reason` word
-- (GlobalStrings l.16-31), the same reason set wow-re's `ui.md` l.2396 carves off
-- `0x51e780`. So the `getglobal` below cannot hand `format` a nil.
FailedAddOnLoad = {};
function UIParentLoadAddOn(name)
local loaded, reason = LoadAddOn(name)
if not loaded then
if not FailedAddOnLoad[name] then
message(format(TEXT(ADDON_LOAD_FAILED), name, TEXT(getglobal("ADDON_" .. reason))))
FailedAddOnLoad[name] = true
end
end
return loaded
end
]]></Script>
<!-- The dialog button faces (ref l.28-37). Same three-piece art as UIPanelButtonTemplate's,
with their own names because the reference's dialogs inherit these directly. -->
<Texture name="DialogButtonNormalTexture" file="Interface\Buttons\UI-Panel-Button-Up" virtual="true">
<TexCoords left="0" right="0.625" top="0" bottom="0.6875"/>
</Texture>
<Texture name="DialogButtonPushedTexture" file="Interface\Buttons\UI-Panel-Button-Down" virtual="true">
<TexCoords left="0" right="0.625" top="0" bottom="0.6875"/>
</Texture>
<Texture name="DialogButtonHighlightTexture" file="Interface\Buttons\UI-Panel-Button-Highlight" alphaMode="ADD" virtual="true">
<TexCoords left="0" right="0.625" top="0" bottom="0.6875"/>
</Texture>
<!-- DialogBoxFrame (ref l.38-77): a centered tooltip-bordered box with one OKAY button that
hides its parent. Virtual — ScriptErrors below is the only thing in shipped FrameXML that
inherits it, but two corpus addons inherit it too. -->
<Frame name="DialogBoxFrame" virtual="true" toplevel="true" frameStrata="DIALOG" hidden="true">
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<EdgeSize><AbsValue val="32"/></EdgeSize>
<TileSize><AbsValue val="32"/></TileSize>
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
</Backdrop>
<Frames>
<Button name="$parentButton">
<Size><AbsDimension x="128" y="32"/></Size>
<Anchors>
<Anchor point="BOTTOM"><Offset><AbsDimension x="0" y="16"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnClick>
this:GetParent():Hide()
</OnClick>
</Scripts>
<NormalTexture inherits="DialogButtonNormalTexture"/>
<PushedTexture inherits="DialogButtonPushedTexture"/>
<HighlightTexture inherits="DialogButtonHighlightTexture"/>
<ButtonText text="OKAY"/>
<NormalFont inherits="DialogButtonNormalText"/>
<HighlightFont inherits="DialogButtonHighlightText"/>
</Button>
</Frames>
</Frame>
<!-- "This is the general scripting error dialog" (ref l.79-100), verbatim. -->
<Frame name="ScriptErrors" inherits="DialogBoxFrame">
<Size><AbsDimension x="384" y="128"/></Size>
<Layers>
<Layer level="ARTWORK">
<FontString name="ScriptErrors_Message" inherits="GameFontRedLarge" justifyH="CENTER" justifyV="TOP" nonspacewrap="true">
<Size><AbsDimension x="360" y="0"/></Size>
<Anchors>
<Anchor point="TOP"><Offset><AbsDimension x="0" y="-16"/></Offset></Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
</Frame>
</Ui>