Homebrew Vendors by PMZFX gives ordinary World of Warcraft 3.3.5a merchants a deterministic 28-day rotation of useful, themed, level-appropriate stock. It is a standard AzerothCore server module and data generator; no client addon, modified executable, DBC, or MPQ patch is required.
Permanent vendor inventory is never replaced. Featured items use
AzerothCore's native game_event_npc_vendor system, so the normal merchant UI,
item prices, stock counts, purchase rules, and restocking behavior remain in
control.
- Classifies physical cash vendors by title and, when safe, permanent stock.
- Adds useful common-through-epic stock appropriate to each merchant's role and level band.
- Covers weapons, armor, professions, bags, food and drink, fishing, ammunition, reagents, poisons, general goods, and other ordinary shops.
- Excludes reputation, PvP, holiday, currency, scripted, quest, boss-loot, deprecated, restricted, suspicious, and extreme-price content.
- Uses native
item_template.BuyPrice; the displayed price is the charged price. - Keeps common stock unlimited, gives uncommons a small restocking supply, and makes rare/epic appearances genuinely scarce.
- Optionally sorts covered merchant stock by quality without changing price, quantity, restocking, or the relative order of equal-quality items.
- With mod-playerbots, prevents bots from consuming limited featured rare/epic pairs while still allowing common/uncommon purchases.
- Produces an audit covering every included and excluded physical cash vendor.
The included reference schedule contains 1,403 covered vendors, 28 recurring events, 137,669 event-vendor rows, and 7,786 distinct featured items. A typical day exposes roughly 5,000 featured listings worldwide.
| Server stack | Support | Behavior |
|---|---|---|
| Current AzerothCore | Yes | Full rotation and quality ordering; Playerbot protection is inactive. |
| AzerothCore + mod-playerbots | Yes | Full rotation plus protection for limited rare/epic featured stock. |
| Fresh world database | Yes | Use the reference snapshot after the collision preflight. |
| Customized or substantially newer world database | Yes | Regenerate from that database so physical vendor GUIDs and available items match. |
The same source tree builds for both server stacks. Playerbots is detected at compile time and is not a required dependency.
With the default configuration, Homebrew Vendors owns only:
- game events
200through227; - rows in
game_event_npc_vendorfor those events; and - the
mod_homebrew_vendor_profileaudit/runtime table.
It does not edit npc_vendor, item_template, creature templates, creature
spawns, player inventories, currencies, or client files.
Event IDs are globally shared. The installer performs a read-only preflight
that verifies every covered vendor GUID/entry pair and featured item, then
refuses to overwrite non-Homebrew events or vendor rows. A snapshot mismatch
means the customized generation path is required. If your server already uses
200–227, select another contiguous 28-ID range within 1–255, regenerate
the schedule with that range, and set the same range in
HomebrewVendors.conf.
From the root of your AzerothCore source tree:
cd modules
git clone https://github.com/PMZFX/mod-homebrew-vendors.git
cd ..Reconfigure, rebuild, and install AzerothCore so it discovers the module. For a typical existing build directory:
cmake -S . -B build
cmake --build build --parallel
cmake --install buildBuild layouts vary. Follow the official AzerothCore module installation guide when using Docker, the dashboard, or a custom build/install directory.
Confirm HomebrewVendors.conf.dist was installed into your module
configuration directory. Copy it to HomebrewVendors.conf if your setup does
not create active module configurations automatically.
Do not restart worldserver until the selected data path below is complete. The
installer deliberately does not guess your service manager or container
layout. Its preflight may run while the realm is online, but stop worldserver
before using --apply.
The reference snapshot is the simplest path for a fresh database from the supported AzerothCore family. Take a world-database backup first.
Run the collision preflight. This command is read-only without --apply:
cd modules/mod-homebrew-vendors
./scripts/install-vendor-data.sh --database acore_worldIf it reports complete vendor/item matches and a free range, apply the reference schedule:
./scripts/install-vendor-data.sh --database acore_world --applyKeep worldserver stopped during the apply operation.
For authenticated MySQL installations, use a protected option file instead of placing a password in shell history:
[client]
user=acore
password=replace-me
host=127.0.0.1chmod 600 /path/to/mysql-client.cnf
./scripts/install-vendor-data.sh \
--database acore_world \
--mysql-defaults-extra-file /path/to/mysql-client.cnf
./scripts/install-vendor-data.sh \
--database acore_world \
--mysql-defaults-extra-file /path/to/mysql-client.cnf \
--applyIf your world database has custom creatures, custom items, changed vendor spawns, or a materially different upstream revision, use the customized path instead.
The generator reads public world data only and emits SQL plus a complete TSV audit. It does not modify the database.
Choose a start date and generate into a private working directory:
mkdir -p build/vendor-data
python3 tools/generate-vendor-rotation.py \
--database acore_world \
--start-date 2026-08-10 \
--output build/vendor-data/vendor-rotation.sql \
--audit-output build/vendor-data/vendor-coverage-audit.tsv
python3 tools/generate-vendor-rotation.py \
--first-event 200 \
--days 28 \
--rollback \
--output build/vendor-data/rollback.sqlPass --mysql-defaults-extra-file /path/to/mysql-client.cnf to the first
command when credentials are required. --mysql-command 'sudo mysql' is also
supported; the command is split into arguments and is never executed through a
shell.
Review the generator summary and audit, then preflight and apply exactly that SQL:
./scripts/install-vendor-data.sh \
--database acore_world \
--sql build/vendor-data/vendor-rotation.sql
./scripts/install-vendor-data.sh \
--database acore_world \
--sql build/vendor-data/vendor-rotation.sql \
--applyStop worldserver after the read-only preflight and before the --apply
command.
For a different event range, use the same values everywhere:
python3 tools/generate-vendor-rotation.py \
--database acore_world \
--first-event 160 \
--days 28 \
--start-date 2026-08-10 \
--output build/vendor-data/vendor-rotation.sql \
--audit-output build/vendor-data/vendor-coverage-audit.tsv
./scripts/install-vendor-data.sh \
--database acore_world \
--sql build/vendor-data/vendor-rotation.sql \
--first-event 160 \
--days 28Then set:
HomebrewVendors.FirstEvent = 160
HomebrewVendors.LastEvent = 187Generate rollback SQL with the same --first-event and --days values.
Default configuration:
HomebrewVendors.Enable = 1
HomebrewVendors.QualityFirst = 1
HomebrewVendors.ProtectPlayerbots = 1
HomebrewVendors.ProtectedMinimumQuality = 3
HomebrewVendors.FirstEvent = 200
HomebrewVendors.LastEvent = 227Restart worldserver after the module and data are installed. Startup logs
should contain mod-homebrew-vendors loaded followed by profile, sorting, and
protected-stock counts.
No extra step is required. ProtectPlayerbots and
ProtectedMinimumQuality are harmless because the module detects that
Playerbots is unavailable. Humans receive the full native vendor experience.
Build this module in the same source tree as mod-playerbots. Bots may buy
featured common and uncommon stock. When protection is enabled, attempted bot
purchases of limited featured items at or above
ProtectedMinimumQuality are rejected before the native purchase completes.
Human purchases are unaffected.
Database checks for the default range:
SELECT COUNT(*) FROM mod_homebrew_vendor_profile;
SELECT COUNT(*) FROM game_event
WHERE eventEntry BETWEEN 200 AND 227
AND description LIKE 'Homebrew vendor rotation day %';
SELECT COUNT(*) FROM game_event_npc_vendor
WHERE eventEntry BETWEEN 200 AND 227;For the reference snapshot the expected results are 1403, 28, and
137669.
In game, visit an ordinary weapon merchant, armor merchant, and profession supplier. Confirm that:
- permanent inventory is still present;
- featured stock matches the merchant and local level range;
- prices and limited quantities behave like native vendor stock;
- better-quality items appear first when
QualityFirst = 1; and - the featured selection changes after the next daily event rollover.
Regenerating is idempotent for the selected owned range. The generated SQL replaces only its event rows and recreates the module-owned profile table.
Recommended upgrade sequence:
- update the module source;
- rebuild and install AzerothCore;
- back up the world database;
- regenerate against the updated world database;
- run the installer preflight, then apply;
- restart and repeat the verification checks.
The audit is part of the generated result. Do not hand-edit schedule SQL; change the generator rules and regenerate both artifacts together.
Stop worldserver and apply the rollback matching your selected event range:
mysql acore_world < data/reference/rollback.sqlFor a custom range, use the rollback generated alongside that schedule. Then
restart worldserver. Rollback removes only the selected event-vendor rows,
matching Homebrew event definitions, and mod_homebrew_vendor_profile.
Permanent vendor stock needs no restoration because it was never changed.
The compiled module may remain installed; with no profiles or featured rows it
has no rotation data to manage. Set HomebrewVendors.Enable = 0 and rebuild if
you also want its hooks unregistered.
The preflight reports occupied event IDs
Do not bypass it. Choose another contiguous range, regenerate, and update the configuration to match.
The preflight reports missing vendor profiles or featured items
The reference snapshot does not exactly match that world database. Do not apply it; use the customized generation path.
A customized server shows missing or incorrect vendors
Do not use the reference snapshot. Generate from that server's current world database so creature GUIDs and candidate items match.
No featured stock appears
- Confirm one event in the configured range is active.
- Confirm
HomebrewVendors.Enable = 1. - Confirm the module loaded and the profile table is populated.
- Confirm the configuration range matches the installed SQL.
Vendor ordering is unexpected
Set HomebrewVendors.QualityFirst = 0 to use AzerothCore's normal ordering.
This changes presentation only; the featured schedule still works.
The generator rejects a vendor or item
Check vendor-coverage-audit.tsv and the documented safety filters before
relaxing a rule. The generator intentionally favors false negatives over
putting restricted or suspicious content into ordinary shops.
Run lightweight validation with:
./tests/test-release.shGitHub CI also builds worldserver from clean checkouts of plain AzerothCore
and AzerothCore with mod-playerbots. Tagged releases include a deterministic
reference-data ZIP and SHA256SUMS.
Homebrew Vendors by PMZFX is licensed under GPL-2.0-or-later.