compat: math.huge and SetColorTexture, the two load blockers of the ported pair
Measured through `addon_harness` before anything was written, which is the only reason this
is two small changes rather than a guess at a list. Both `Addon_Ports` addons failed to load
at all; these are their first two stops.
**`math.huge` was nil, deliberately.** `stdlib_backport.rs` restores the 5.1 stdlib members
ClassicAPI backports, scoped to what the corpus calls, and `math.huge` was on the stated
"nothing calls them" list. `Cinematic/Core.lua:1103` is `local lastMovingOff = -math.huge`
at **file scope**, so the nil stopped the addon's main file dead ("attempt to perform
arithmetic on field `?`") and nothing after it ran — one site, but a load-time one, which is
the bar that table sets. The real `ClassicAPI.dll` carries `huge` in its own stdlib name
table beside `fmod`, `modf`, `gmatch`, `match`, `select`, `maxn`, `cosh` and `reverse`, so
this is what the client we already claim to be actually has.
Two tests pinned it absent and are updated rather than deleted: `lua50.rs`'s keeps asserting
this *layer* removes it (the registry stash is the proof), and `stdlib_backport.rs`'s keeps
the narrowness assertion for the four that stay gone. The new assertion is `-math.huge`,
because file-scope arithmetic is the shape that failed.
**`Texture:SetColorTexture`** is the modern spelling of `SetTexture`'s colour arm, which
1.12 already has (`0x770360`'s 8×8 solid surface, and `region/paint.rs` defaults the alpha
to 1 as it does). Retail split the names when `SetTexture` stopped taking a colour, so every
Era-era addon writes the new one. `Cinematic/Options.lua:701` paints its list border with it
and died at session start; OpenMapClassic its map chrome. Four lines of the same composition
chunk `SetShown` and the geometry pair use, and an `ALLOWED_BEYOND` row with both call sites
— `docs/ADDON_COMPAT.md` had it on the same "plausible and untraced" line as
`RegisterUnitEvent`, and this is that line's follow-through.
Movement, same harness both ways:
- Cinematic load: `Core.lua:1103` → `Frames.lua:2611` (~10 files further; wants
`RegisterUnitEvent` next). Session: `Options.lua:701` → `Options.lua:4130` (3400 lines on,
wants `SetWordWrap`).
- OpenMapClassic: unchanged at `DialogBorderOpaqueTemplate`, which neither fix touches.
benilla-ui 2076 passed, 0 failed. Full chain green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -78,6 +78,20 @@ 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`
|
||||
/// stopped taking a colour; every Era-era addon writes the new one, and both of the addons being
|
||||
/// ported here are blocked on it — `Cinematic/Options.lua:701` paints its list border with it, and
|
||||
/// OpenMapClassic its map chrome.
|
||||
const TEXTURE_DELEGATES: &str = r#"
|
||||
return function(m)
|
||||
function m.SetColorTexture(self, r, g, b, a)
|
||||
self:SetTexture(r, g, b, a)
|
||||
end
|
||||
end
|
||||
"#;
|
||||
|
||||
/// FontString-only: `SetFormattedText` is `SetText(format(...))`. 1.12's `string.format` is the
|
||||
/// `format` global here, as `lua50.rs` leaves it.
|
||||
const FONTSTRING_DELEGATES: &str = r#"
|
||||
@@ -157,6 +171,7 @@ pub(super) fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
delegate(lua, key, GEOMETRY_DELEGATES)?;
|
||||
delegate(lua, key, SHOWN_DELEGATES)?;
|
||||
}
|
||||
delegate(lua, REG_TEXTURE_METHODS, TEXTURE_DELEGATES)?;
|
||||
delegate(lua, REG_FONTSTRING_METHODS, FONTSTRING_DELEGATES)?;
|
||||
|
||||
// `GetStringHeight()`: the laid-out height of the current text — wrapped to the declared
|
||||
|
||||
@@ -28,13 +28,18 @@
|
||||
//! | `math.fmod` | 2 |
|
||||
//! | `math.modf` | 1 |
|
||||
//! | `string.reverse` | 1 |
|
||||
//! | `math.huge` | 1 |
|
||||
//!
|
||||
//! `string.reverse` joined the list when SoftSpoken was installed — it is a ClassicAPI-dependent
|
||||
//! addon, so it writes 5.1 and its one `string.reverse` site is a load-time call.
|
||||
//! addon, so it writes 5.1 and its one `string.reverse` site is a load-time call. `math.huge`
|
||||
//! joined it when the two Addon_Ports addons were measured: `Cinematic/Core.lua:1103` is
|
||||
//! `local lastMovingOff = -math.huge` at **file scope**, so the nil stopped the addon's main file
|
||||
//! dead ("attempt to perform arithmetic on field `?`") and nothing after it ran. One site is the
|
||||
//! bar this table sets, and a load-time one at that.
|
||||
//!
|
||||
//! Deliberately **not** restored, because nothing calls them: `strrev`,
|
||||
//! `table.maxn`, `math.huge`, the hyperbolics, and `coroutine`. Each stays nil, so the surface
|
||||
//! grows by five names rather than by a whole library — and `table.maxn` in particular would
|
||||
//! `table.maxn`, the hyperbolics, and `coroutine`. Each stays nil, so the surface
|
||||
//! grows by six names rather than by a whole library — and `table.maxn` in particular would
|
||||
//! fight `lua50.rs`'s `n`-based table library, which is 5.0 semantics this client genuinely needs.
|
||||
//!
|
||||
//! ## What this costs, stated plainly
|
||||
@@ -60,6 +65,12 @@ const RESTORED: &[(&str, &str)] = &[
|
||||
("math", "fmod"),
|
||||
("math", "modf"),
|
||||
("string", "reverse"),
|
||||
// Not a function: the stash is over `Value`, so a number restores the same way. The real
|
||||
// `ClassicAPI.dll` carries `huge` in its own stdlib name table beside `fmod`, `modf`,
|
||||
// `gmatch`, `match`, `select`, `maxn`, `cosh` and `reverse` (its string pool, the evidence
|
||||
// class `benilla-dll-contract-from-strings` names), so this is what the client it claims to
|
||||
// be actually has.
|
||||
("math", "huge"),
|
||||
];
|
||||
|
||||
pub(super) fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
@@ -138,25 +149,24 @@ mod tests {
|
||||
"abc"
|
||||
);
|
||||
assert_eq!(s.eval::<f64>("return math.fmod(7, 3)").unwrap(), 1.0);
|
||||
// `math.huge` is a number, not a function: the one site that needed it is file-scope
|
||||
// arithmetic (`Cinematic/Core.lua:1103`, `-math.huge`), so negating it is the test.
|
||||
assert!(s
|
||||
.eval::<bool>("return -math.huge < -1e308 and math.huge > 1e308")
|
||||
.unwrap());
|
||||
assert_eq!(
|
||||
s.eval::<(f64, f64)>("return math.modf(3.25)").unwrap(),
|
||||
(3.0, 0.25)
|
||||
);
|
||||
}
|
||||
|
||||
/// The narrowness is the point: five names, not a whole library. `table.maxn` especially must
|
||||
/// The narrowness is the point: six names, not a whole library. `table.maxn` especially must
|
||||
/// stay gone — it fights `lua50.rs`'s `n`-based table library, which is 5.0 semantics this
|
||||
/// client relies on.
|
||||
#[test]
|
||||
fn nothing_beyond_the_measured_members_comes_back() {
|
||||
let s = UiScript::new().unwrap();
|
||||
for expr in [
|
||||
"strrev",
|
||||
"table.maxn",
|
||||
"math.huge",
|
||||
"math.cosh",
|
||||
"coroutine",
|
||||
] {
|
||||
for expr in ["strrev", "table.maxn", "math.cosh", "coroutine"] {
|
||||
assert_eq!(
|
||||
s.eval::<String>(&format!("return type({expr})")).unwrap(),
|
||||
"nil",
|
||||
|
||||
@@ -513,17 +513,17 @@ mod tests {
|
||||
}
|
||||
|
||||
/// The 5.1-only members this *dialect* removes stay removed in the finished VM — except the
|
||||
/// five `compat/classic_api/stdlib_backport.rs` deliberately hands back, which is a documented
|
||||
/// six `compat/classic_api/stdlib_backport.rs` deliberately hands back, which is a documented
|
||||
/// maintainer decision, not drift.
|
||||
///
|
||||
/// Split in two on purpose. For the restored five, asserting "nil" would be asserting the
|
||||
/// Split in two on purpose. For the restored six, asserting "nil" would be asserting the
|
||||
/// opposite of the decision; instead this checks they are in the registry stash, which is
|
||||
/// proof *this layer* removed them and only compat put them back. For everything else the
|
||||
/// original assertion stands unchanged, so a genuine regression still fails here.
|
||||
#[test]
|
||||
fn the_5_1_only_members_are_not_offered() {
|
||||
let s = UiScript::new().unwrap();
|
||||
for expr in ["table.maxn", "math.huge", "math.cosh", "coroutine"] {
|
||||
for expr in ["table.maxn", "math.cosh", "coroutine"] {
|
||||
assert!(
|
||||
s.eval::<bool>(&format!("return {expr} == nil")).unwrap(),
|
||||
"{expr} is a Lua 5.1 addition — 1.12 does not have it, and nothing restores it"
|
||||
|
||||
@@ -290,6 +290,15 @@ const ALLOWED_BEYOND: &[(&str, &str, &str)] = &[
|
||||
"ClassicAPI: the laid-out wrapped height, the other half of GetStringWidth's measure — \
|
||||
AceGUI-3.0's Label and CheckBox call it unguarded",
|
||||
),
|
||||
(
|
||||
"SetColorTexture",
|
||||
"Texture",
|
||||
"ClassicAPI: the modern spelling of SetTexture's colour arm, which 1.12 already has \
|
||||
(0x770360's 8x8 solid surface; region/paint.rs defaults the alpha to 1 as it does). \
|
||||
Retail split the two names when SetTexture stopped taking a colour, so every Era-era \
|
||||
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",
|
||||
),
|
||||
(
|
||||
"SetShown",
|
||||
"Button CheckButton ColorSelect DressUpModel EditBox FontString Frame GameTooltip LootButton MessageFrame Minimap Model MovieFrame PlayerModel ScrollFrame ScrollingMessageFrame SimpleHTML Slider StatusBar TabardModel Texture WorldFrame",
|
||||
|
||||
Reference in New Issue
Block a user