the action bars are the reference's own, and a gift can be wrapped
- the action-bar cluster is the reference's own: `MainMenuBar.xml`, `ActionBarFrame.xml`, `MultiActionBars.xml` and `BonusActionBarFrame.xml` run off the player's own chain, and our `ActionBar.xml` (2047 lines), `MultiBars.xml` and `StanceBar.xml` are deleted — three, since the stock bonus-bar file declares the shapeshift bar too; one engine verb, `ChangeActionBarPage`, fires `ACTIONBAR_PAGE_CHANGED` and nothing else; one load blocker: stock `MultiActionBars.lua` writes the options window's table from its OnLoad, the reference's own load-order hack, so our options window moves to the reference's toc slot; and ten things the reference does that ours did not: an empty button is HIDDEN while showgrid is 0, the bonus overlay sits one pixel right of the main buttons, every slide takes one frame more than its time, and `ActionButton_ShowGrid` ghosts EVERY ring, occupied included (1938) - a gift can be wrapped: right-clicking wrapping paper fell through to plain use and sent `CMSG_USE_ITEM`, so nothing happened — you could receive a gift and never give one; the wrap is a displayed-cursor MODE plus a stashed slot, never a payload, so `CursorHasItem()` stays false and every stock gate on it stays shut: right-click arms it, a left-click on a bag slot sends `CMSG_WRAP_ITEM`, and the client applies no eligibility test — the server's `ERR_CANT_WRAP_*` reasons are the error line (1934); a duration-limited item counts down: `SMSG_ITEM_TIME_UPDATE` parks a deadline and the tooltip's `ITEM_DURATION` line runs the enchant countdown's bucket ladder, so "Duration: 1 days" is what the reference renders; an update for an item we do not hold is DROPPED, no queue (1933); and a renamed crowd-control refusal names its mechanic — "Can't do that while stunned" — off `SpellMechanic.dbc` (1943) - a creature paths on a boat: `SMSG_MONSTER_MOVE_TRANSPORT` carries the transport's guid and deck-local coordinates, and is the attach/detach edge; a deck sample lands on the rider or nowhere, never as a world write a few yards from the map origin; and "there is no terrain under a boat" turned out wrong: the ground probe admits GameObject meshes — a boat's `.wmo` is a GameObject, so the probe hits the deck (1936); `MSG_MOVE_TIME_SKIPPED` is read, not dropped — the reference adds the lag to the observed unit's last-wire stamp, so dropping it scheduled their next packet `lag` ms late, a hitch for every player who stalled zoning in near us; and our own settle hold reports once (1935); and the tradeskill tool order was backwards — focus FIRST, so every two-tool recipe had read "Blacksmith Hammer, Anvil" for the reference's "Anvil, Blacksmith Hammer"; the focus's `hasTool` is 1.0 in the reference too (1942) - the crowd's second sitting, instruments first: the probe line carries the tail — cpu p95/p99 and the six worst frames — because a mean under budget hides the one frame in twenty over it (raid legs railed at 16.67 with p95 at 18–20 ms) and whether that frame was work or a wait is the first question about a stutter, and the visible meshes are counted by lane; then two cuts — a terrain tile furnishes as 4×4 cells of 4×4 chunks, one mesh, one entity, one draw per 133-yd cell instead of per 33-yd chunk (a city horizon is over a thousand chunks a frame, and a cell changes nothing a pixel can see; Stormwind 10.55 → 10.32 `cpu_ms`), and an authored point light is our own `WorldPointLight`, not Bevy's `PointLight`, which was only a data carrier while Bevy ran its whole light lane over every lamp, ~2 % of the alone frame; the sitting's record is 1945, and the code says so (1945) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -1075,8 +1075,7 @@ mod tests {
|
||||
/// do not ship under its own name usually has a counterpart of ours under a different one, and
|
||||
/// both would declare the same frames.
|
||||
///
|
||||
/// That half doubles as the map nothing else holds: `ActionBarFrame.xml` is our
|
||||
/// `ActionBar.xml`, `FloatingChatFrame.xml` is our `ChatFrame.xml`,
|
||||
/// That half doubles as the map nothing else holds: `FloatingChatFrame.xml` is our `ChatFrame.xml`,
|
||||
/// `MainMenuBarMicroButtons.xml` is our `MicroMenu.xml`, `StaticPopup.xml` is our
|
||||
/// `UiPanels.xml`. (The row this map used to lead with — `PlayerFrame.xml`/`TargetFrame.xml`/
|
||||
/// `PetFrame.xml` all being our one `UnitFrames.xml` — is retired: those four are the
|
||||
@@ -2037,11 +2036,6 @@ mod tests {
|
||||
flow works without it",
|
||||
),
|
||||
("ITEM_TEXT_TRANSLATION", "ItemTextFrame.lua"),
|
||||
(
|
||||
"PARTY_MEMBER_DISABLE",
|
||||
"PartyMemberFrame.lua — the offline grey-out",
|
||||
),
|
||||
("PARTY_MEMBER_ENABLE", "PartyMemberFrame.lua"),
|
||||
("PET_UI_CLOSE", "PetPaperDollFrame.lua"),
|
||||
("PET_UI_UPDATE", "PetPaperDollFrame.lua"),
|
||||
("PLAYER_DAMAGE_DONE_MODS", "PaperDollFrame.lua"),
|
||||
@@ -2049,10 +2043,6 @@ mod tests {
|
||||
"PLAYER_FLAGS_CHANGED",
|
||||
"TargetFrame.lua — the AFK/DND badge",
|
||||
),
|
||||
(
|
||||
"PLAYER_REGEN_ENABLED",
|
||||
"PlayerFrame.lua — and _DISABLED is unfired too, so the pair is whole",
|
||||
),
|
||||
("PLAYTIME_CHANGED", "PlayerFrame.lua"),
|
||||
("SHOW_COMPARE_TOOLTIP", "PaperDollFrame.lua"),
|
||||
("SYSMSG", "UIErrorsFrame.lua"),
|
||||
@@ -2080,47 +2070,59 @@ mod tests {
|
||||
} else if p.extension().is_some_and(|x| x == "rs") {
|
||||
let text = std::fs::read_to_string(&p).unwrap_or_default();
|
||||
// Split so this file cannot match its own walker (see the sibling gate).
|
||||
const CALL: &str = concat!("fire_event", "(");
|
||||
let mut from = 0;
|
||||
// Two producer shapes: `UiScript::fire_event(` and its `&Lua` twin
|
||||
// `tick::fire_event_into(` (1924), which an engine verb fires from inside a
|
||||
// binding — `UpdateSpells` → SPELLS_CHANGED, `ChangeActionBarPage` →
|
||||
// ACTIONBAR_PAGE_CHANGED (1938).
|
||||
const CALLS: [&str; 2] =
|
||||
[concat!("fire_event", "("), concat!("fire_event_into", "(")];
|
||||
let mut fires_indirectly = false;
|
||||
while let Some(i) = text[from..].find(CALL) {
|
||||
let at = from + i + CALL.len();
|
||||
from = at;
|
||||
let rest = text[at..].trim_start();
|
||||
if !rest.starts_with('"') {
|
||||
// `fire_event(event, args)` — the name reached the call through a
|
||||
// variable, so adjacency cannot see it. `ui_cast.rs` does exactly
|
||||
// this: a `match edge` yields `("SPELLCAST_INTERRUPTED", vec![])` and
|
||||
// one call site fires whatever it produced. Treated below.
|
||||
fires_indirectly = true;
|
||||
}
|
||||
if let Some(body) = rest.strip_prefix('"') {
|
||||
if let Some(end) = body.find('"') {
|
||||
fired.insert(body[..end].to_string());
|
||||
for call in CALLS {
|
||||
let mut from = 0;
|
||||
while let Some(i) = text[from..].find(call) {
|
||||
let at = from + i + call.len();
|
||||
from = at;
|
||||
let rest = text[at..].trim_start();
|
||||
let rest = rest.strip_prefix("lua,").map_or(rest, str::trim_start);
|
||||
if !rest.starts_with('"') {
|
||||
fires_indirectly = true;
|
||||
}
|
||||
if let Some(body) = rest.strip_prefix('"') {
|
||||
if let Some(end) = body.find('"') {
|
||||
fired.insert(body[..end].to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if fires_indirectly {
|
||||
// The name reached `fire_event` through a variable. Rather than guess, we
|
||||
// match the SHAPE that produced it: `("EVENT_NAME", vec!` — a tuple whose
|
||||
// second element is the argument vector, which is how `ui_cast.rs`'s
|
||||
// `match edge` hands a name and its args to one shared call site.
|
||||
//
|
||||
// The first attempt at this counted EVERY SCREAMING_CASE literal in such a
|
||||
// file, and that swept up eighteen names off the UNPRODUCED list — a gate
|
||||
// made vacuous by its own conservatism, which is the failure mode this
|
||||
// file has now hit twice. The shape is the discipline: it admits the
|
||||
// literals that are actually being fired and nothing else.
|
||||
// An indirect fire names its event either as `"NAME", vec![…]` or as one
|
||||
// arm of an `if … { "A" } else { "B" }` chosen before the call — a literal
|
||||
// standing alone on its line (`ui_action/state.rs`'s START/STOP_AUTOREPEAT).
|
||||
const SHAPE: &str = "\", vec!";
|
||||
let caps = |lit: &str| {
|
||||
!lit.is_empty()
|
||||
&& lit.chars().all(|c| {
|
||||
c.is_ascii_uppercase() || c == '_' || c.is_ascii_digit()
|
||||
})
|
||||
};
|
||||
for (i, _) in text.match_indices(SHAPE) {
|
||||
let before = &text[..i];
|
||||
let Some(q) = before.rfind('"') else { continue };
|
||||
let lit = &before[q + 1..];
|
||||
if !lit.is_empty()
|
||||
&& lit.chars().all(|c| {
|
||||
c.is_ascii_uppercase() || c == '_' || c.is_ascii_digit()
|
||||
})
|
||||
{
|
||||
if caps(lit) {
|
||||
fired.insert(lit.to_string());
|
||||
}
|
||||
}
|
||||
let lines: Vec<&str> = text.lines().map(str::trim).collect();
|
||||
for (i, t) in lines.iter().enumerate() {
|
||||
let Some(lit) = t.strip_prefix('"').and_then(|x| x.strip_suffix('"'))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let arm = i > 0
|
||||
&& lines[i - 1].ends_with('{')
|
||||
&& lines.get(i + 1).is_some_and(|n| n.starts_with('}'));
|
||||
if arm && caps(lit) {
|
||||
fired.insert(lit.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user