Housing Decor Guide

All 1,690 housing decorations in one addon. Browse every acquirable item, plan vendor shopping routes with built-in waypoints, queue crafting recipes with material tracking, and monitor profit margins — all with account-wide alt awareness.

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.