- on a still frame the world stops redoing settled work — each cut an exact gate, measured with the process pinned to the efficiency cores, where the main thread IS the frame: point lookups go through the water index, a terrain column tests its cell's four fan triangles, not the chunk's 256 (−1.3 ms), the flare march resolves its tile once, the static-world publish and light blob write only on change, billboards, emitter gates (off the new-portal edge), doodad-anim verdicts, the visibility walk, the unit publisher (its filter a named type), a rampless unit's alpha and the stable feed skip when nothing moved, the rig evaluator reuses its scratch, dormant emitters skip their step, child wiring visits pending emitters only, the shade map persists, and the terrain streamer skips its walk once settled; alone parked 25.4 → 21.6–22.8 ms of main thread, 32 → 36–38 fps there with nothing on screen (1979, 1982)
- the UI tick got the same treatment: a solo run's colour rides the material, not the mesh — the glow pulse's one `Assets<Mesh>` write a frame had armed bevy's asset-changed probes over ~44 k `Mesh3d` rows (−1.0 ms); script object ids index a dense map instead of a hash, where every scripted method call starts (−0.7 ms); the draw list is fingerprint-cached, walked every frame and sorted only when it changed (the list a named type); and the instrument that made the gates count at all: the first battery read flat until the probe printed how many frames each gate input had read as changed — `noisy=[cam:0,dbg:299,view:0,win:0,claim:0]` — one dev system took `&mut` on `DebugState` every frame to test a flag, so bevy marked it changed on 299 of 300 frames and silently disarmed every gate reading `debug.is_changed()`; it reads the flag first now, and the counters stay on the probe line (1982)
- two of the new gates were wrong the day they landed and are fixed in the same snapshot: the streamer's settled skip engaged the frame `complete` flipped, with the retained pass still baking the new cells, and froze the undrawn count `presentable()` reads above zero — the loading screen stayed up for good after a `.tele`; it now waits for a paced, presentable, complete world and keeps that count fresh; and the still-frame gates read the camera's `GlobalTransform`, which moves only after propagation — which runs after them — so a teleport frame carried every host's pre-snap verdict across the snap (a lamppost glow due to park kept its clock, over-bright after the `.tele`); the gates read the seat's own `Transform` write too (1982)
- a guild master can design the guild's tabard: the reference's own `TabardFrame.xml` joins the manifest (benilla never had the window), opened only from the wire — the click ladder's TabardDesigner arm now sends `MSG_TABARDVENDOR_ACTIVATE` and the Battlemaster arm its own hello (1861's two deviations retire); the `TabardModel` method table runs over five ints bounded by the `.rdata` table `{170, 17, 6, 17, 51}`, the design previews on the player's own body so the pane and the world show one look, and `Save` runs the fourteen pre-flight checks in the reference's order; the world frame is the reference's own `WorldFrame.xml` too — the framerate readout is live on CTRL-R — and the carve settled its kind: a `Frame` to Lua, a one-shot type, the sole tenant of stratum WORLD, and not "over the UI" when hovered, so world clicks and camera look stay live while its scripts fire (1977, 1983, 1984)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
99 lines
3.4 KiB
Rust
99 lines
3.4 KiB
Rust
//! The `WorldFrame` kind (decisions 1983/1984; wow-re `worldframe-widget.md`): a `Frame` to Lua,
|
|
//! a one-shot type, born in stratum `WORLD` with mouse and wheel enabled, and a hit the app's
|
|
//! arbiter must be able to tell apart.
|
|
|
|
use crate::script::UiScript;
|
|
|
|
fn vm() -> UiScript {
|
|
let mut s = UiScript::new().unwrap();
|
|
s.set_screen_size(1024.0, 768.0);
|
|
s.run(r#"WorldFrame = CreateFrame("WorldFrame", "WorldFrame") WorldFrame:SetAllPoints()"#)
|
|
.unwrap();
|
|
s.resolve();
|
|
s
|
|
}
|
|
|
|
/// `GetObjectType()` answers `"Frame"` and `IsObjectType("WorldFrame")` is nil: the class
|
|
/// inherits the base table's type slots (the TaxiRouteFrame precedent), so the registered name
|
|
/// never becomes an identity.
|
|
#[test]
|
|
fn the_world_frame_is_a_frame_to_lua() {
|
|
let s = vm();
|
|
assert_eq!(
|
|
s.eval::<String>("return WorldFrame:GetObjectType()")
|
|
.unwrap(),
|
|
"Frame"
|
|
);
|
|
assert!(s
|
|
.eval::<bool>(r#"return WorldFrame:IsObjectType("Frame") == 1 and WorldFrame:IsObjectType("Region") == 1"#)
|
|
.unwrap());
|
|
assert!(s
|
|
.eval::<bool>(r#"return WorldFrame:IsObjectType("WorldFrame") == nil"#)
|
|
.unwrap());
|
|
}
|
|
|
|
/// The registry record is destroyed on the first instantiation: a second one is an unknown type.
|
|
#[test]
|
|
fn a_second_world_frame_is_an_unknown_type() {
|
|
let s = vm();
|
|
let err = s
|
|
.run(r#"CreateFrame("WorldFrame", "Another")"#)
|
|
.unwrap_err()
|
|
.to_string();
|
|
assert!(err.contains("unknown frame type 'WorldFrame'"), "{err}");
|
|
assert!(s.eval::<bool>("return Another == nil").unwrap());
|
|
}
|
|
|
|
/// Born in stratum 0 (`WORLD`, below `BACKGROUND`) with key/mouse/wheel enabled; no XML or Lua can
|
|
/// name that stratum for another frame.
|
|
#[test]
|
|
fn the_world_frame_is_born_in_stratum_world_with_the_mouse_and_wheel() {
|
|
let s = vm();
|
|
assert_eq!(
|
|
s.eval::<String>("return WorldFrame:GetFrameStrata()")
|
|
.unwrap(),
|
|
"WORLD"
|
|
);
|
|
assert!(s
|
|
.eval::<bool>(
|
|
"return WorldFrame:IsMouseEnabled() == 1 and WorldFrame:IsMouseWheelEnabled() == 1"
|
|
)
|
|
.unwrap());
|
|
s.run(r#"plain = CreateFrame("Frame", "Plain") plain:SetFrameStrata("BACKGROUND")"#)
|
|
.unwrap();
|
|
let err = s
|
|
.run(r#"plain:SetFrameStrata("WORLD")"#)
|
|
.unwrap_err()
|
|
.to_string();
|
|
assert!(err.contains("unknown frameStrata 'WORLD'"), "{err}");
|
|
assert_eq!(
|
|
s.eval::<String>("return plain:GetFrameStrata()").unwrap(),
|
|
"BACKGROUND"
|
|
);
|
|
}
|
|
|
|
/// The hit test answers the world frame where nothing else is under the cursor — the addon-facing
|
|
/// scripts on it fire — and the app can tell that hit apart from a UI hit.
|
|
#[test]
|
|
fn a_hit_on_the_world_frame_is_told_apart_from_a_ui_hit() {
|
|
let mut s = vm();
|
|
let id = s
|
|
.hit_test(100.0, 100.0)
|
|
.expect("the world frame is under the cursor");
|
|
assert!(s.is_world_frame(id));
|
|
s.run(
|
|
r#"plate = CreateFrame("Frame", "Plate", WorldFrame) plate:SetWidth(50) plate:SetHeight(50)
|
|
plate:SetPoint("BOTTOMLEFT", WorldFrame, "BOTTOMLEFT", 75, 75) plate:EnableMouse(true)"#,
|
|
)
|
|
.unwrap();
|
|
s.resolve();
|
|
let over_plate = s
|
|
.hit_test(100.0, 100.0)
|
|
.expect("the plate is under the cursor now");
|
|
assert!(
|
|
!s.is_world_frame(over_plate),
|
|
"a child frame's hit is the UI's"
|
|
);
|
|
assert!(s.is_world_frame(s.hit_test(600.0, 600.0).unwrap()));
|
|
}
|