From df1d308fa25222fe2473e22940271ea480719cc9 Mon Sep 17 00:00:00 2001 From: Tecc Date: Thu, 2 Jul 2026 12:50:59 +0000 Subject: [PATCH] docs: expand README to cover all Merkerhood customizations Document the full fork surface, not just the recent pricing work: dynamic market pricing (auction-history moving averages, outlier filtering, recency weighting, reset threshold), ChromieCraft base prices, reagent-cost derivation, per-item count override, reasonable stack sizes, multiple seller characters, per-faction bidding, market population control, item filtering, the performance rewrites, and the data tables + tooling. --- README.md | 98 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 761ff47..f332508 100644 --- a/README.md +++ b/README.md @@ -66,28 +66,47 @@ The sum of the percentage for these categories must always be 100, or otherwise ## Merkerhood customizations -This fork adds four behaviours on top of the stock buyer/seller bot, so the auction -house reads like a real ChromieCraft economy instead of quality-multiplier defaults. -Design detail lives in `docs/superpowers/specs/`; the Python tooling that generates the -data tables is in `tools/price-backfill/` (stdlib only, no dependencies). +This branch is a heavily modified fork. On top of the stock buyer/seller bot it adds a +dynamic market-price engine, real ChromieCraft base prices, lifelike listing quantities and +stack sizes, multi-character sellers, per-faction bidding, item filtering, and a set of +performance rewrites for large realms. The goal is an auction house that reads like a real +economy rather than quality-multiplier defaults. + +Design detail for the recent pricing/stacks work is in `docs/superpowers/specs/`; the Python +tooling that generates the price and count tables is in `tools/price-backfill/` (stdlib only, +no dependencies). + +### Dynamic market pricing + +When `AuctionHouseBot.UseMarketPriceForSeller` is on, the seller prices items from what +players are actually paying instead of a static value. Sales are recorded in +`mod_auctionhousebot_auction_history`, and the bot computes a moving average per item: + +- `UseAuctionCount` / `AuctionCount` averages over the last N auctions; otherwise `Days` + averages over a time window. +- `FilterOutliers` drops price outliers from the sample; `WeightRecent` weights newer + auctions more. +- `MarketResetThreshold` is how many auctions of an item must accumulate before the plain + computed price is adopted; below it the price is nudged by a heuristic, which smooths + oscillations. Old history is pruned automatically. ### ChromieCraft base prices -`mod_auctionhousebot_priceOverride` (`item`, `avgPrice`, `minPrice`) is the base-price -source. The bot prioritises listing items that have an override and falls back to the -fixed defaults otherwise. The table is generated by `tools/price-backfill/backfill.py` -from ChromieCraft's live auction data, scraped from wowauctions.net's JSON endpoint keyed -by item id. Price changes that swing far from the previous overrides land in a -`reports/deviations-*.csv` worklist for manual review. See the tool README to regenerate. +`mod_auctionhousebot_priceOverride` (`item`, `avgPrice`, `minPrice`) is the base "plain" +price: it is used directly when market pricing is off, and is the baseline the market engine +converges toward once enough auctions accumulate (see `MarketResetThreshold`). The bot +prioritises listing items that have an override and falls back to fixed defaults otherwise. The table is generated by +`tools/price-backfill/backfill.py` from ChromieCraft's live auction data, scraped from +wowauctions.net's JSON endpoint keyed by item id. Price changes that swing far from the +previous overrides land in a `reports/deviations-*.csv` worklist for manual review. ### Reagent-cost derivation -Craftable items that never traded on ChromieCraft (so have no market price) get a price -derived from their reagents. `tools/price-backfill/derive.py` parses the recipe graph from -`Spell.dbc` (committed as `recipes.json`), prices each item recursively from its reagents' -ChromieCraft prices, falls back to vendor sell price where a reagent is unpriced, and -applies a crafting margin. Derived rows are merged (add-only) into the same priceOverride -table. +Craftable items that never traded on ChromieCraft get a price derived from their reagents. +`tools/price-backfill/derive.py` parses the recipe graph from `Spell.dbc` (committed as +`recipes.json`), prices each item recursively from its reagents' ChromieCraft prices, falls +back to vendor sell price where a reagent is unpriced, and applies a crafting margin. Derived +rows are merged (add-only) into the same priceOverride table. ### Per-item listing count override @@ -105,8 +124,51 @@ Glyphs, recipes, quest items, containers, keys, and cut gems (socketable, `GemProperties != 0`) always list as quantity 1, regardless of the item's stackable value. Other stackables use weighted human breakpoints `{1, 5, 10, 20, full}` clamped to the per-quality maximum, never a random 7 or 13. This is the default when -`AuctionHouseBot.DivisibleStacks = 0`; setting it to `1` keeps the older divisible-multiples -mode. +`AuctionHouseBot.DivisibleStacks = 0`; `1` keeps the older divisible-multiples mode. +`AuctionHouseBot.MaxStackSize` caps the largest stack. + +### Multiple seller characters + +`AuctionHouseBot.GUIDs` is a comma-separated list of character GUIDs (all under +`AuctionHouseBot.Account`) that the bot lists as, instead of a single character, so listings +are spread across several names. + +### Per-faction bidding + +`AllianceBiddingInterval` / `HordeBiddingInterval` / `NeutralBiddingInterval` and the +matching `BidsPerInterval` values set how often, and how many, bids the buyer places per +faction auction house. + +### Market population control + +- `AuctionHouseBot.ConsiderOnlyBotAuctions` counts only the bot's own auctions when deciding + how full the market is, so it keeps a background of listings even when many players are + online (without it, player auctions count toward the total and the SQL max values must be + raised a lot). +- `MinItems` / `MaxItems` bound the total number of auctions; `DuplicatesCount` caps + duplicate stacks of a single item (per-item overrides can raise or lower this). + +### Item filtering + +`z_filter_disabled_and_trash.sql` builds an exclusion set (disabled, trash, and non-market +items) so the bot never lists junk. `AuctionHouseBot.DEBUG_FILTERS` traces what gets filtered. + +### Performance + +For large or busy realms the seller path was rewritten to avoid repeatedly scanning the +whole auction house: `GetItemsToSell` builds a set of item ids already listed, `getElement` +uses an in-memory item-count map instead of iterating the auction table, and item ordering is +deterministic rather than randomised. These are the `fix_slow_updates` / `fix_low_pop` +changes. + +### Data tables and tooling + +- World DB tables: `mod_auctionhousebot` (per-AH item counts, per-quality price/stack limits), + `mod_auctionhousebot_priceOverride`, `mod_auctionhousebot_countOverride`, + `mod_auctionhousebot_auction_history`. Cleanup runs from `mod_autionhousebot_cleanup.sql`. +- Module SQL auto-applies via the AzerothCore updater on server start. +- `tools/price-backfill/` regenerates the price and count tables from ChromieCraft data; see + its README for the full workflow. ## Credits