File Details
Housing Decor Guide v2.41.0
- R
- May 7, 2026
- 1.96 MB
- 4.7K
- 12.0.5+2
- Retail
File Name
HousingDecorGuide-2.41.0.zip
Supported Versions
- 12.0.5
- 12.0.1
- 12.0.0
* House Editor: HDG no longer touches Blizzard's HouseEditorStoragePanel
at all. Two attempts to inject a tab there (v2.39.0 and a 2026-05-08
retry) both crashed Blizzard's Catalog tab via productInfo-nil races
introduced in the 12.0.5 patch -- any participation in the storage
panel's tab dispatch was sufficient to trigger the bug, even with no
callbacks or catalog API calls of our own. Replaced with a small
launcher button (HDG icon, anchored to UIParent's left edge by
default, draggable) shown only while the housing editor is open;
click to toggle the standalone HDG editor window. Zero AddNamedTab,
zero SetTabCallback, zero hooksecurefunc, zero HookScript on any
Blizzard panel.
* Mogul tab polish (2026-05-08): fix locale lookup so all UI strings
resolve (was rendering raw keys like "MOGUL_HEADER_BEST_PLAN"); column
layout (Qty / Crafter / Recipe / Lumber-each / gold-per-lumber /
Revenue-Net / Expansion) with bordered + tinted header strip matching
the scrollbox width below; in-list section dividers ("Plan -- craft
these" / "Runners-up -- did not fit") with full-width accent
underlines; vertical theme-accent bar on each plan row to mark active
plan vs runner-ups; sortable plan rows (revenue desc) so greedy and LP
outputs align row-for-row when they pick the same plan; click a row
again to deselect (mats panel returns to plan-wide list); selection
survives refresh when the same recipe is still picked; mats panel
migrated to WowScrollBoxList (was clipping past ~6 entries with the
flat anchor chain); mat rows are have/need StatusBars colored by
progress (red/amber/green) with hover tooltips and AH-search /
Auctionator-multi-search / Auctionator-list click handlers ported
from MaterialsList; Send to Auctionator button moved to the action
row alongside Send-entire-plan and Hide-runners-up so all primary
actions sit in one strip; lumber budget panel at top-right of the
frame replaces the single "Lumber: N" readout, showing all 12 tiers
in two columns colored by expansion, with leftover-after-plan as
"have - used [arrow] remaining" and green numbers on tiers the plan
used; "Lumber-only / Lumber + mats" two-button toggle replaced with a
single "I'll buy mats from AH" checkbox plus an explainer tooltip
("checked = rank by net profit including AH cost of mats you don't
own; unchecked = rank by gross revenue, treats mats as free; owned
mats are always free in the spend math regardless of mode");
Greedy/LP buttons are blizz UIPanelButtonTemplate with auto-sized
width and tooltips explaining the algorithm choice; "Hide candidates"
renamed to "Hide runners-up" (and Show too) to match the section
divider; mat cost shown in collection-mode summary so the player sees
the gold required for non-owned reagents; collected/uncollected icon
and expansion-color background tint on every plan row; row hover
shows item tooltip + per-mat have/need + bestAlt; "Best on: <Alt>"
moved from inline name suffix to its own Crafter column with subtle
gold-accent text; the Crafter column shows the active player's name
in active-char view too so the column is meaningful in both modes.
* Mogul algorithm: shipped an LP-relaxation alternative to the greedy
planner. New modules/HDG_MogulLP.lua: pure-Lua tableau simplex with
Bland's rule (cycle-safe), solves max profit s.t. per-tier lumber
budgets, rounds down to integer crafts, then greedy-fills any
leftover; collection mode delegates back to greedy. Greedy/LP toggle
on the Mogul header lets players A/B compare. On typical single-tier
housing-recipe data the two algorithms produce identical plans (LP
relaxation collapses to the per-lumber greedy result); LP can win on
contrived multi-tier or shared-mat scenarios. 6 LP tests covering
empty input, single-tier parity with greedy, per-tier budget respect,
multi-tier ranking, collection delegation, dispatcher routing.
* Mogul engine: standardised reagent-quantity field name to `qty`
(previously some producers emitted `amount`, some `count`, some
`qty`; consumers had defensive `or` cascades reading all three).
Producer renames: HDG_PowerCrafting.normalizeReagents,
HDG_PowerCrafting.BuildReagentToRecipesIndex, HDG_Data recipe
iteration, HDG_GoblinTab queue insertion. Consumer cleanups across
HDG_RecipesTab, HDG_LumberTracker, HDG_MaterialsList,
HDG_PriceIntegration, HDG_DataTab (cascades stripped, dead defensive
branches removed). Plan-row count renamed to `crafts`; shoppingList
count renamed to `qty`. `lumberOnlyProfit`/`lumberPlusMatsProfit`
fields renamed to `revenuePerCraft`/`netProfitPerCraft` (per-craft)
and `revenue`/`netProfit` (totals) so user-facing labels read
"Revenue (mats free)" and "Net profit (mats bought)" -- the old
"lumber-only profit" name was confusing because the number is gross
revenue, not actual profit.
* Mogul engine: multi-tier lumber ranking fix. Recipes that need 2+
lumber tiers (rare in current data but possible) were under-ranked
because the per-lumber profit divisor was the SUM of lumber tiers,
while `lumberCap` correctly used the bottleneck tier. Engine now
computes `bindingLumberQty = max(qty across tiers)` and uses it as
the ranking divisor; `lumberCost` (sum) stays for display. Single-
tier recipes are unaffected (max == sum); multi-tier recipes now
rank by their actual binding constraint. New regression test in
test_mogul.lua covers a 5-Sturdy + 5-Polished recipe vs a 6-Sturdy
recipe scenario where the new ranking flips the plan to the more
profitable choice.
* Mogul tab: account-view fix. Toggling between Active char and
Account didn't change the candidate set because Refresh filtered to
`knownByActive` regardless of view. Account view now correctly
expands the plan to include alt-only recipes with the bestAlt tag
visible in the Crafter column; owned mats and prices stay
active-char-scoped (we can't see alt bags). Spec section 6 clarifies
this is the intended scope.
* Mogul: defensive cascade cleanup. Per code review of the new module,
removed multi-field-or fallbacks where the producer is now strict
(`reagent.qty or reagent.amount or 1` style). These were silently
papering over data bugs -- if a producer ever emits the wrong field,
downstream math now errors loudly with `attempt to perform arithmetic
on a nil value` instead of computing a wrong total with `or 1`.
* Goblin tab: lumber count for each row's required tier is now colored
green when you have enough of that lumber for at least one craft of
that recipe, dim grey otherwise. At-a-glance "can I craft this right
now?" indicator in the same column that already showed the type.
* Vendor DB: Bel'ameth vendors Mythrin'dir (NPC 216284) and Ellandrieth
(NPC 216285, sells Bel'ameth Barrel + ~7 other Bel'ameth-themed
items) were tagged "Amirdrassil" with uiMapID 2239 because Blizzard's
catalog inherits the parent zone. Pin landed on the Amirdrassil map
and the shopping-list label sent players via the wrong portal.
Updated to "Bel'ameth" with uiMapID 2369; coords are estimates
pending in-game verification. Reported by Moondaze on Discord.
* MultiHouse widget: ADDON_ACTION_BLOCKED on Frame:Show() during
tainted refresh paths. The card itself is a regular Frame but has a
SecureActionButtonTemplate child (tpBtn), and recent WoW versions
treat Frame:Show() on parents-of-secure-buttons as protected when
the call stack is tainted. Switched the card visibility from
Show()/Hide() to SetAlpha + EnableMouse (same pattern already used on
the secure tpBtn for the same reason).
* Mogul tab: new craft optimizer that produces a planned recipe mix
from your lumber stockpile. Two modes: Profit (greedy by per-lumber
profit, mix emerges from owned-mat depletion; two columns Lumber-only
and Lumber + mats) and Collection (cheapest-uncollected-first to
maximize new appearances per lumber). Header toggles for mode / view /
optimize and an editable lumber budget. Plan rows show
"K x Recipe L lumber/ea +cashg / +marging" in a WowScrollBoxList;
selecting a row reveals that recipe's mat list. Mats panel includes
Send to Auctionator (creates a Housing Decor shopping list) and the
action row has Send entire plan to crafting queue. Show all candidates
appends dimmed runner-up rows. Account view tags rows with
"Best on: <AltName>" when the active char doesn't know the recipe.
Tab is a compact icon-only button next to Goblin. Pure-function
engine in modules/HDG_Mogul.lua with 21 unit tests covering scoring,
profit greedy-with-state, and collection ordering. Static panel
(no event subscriptions); price freshness is owned by the Goblin
tab's scan.
* HDG_LumberTracker: new public accessors GetTotalLumberCount and
GetLumberIDs so other modules can read the lumber set without poking
the file-local LUMBER_TYPES table.
* HDG_PowerCrafting: new public GetAllKnownDecorRecipes(viewMode) ->
list of decor recipes the active char (viewMode = "char") or any alt
("account") knows, with knownByActive and bestAlt tags.
* Style Curator: new "Wishlist - Uncollected" virtual source in the
source dropdown. Shows the catalog slice you don't yet own and lets
you pre-file uncollected decor into your styles -- plan an Apothecary
build before you have the pieces. Filings persist; once an item lands
in your chest it's already filed under the styles you intended.
Coverage bar is unaffected (still scoped to collected decor only).
* VendorResolver: pcall-wrap UnitGUID/strsplit probes (Method 1 + 2) to
guard against the 12.0.5 secret-string taint when called from tainted
call stacks (e.g. after teleporting via MultiHouse). Pre-fix, vendor
name resolution could silently fail for the rest of the session.
* MultiHouse: defensive pcall around SetAttribute teleport bind. The
outer InCombatLockdown guard handled the in-combat case; pcall covers
the rare path where Bind is called from a tainted stack outside combat.
Card stays stable on failure; next Refresh re-binds.
* Cockpit aggregator: gate the subscriber-error print behind the debug
flag. Pre-fix, transient widget init errors during the cold-cache
retry window at login could spam chat for all users.
* Cockpit aggregator: removed C_Timer-based 1-8s retry cascade. The
HDG_COLLECTION_READY event fires when the catalog cache is warm and
is already wired to RequestRebuild -- the cascade was redundant
belt-and-suspenders that violated the no-UI-timers rule. Verified via
cold-cache smoke test (full client restart) that the cockpit
Decorator Profile populates correctly without the cascade.
* Style Curator: Coverage bar now reads "Coverage (collected): ..." to
make the bar's scope unambiguous. Pre-fix, users filing uncollected
items into styles via the new Wishlist source would see a stationary
bar with no indication why.
* Shopping List: title summary now includes per-currency totals across
the entire active list (gold + Hearthsteel + Kirin Tor tokens etc),
not just per-zone. Saves the manual tallying before a vendor run.