- `UnitHasRelicSlot` is real in 1.12 and benilla had no binding for it: `0x519e50` reads `ChrClasses.dbc` field 16 — set for Paladin, Shaman and Druid in `patch.MPQ`'s 17-column copy (the base `dbc.MPQ` copy has 16 columns and no such field, which is how the "always false in vanilla" belief survived twice in decisions and seven times in code) — and stock `PaperDollFrame.lua` calls it unconditionally, so the character sheet would have raised for EVERY class; a druid, paladin or shaman's sheet now hides the ammo slot, shows the relic plate where the bow was, tooltips "Relic", and reports ranged Attack/Damage/Power as N/A, all four branches transcribed from the reference - the loot window is the reference's own `LootFrame.xml`: `LootButton` is built as a real widget type rather than aliased (a Button plus one slot dword and one overridden OnClick — right-click loots exactly like left, no shift/ctrl/alt takes, a row whose Lua handler errored still loots, a fast double-click takes two slots), `LOOT_SLOT_CLEARED` fires per row again because the stock file hangs hide-in-place AND the emptied-page auto-advance off it, `EditBox:Insert(nil)` is a no-op as `lua_tostring` makes it, and an alias `GameTooltip.xml` had quietly become a reader of would have turned every item tooltip white, silently, had it just gone nil - the vendor cursor: `PickupMerchantItem` is two verbs behind one name, decided by what the cursor holds and never by the caller — a held bag item SELLS (index ignored, no merchant-open gate), otherwise the vendor row is grabbed as cursor mode 5, which is invisible to `CursorHasItem` (modes 1 and 9 only) so all thirteen stock gates stay closed while it is held; the drop is the buy, `CMSG_BUY_ITEM_IN_SLOT`, count 1, into a bag or an equipment slot, and every refusal is silent and clears the cursor; the four `Model_*` rotation handlers land in UIParent where the reference keeps them - the gap report reads `:Method(` sites now — it found `SetMerchantCompareItem`, which would have raised on the first vendor-row hover with every check green, and `LootButton:SetSlot`, and 28 "free" windows became 25; the shared coin kit moved out of the merchant window into `MoneyFrame.xml` so the eight windows that draw coins through it can reach it without loading a vendor Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
47 lines
1.9 KiB
Rust
47 lines
1.9 KiB
Rust
//! `ChrClasses.dbc`, loaded once and read by everything that asks the client a question about a
|
|
//! class.
|
|
//!
|
|
//! Two consumers today and they are unrelated to each other — [`crate::ui_pet_book`] wants field
|
|
//! 4's pet name token, `UnitHasRelicSlot` wants field 16's relic flag — which is exactly why the
|
|
//! table does not live inside either of them. It used to live in the pet book, back when the pet
|
|
//! token was the only column anyone read.
|
|
//!
|
|
//! The resource is **absent**, not empty, when the load fails. Both readers then fall to the
|
|
//! reference's own degraded answer (`"PET"` for the token, no relic slot for any class), so a
|
|
//! missing table costs a warlock the word "Demon" and a paladin their relic branches rather than
|
|
//! taking the client down.
|
|
|
|
use bevy::prelude::*;
|
|
|
|
use benilla_assets::{AssetSet, LockRecover, WorldAssets};
|
|
use benilla_formats::ChrClasses;
|
|
|
|
/// The parsed table — see [`benilla_formats::ChrClasses`] for what each column is and which bytes
|
|
/// say so.
|
|
#[derive(Resource)]
|
|
pub(crate) struct ChrClassTable(pub(crate) ChrClasses);
|
|
|
|
pub(crate) struct ChrClassesPlugin;
|
|
|
|
impl Plugin for ChrClassesPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.add_systems(Startup, load_chr_classes.after(AssetSet::Open));
|
|
}
|
|
}
|
|
|
|
fn load_chr_classes(mut commands: Commands, assets: Option<Res<WorldAssets>>) {
|
|
let Some(assets) = assets else { return };
|
|
let loaded = {
|
|
let mut chain = assets.chain.lock_recover();
|
|
benilla_formats::load_chr_classes(&mut chain)
|
|
};
|
|
match loaded {
|
|
Ok(table) => commands.insert_resource(ChrClassTable(table)),
|
|
Err(e) => warn!(
|
|
"chr_classes: ChrClasses.dbc failed to load — every pet book tab reads the client's \
|
|
own \"PET\" fallback, so a warlock's says Pet rather than Demon, and no class reads \
|
|
as having a relic slot: {e:#}"
|
|
),
|
|
}
|
|
}
|