This checkout had no git history at all, so this one commit carries the whole
of the Everwood work as a single import on top of chairmanpow/benilla-octo's
`main` (706cd71). The two trees have genuinely diverged — each has files the
other does not — so this is a fork point, not a catch-up.
Today's work, which is the reason a baseline exists at all:
- Booth previews no longer cast world shadows (`NO_BOOTH_SHADOW`). Portrait
characters were entering the sun's shadow cascades, so every skinned-rig
shadow specialization compiled live mid-frame; the hitch detector logged
"main thread blocked 1316 ms" beside a `compiled LIVE` warning. This was
the Fashion/Tmog stutter.
- Per-pane dress-up: each `DressUpModel` pane assembles and stages its own
tried-on look instead of every pane mirroring the live player.
- Item template cache is append-only JSONL written on the IO pool, replacing
an 11.6 MB whole-map JSON rewrite on the main thread every 10 s.
- `WOW_SYSTEM_TIMING` rebuilt per-thread: it took 2 mutexes per system enter
and 4 per exit, costing 15 ms a frame (590 fps -> 60) and corrupting the
measurements it was taken to produce.
- The visibility-churn sweep moved to its own `WOW_FLASH_CHURN` switch, so a
frame-cost reading no longer pays 2.7 ms a frame for it.
Local state (`benilla-config/`, `logs/`, `target/`) is excluded by the
existing .gitignore; the account credential it holds is not in this commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
156 lines
5.6 KiB
Rust
156 lines
5.6 KiB
Rust
//! The stock guild tabard designer (`TabardFrame.xml`): the open event seeds and shows it, the rows
|
|
//! cycle the design, Save follows `CanSaveTabardNow`, and closing calls `CloseTabardCreation`.
|
|
|
|
use benilla_ui::script::{
|
|
emblem_mask_path, TabardHost, TabardIntent, UiScript, UnitGuild, UnitState,
|
|
};
|
|
|
|
/// The player in a guild at `rank`, 0 the master; `GetGuildInfo("player")` reads the unit's guild.
|
|
fn harness(rank: u32) -> UiScript {
|
|
let mut s = UiScript::new().unwrap();
|
|
s.set_screen_size(1024.0, 768.0);
|
|
for (token, name, guild) in [
|
|
(
|
|
"player",
|
|
"Probefour",
|
|
Some(UnitGuild {
|
|
name: "Probe Guild".into(),
|
|
rank_name: if rank == 0 { "Guild Master" } else { "Member" }.into(),
|
|
rank_index: rank,
|
|
}),
|
|
),
|
|
("npc", "Tabard Vendor", None),
|
|
] {
|
|
s.set_unit(
|
|
token,
|
|
Some(UnitState {
|
|
exists: true,
|
|
name: Some(name.into()),
|
|
level: 60,
|
|
guild,
|
|
..Default::default()
|
|
}),
|
|
);
|
|
}
|
|
for file in [
|
|
"Interface\\FrameXML\\Fonts.xml",
|
|
r"Interface\FrameXML\UIParent.xml",
|
|
"ScrollTemplates.xml", // ours: the scroll kits
|
|
r"Interface\FrameXML\MoneyFrame.lua",
|
|
r"Interface\FrameXML\MoneyFrame.xml",
|
|
r"Interface\FrameXML\UIPanelTemplates.lua",
|
|
r"Interface\FrameXML\UIPanelTemplates.xml",
|
|
"Interface\\FrameXML\\GlobalStrings.lua",
|
|
"Interface\\FrameXML\\BasicControls.xml",
|
|
"Interface\\FrameXML\\LocaleProperties.lua",
|
|
"Interface\\FrameXML\\StaticPopup.xml",
|
|
"Interface\\FrameXML\\GameTooltip.xml",
|
|
r"Interface\FrameXML\TabardFrame.xml",
|
|
] {
|
|
super::test_ui::load_ui(&s, file);
|
|
}
|
|
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
|
s
|
|
}
|
|
|
|
/// `MSG_TABARDVENDOR_ACTIVATE` fires `OPEN_TABARD_FRAME`; the handler seeds the design from the
|
|
/// guild record and shows the panel (`TabardFrame.lua:25`).
|
|
#[test]
|
|
fn the_open_event_seeds_the_design_paints_the_cells_and_shows_the_window() {
|
|
let _data = benilla_formats::wow_data_or_skip!();
|
|
let mut s = harness(0);
|
|
s.set_tabard_host(TabardHost {
|
|
guild_record: Some([12, 4, 1, 2, 9]),
|
|
save_pending: false,
|
|
});
|
|
s.fire_event("OPEN_TABARD_FRAME", vec![]);
|
|
s.resolve();
|
|
assert!(s.eval::<bool>("return TabardFrame:IsVisible()").unwrap());
|
|
assert_eq!(s.tabard_design(), Some([12, 4, 1, 2, 9]));
|
|
assert_eq!(
|
|
s.eval::<String>("return TabardFrameNameText:GetText()")
|
|
.unwrap(),
|
|
"Tabard Vendor"
|
|
);
|
|
let cell = s
|
|
.eval::<String>("return TabardFrameEmblemTopLeft:GetTexture()")
|
|
.unwrap();
|
|
assert_eq!(
|
|
emblem_mask_path(&cell),
|
|
Some(r"Textures\GuildEmblems\Emblem_12_04_TU_U")
|
|
);
|
|
let cell = s
|
|
.eval::<String>("return TabardFrameEmblemBottomRight:GetTexture()")
|
|
.unwrap();
|
|
assert!(cell.ends_with("Emblem_12_04_TL_U"), "{cell}");
|
|
assert!(
|
|
s.eval::<bool>("return TabardFrameAcceptButton:IsEnabled() == 1")
|
|
.unwrap(),
|
|
"a guild master with a cached record can save"
|
|
);
|
|
assert_eq!(
|
|
s.eval::<String>("return TabardFrameGreetingText:GetText()")
|
|
.unwrap(),
|
|
s.eval::<String>("return TABARDVENDORGREETING").unwrap()
|
|
);
|
|
|
|
s.run("TabardCustomization_Right(1)").unwrap();
|
|
assert_eq!(s.tabard_design(), Some([13, 4, 1, 2, 9]));
|
|
let cell = s
|
|
.eval::<String>("return TabardFrameEmblemTopRight:GetTexture()")
|
|
.unwrap();
|
|
assert!(cell.ends_with("Emblem_13_04_TU_U"), "{cell}");
|
|
s.run("TabardCustomization_Left(5) TabardCustomization_Left(5)")
|
|
.unwrap();
|
|
assert_eq!(s.tabard_design().unwrap()[4], 7);
|
|
|
|
// Save sends the five values; the pending latch greys the button (`TabardFrame.lua:38`).
|
|
s.run("TabardFrameAcceptButton:Click()").unwrap();
|
|
assert_eq!(
|
|
s.take_tabard_intents(),
|
|
vec![TabardIntent::Save([13, 4, 1, 2, 7])]
|
|
);
|
|
s.set_tabard_host(TabardHost {
|
|
guild_record: Some([12, 4, 1, 2, 9]),
|
|
save_pending: true,
|
|
});
|
|
s.fire_event("TABARD_SAVE_PENDING", vec![]);
|
|
assert!(
|
|
!s.eval::<bool>("return TabardFrameAcceptButton:IsEnabled() == 1")
|
|
.unwrap(),
|
|
"the latch greys the button"
|
|
);
|
|
|
|
// Cancel hides the panel, whose OnHide calls `CloseTabardCreation` (`TabardFrame.xml:625`).
|
|
s.run("TabardFrameCancelButton:Click()").unwrap();
|
|
s.resolve();
|
|
assert!(!s.eval::<bool>("return TabardFrame:IsVisible()").unwrap());
|
|
assert_eq!(s.take_tabard_intents(), vec![TabardIntent::Close]);
|
|
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
|
}
|
|
|
|
/// No guild or a rank above 0: the no-guild greeting and no Save (`TabardFrame.lua:97`).
|
|
#[test]
|
|
fn a_non_master_gets_the_no_guild_greeting_and_no_save() {
|
|
let _data = benilla_formats::wow_data_or_skip!();
|
|
let mut s = harness(3);
|
|
s.set_tabard_host(TabardHost {
|
|
guild_record: Some([-1; 5]),
|
|
save_pending: false,
|
|
});
|
|
s.fire_event("OPEN_TABARD_FRAME", vec![]);
|
|
assert!(!s
|
|
.eval::<bool>("return TabardFrameAcceptButton:IsEnabled() == 1")
|
|
.unwrap());
|
|
assert_eq!(
|
|
s.eval::<String>("return TabardFrameGreetingText:GetText()")
|
|
.unwrap(),
|
|
s.eval::<String>("return TABARDVENDORNOGUILDGREETING")
|
|
.unwrap()
|
|
);
|
|
s.fire_event("CLOSE_TABARD_FRAME", vec![]);
|
|
s.resolve();
|
|
assert!(!s.eval::<bool>("return TabardFrame:IsVisible()").unwrap());
|
|
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
|
}
|