Website: Market
Step-by-step guide for web developers - show Market listings (every item for sale, a character's store) and sold listings (recent sales, price history, top sellers) on the website, with SQL, Node.js a
The Market keeps each character's store in one binary column and every sale in one table. This guide shows how to use both on a website: an all listings page, a character store page, a recent sales feed, price history and a sellers ladder.
What you can show
All listings
Every priced item on the server. Filter by currency, item, level. Sort by price or newest
Character.MarketStore
Character store
One character's priced rows
Character.MarketStore
My store (owner only)
All rows, unlisted rows and the wallet
Character.MarketStore
Recent sales
Last sales: item, seller, buyer, price, time
dbo.MarketSaleLog
Where the data lives
Store rows + wallet
Character.MarketStore, varbinary(1536). NULL = empty store
Sales
dbo.MarketSaleLog, one row per sale
Item bytes
Same 16-byte format as Character.Inventory. Use your site's existing item decoder for names, options and images
Both are created by DataServer/SQL/Migrations/0002_market.sql (schema 2).
The store column is saved together with the inventory, right after each change (deposit, withdraw, open, close, sale, collect). A price change is saved within a few seconds.
Step 1 - Read the store blob
All numbers are little-endian (least significant byte first). Total size 1471 bytes.
0
1
Version. 1 = valid. 0 or NULL column = empty store
1
8
Wallet zen, signed 64-bit
9
4
Wallet Jewel of Bless (single jewels)
13
4
Wallet Jewel of Soul
17
4
Wallet Jewel of Chaos
21
29 × 50
50 rows. Row r starts at 21 + r × 29
Row (29 bytes):
0
16
Item, 16-byte DB format. All 0xFF = empty row
16
1
Currency. 0 = in the store but not listed
17
8
Price, signed 64-bit
25
4
Listed at, Unix time in seconds (UTC). Set when the price was set
Currency codes (same in MarketSaleLog.Currency):
1
Zen
2
Jewel of Bless
3
Jewel of Soul
4
Jewel of Chaos
5
WCoinC
6
WCoinP
7
GoblinPoint
A row is for sale when the item is not empty, Currency is 1-7 and Price > 0. Jewel prices count single jewels.
Useful item bytes (offsets inside the 16-byte item):
Section
byte9 >> 4
Number
byte0 + ((byte7 & 0x80) << 1)
Level (+0..+15)
(byte1 >> 3) & 15
Excellent options
byte7 & 63 (bit mask)
Durability or stack count
byte2
Serial
bytes 3-6, big-endian
Prices and zen are bigint. Zen can be above Number.MAX_SAFE_INTEGER, so convert with .toString() for JSON.
Needs 64-bit PHP 7.1+ (P = 64-bit little-endian). Read MarketStore with PDO::SQLSRV_ENCODING_BINARY so it comes back as raw bytes.
Step 2 - All listings page
Reading 1471 bytes per character in code is fine for one store. For a page that searches every store, add this view once. It turns each priced row into one SQL row, so you can filter, sort and page in SQL.
Run it against the MuOnline database in SQL Server Management Studio. It only adds a new object (WEB_ prefix); it changes nothing the game uses.
Rows with a price of 0 or below never get saved as listed, so Currency 1-7 is enough.
All listings, newest first (page 1, 20 per page):
Filter (zen only, +9 or higher, excellent, cheapest first):
One item type (section and number as in Item.xml):
Character store page:
Listings count per currency (stats box):
Step 3 - Sold listings
dbo.MarketSaleLog has one row per sale:
Id
bigint, identity
Grows by 1 per row
Seller / Buyer
varchar(10)
Character names
ItemData
varbinary(16)
The item sold, 16-byte DB format
Price
bigint
What the buyer paid
Net
bigint
What the seller got (price minus commission)
Status
tinyint
1 sold. 0 coin sale in progress, 2 refunded, 3 stuck coin sale (GM). Only show 1
SoldAt
datetime
Time of sale, SQL Server's local clock
Add this index once for time-based pages (safe, the game does not care):
Recent sales feed (last 20):
A character's sales (the in-game Sold tab):
A character's purchases:
Price history of one item type, last 30 days (zen):
SUBSTRING is 1-based, so item byte 9 is SUBSTRING(ItemData, 10, 1).
All-time sales archive
MarketSaleLog is a rolling window: each seller keeps only the last SaleLogKeep sold rows (default 50, set in Market.xml). Older ones are deleted. Short feeds are fine; all-time totals and long price history need their own table.
Use
Query MarketSaleLog directly?
Recent sales, a character's last sales, price history of busy items this week
Yes
All-time top sellers, total trade volume, long price history
No - use the archive
Install (once)
Run it once by hand to copy what is there now:
Keep it updated
Run EXEC dbo.WEB_MarketSalesUpdate every 1-5 minutes. Running it twice copies nothing twice.
SQL Server Agent (not in Express)
New job, one step EXEC dbo.WEB_MarketSalesUpdate, schedule every 1 minute
Windows Task Scheduler
Every 1 minute: sqlcmd -S . -E -d MuOnline -Q "EXEC dbo.WEB_MarketSalesUpdate"
Website cron
Your site's scheduler runs the EXEC
Archive queries
Top sellers by zen earned:
Most sales (any currency): GROUP BY Seller ORDER BY COUNT(*) DESC.
Trade volume per day:
Price history: the price history query works on WEB_MarketSales too. Drop the Status = 1 line.
Season reset: TRUNCATE TABLE dbo.WEB_MarketSales.
Important Behavior
Open / closed is not stored. A listed row on the website may belong to a closed store. Do not show "buy" buttons: buying only happens in game.
Search is per GameServer in game. The website shows every character's store from the database, so it can list items a player on another server cannot reach with the search window.
Rows above
MaxRows. If you loweredMaxRowsinMarket.xml, rows above it keep their price in the database but are not sold in game. AddAND [Row] < <MaxRows>to listing queries.Rule changes. If an item stops being allowed (ItemMove,
TradeItemBlock*, binding), the row becomes unlisted the next time the owner opens the store. Until then it still shows as listed.Coin sales (
Currency5-7) appear inMarketSaleLogatStatus = 0first and turn to1when the item is delivered. Never count0,2or3.Character rename. Old sale rows keep the old name.
Time.
ListedAtUtcis UTC.SoldAtis the SQL Server machine's local time.
Common Issues
Related pages
Market - settings, currencies, commission,
SaleLogKeepWebsite: Inscription Tooltips - extra tooltip lines for inscribed items, keyed by the item serial
Last updated