The nameplate verbs write two runtime bits, cleared at world entry, and the setting lives in FrameXML's saved variables, not two CVars (#571)
The nameplate verbs now answer as the reference's (`0x489450`-`0x489480`): they flip bits `0x1` (enemy) and `0x8` (friend) of runtime state, write no CVar, and world entry clears both (`0x401639` → `0x6033c0`, after `VARIABLES_LOADED`). The setting persists only through FrameXML's `NAMEPLATES_ON`/`FRIENDNAMEPLATES_ON`, as on 1.12.1. - The `nameplateShowEnemies`/`nameplateShowFriends` CVar rows and the host's plate push are gone. A player's saved plate setting in `config.toml` moves once into the saved variables at the first world entry. - benilla's layer keeps what players see today. Its `UpdateNameplates` fix drops the stock show-then-hide (`UIOptionsFrame.lua:775-776`), and it registers `FRIENDNAMEPLATES_ON` for saving, which the stock file never does (`:180-183`). So plates turned on come back after login. - With the layer off, benilla behaves as 1.12.1: friendly plates are off after entry. - The V keys flip the verb and the saved global together. V and Shift-V keep their recorded deviation; #570 tracks moving the binding table onto the stock `Bindings.xml`. Verified: - New tests for the verbs, the entry clear, the stock-only and layered persistence across entry and reload, the V keys and the one-time migration, each failing with its change undone. - `scripts/gates.sh` and `scripts/smoke.sh` are green. - A live run with `WOW_GM=off` turned both kinds on, relogged and read both back, from the file too. Built on macOS; no platform seam touched. Fixes #552 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
05e204de10
commit
0a1f69466c
@@ -1459,58 +1459,67 @@ fn the_pfui_hdgraphic_extended_arm_runs() {
|
||||
|
||||
/// `ShowNameplates 0x489450`, `HideNameplates 0x489460`, `ShowFriendNameplates 0x489470` and
|
||||
/// `HideFriendNameplates 0x489480` read no argument and return nothing: four 10-byte bodies over
|
||||
/// two setters, differing only in an `or`/`and` mask.
|
||||
/// two setters, differing only in an `or`/`and` mask. They write bits `0x1` and `0x8` of the
|
||||
/// runtime dword `[0xc4da34]` and no CVar: 1.12 registers none (no `0x63db90` site names a plate).
|
||||
#[test]
|
||||
fn the_nameplate_verbs_ignore_their_arguments_and_return_nothing() {
|
||||
let s = script();
|
||||
s.register_cvars([
|
||||
(crate::script::CVAR_NAMEPLATE_ENEMIES, "1"),
|
||||
(crate::script::CVAR_NAMEPLATE_FRIENDS, "0"),
|
||||
]);
|
||||
fn the_nameplate_verbs_write_two_runtime_bits_and_no_cvar() {
|
||||
use crate::script::{PLATE_BIT_ENEMY as ENEMY, PLATE_BIT_FRIEND as FRIEND};
|
||||
let mut s = script();
|
||||
|
||||
let get = |s: &crate::script::UiScript, n: &str| s.cvar(n);
|
||||
assert_eq!(
|
||||
get(&s, crate::script::CVAR_NAMEPLATE_ENEMIES).as_deref(),
|
||||
Some("1")
|
||||
s.run("ShowNameplates()").unwrap();
|
||||
assert_eq!(s.take_nameplate_bit_writes().apply(0), ENEMY);
|
||||
assert!(
|
||||
s.take_nameplate_bit_writes().is_empty(),
|
||||
"a drain empties the queue"
|
||||
);
|
||||
|
||||
s.run("HideNameplates()").unwrap();
|
||||
assert_eq!(
|
||||
get(&s, crate::script::CVAR_NAMEPLATE_ENEMIES).as_deref(),
|
||||
Some("0")
|
||||
);
|
||||
assert_eq!(
|
||||
get(&s, crate::script::CVAR_NAMEPLATE_FRIENDS).as_deref(),
|
||||
Some("0"),
|
||||
s.take_nameplate_bit_writes().apply(ENEMY | FRIEND),
|
||||
FRIEND,
|
||||
"the friendly bit is a separate setter — hiding enemies must not touch it"
|
||||
);
|
||||
s.run("ShowFriendNameplates()").unwrap();
|
||||
assert_eq!(
|
||||
get(&s, crate::script::CVAR_NAMEPLATE_FRIENDS).as_deref(),
|
||||
Some("1")
|
||||
);
|
||||
assert_eq!(
|
||||
get(&s, crate::script::CVAR_NAMEPLATE_ENEMIES).as_deref(),
|
||||
Some("0"),
|
||||
s.take_nameplate_bit_writes().apply(0),
|
||||
FRIEND,
|
||||
"...and back the other way"
|
||||
);
|
||||
s.run("HideFriendNameplates()").unwrap();
|
||||
assert_eq!(s.take_nameplate_bit_writes().apply(FRIEND), 0);
|
||||
|
||||
// In call order, the last write per bit standing, as the setters `or`/`and` the live dword.
|
||||
s.run("ShowFriendNameplates() HideFriendNameplates() HideNameplates() ShowNameplates()")
|
||||
.unwrap();
|
||||
assert_eq!(s.take_nameplate_bit_writes().apply(FRIEND), ENEMY);
|
||||
// The frame loop's latches, bits `0x2` and `0x4`, are no verb's to touch.
|
||||
s.run("HideNameplates() HideFriendNameplates()").unwrap();
|
||||
assert_eq!(s.take_nameplate_bit_writes().apply(0xff), !(ENEMY | FRIEND));
|
||||
|
||||
s.run("ShowNameplates(false)").unwrap();
|
||||
assert_eq!(
|
||||
get(&s, crate::script::CVAR_NAMEPLATE_ENEMIES).as_deref(),
|
||||
Some("1"),
|
||||
s.take_nameplate_bit_writes().apply(0),
|
||||
ENEMY,
|
||||
"the verb IS the value — a falsy argument does not invert it"
|
||||
);
|
||||
for call in ["HideNameplates(1, 2, 3)", "ShowFriendNameplates({})"] {
|
||||
s.run(call)
|
||||
.unwrap_or_else(|e| panic!("{call} must not raise: {e}"));
|
||||
}
|
||||
let _ = s.take_nameplate_bit_writes();
|
||||
|
||||
assert_eq!(
|
||||
s.arity("ShowNameplates()").unwrap(),
|
||||
0,
|
||||
"zero values — observably different from nil for a caller that counts"
|
||||
);
|
||||
assert!(
|
||||
s.take_cvar_changes().is_empty(),
|
||||
"no CVar written: the dword is not a setting"
|
||||
);
|
||||
for name in ["nameplateShowEnemies", "nameplateShowFriends"] {
|
||||
assert_eq!(s.cvar(name), None, "{name}: no plate CVar is registered");
|
||||
}
|
||||
}
|
||||
|
||||
/// The host seams benilla's own interface used are gone, now that it speaks 1.12 alone: the key
|
||||
|
||||
Reference in New Issue
Block a user