ui: GetDebugName, the name an unnamed frame still answers

`Cinematic/Frames.lua:3734` is `entry.name or entry.frame:GetDebugName()` — an addon that keeps a
list of frames reaches for this precisely because some of them have no name, which is the one case
`GetName` cannot serve. With the method absent, `/cine debug frame <name>` raised on the first
unnamed row in the list instead of printing the row the player asked for.

On all three method tables, since the era puts it on ScriptObject. A named frame answers its name,
so a feature test on it learns nothing a 1.12 client would answer differently. The unnamed leg
deviates in its fallback only: it walks the parent's own fields for the key the child is stored
under (frames here are plain tables, so `parent.icon = tex` is visible) and answers
`Parent.<unnamed>` when there is none, where the era answers an index among the parent's children —
an index here would be the order of a list this client does not keep, and a wrong number reads
worse than an honest absence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
2026-11-02 14:17:44 -07:00
co-authored by Claude Opus 5
parent 09aca72c46
commit bb2e40d1dd
2 changed files with 48 additions and 0 deletions
@@ -110,6 +110,38 @@ end
end
"#;
/// Goes on all three tables: `GetDebugName()` is the era's "what is this frame called" for logs
/// and error messages, and it answers for an **unnamed** frame too, which `GetName` cannot. An
/// addon that keeps a list of frames and reports on them reaches for it precisely because some of
/// them have no name — `Cinematic/Frames.lua:3734` is `entry.name or entry.frame:GetDebugName()`,
/// and with the method absent its `/cine debug frame <name>` raised on the first unnamed frame in
/// the list instead of printing the row the player asked for.
///
/// Deviation, and it is in the unnamed leg only: the era walks the parent's own fields to find
/// the key the child is stored under and builds `Parent.key`; failing that it reports an index
/// among the parent's children. This walks the same fields — frames here are plain tables, so a
/// `parent.icon = tex` is visible — and falls back to `Parent.<unnamed>` rather than an index,
/// because an index here would be the creation order of a list this client does not keep and a
/// *wrong* number reads worse than an honest "no key". A frame with no parent answers
/// `<unnamed>`.
const DEBUG_NAME_DELEGATES: &str = r#"
return function(m)
function m.GetDebugName(self)
local name = self:GetName()
if name then return name end
local parent = self.GetParent and self:GetParent()
if not parent then return "<unnamed>" end
local base = parent.GetDebugName and parent:GetDebugName() or parent:GetName() or "<unnamed>"
for key, value in pairs(parent) do
if value == self and type(key) == "string" then
return base .. "." .. key
end
end
return base .. ".<unnamed>"
end
end
"#;
/// Texture-only: `SetColorTexture(r, g, b[, a])` is the modern name for `SetTexture`'s colour arm,
/// which 1.12 already has (`0x770360` makes the 8x8 solid surface, and our `region/paint.rs` arm
/// defaults the alpha to 1 exactly as it does). Retail split the two spellings when `SetTexture`
@@ -261,6 +293,7 @@ pub(super) fn install(lua: &Lua) -> mlua::Result<()> {
delegate(lua, key, GEOMETRY_DELEGATES)?;
delegate(lua, key, SHOWN_DELEGATES)?;
delegate(lua, key, MOUSE_OVER_DELEGATES)?;
delegate(lua, key, DEBUG_NAME_DELEGATES)?;
}
delegate(lua, REG_TEXTURE_METHODS, TEXTURE_DELEGATES)?;
delegate(lua, REG_FONTSTRING_METHODS, FONTSTRING_DELEGATES)?;
@@ -603,6 +603,21 @@ const ALLOWED_BEYOND: &[(&str, &str, &str)] = &[
addon writes this one — Cinematic/Options.lua:701 paints its list border with it and \
died at session start without it, and OpenMapClassic its map chrome",
),
(
"GetDebugName",
"Button CheckButton ColorSelect DressUpModel EditBox FontString Frame GameTooltip \
LootButton MessageFrame Minimap Model MovieFrame ScrollFrame ScrollingMessageFrame \
SimpleHTML Slider StatusBar TabardModel Texture WorldFrame PlayerModel",
"ClassicAPI: the era's \"what is this frame called\" for a log line or an error message, \
and the one that answers for an UNNAMED frame, which GetName cannot. An addon keeping a \
list of frames reaches for it precisely because some of them have no name — \
Cinematic/Frames.lua:3734 is `entry.name or entry.frame:GetDebugName()`, so /cine debug \
frame <name> raised on the first unnamed row instead of printing the one asked for. \
Named frames answer their name, so a feature test on it learns nothing a 1.12 client \
would answer differently; the unnamed leg deviates in its fallback only (Parent.key by \
walking the parent's fields, else Parent.<unnamed>, never the era's child index — a \
wrong number reads worse than an honest absence)",
),
(
"SetEnabled",
"Button CheckButton EditBox LootButton",