遊戲拍賣場與玩家市集
每個用戶端即時看到上架、出價和倒數,最後幾秒出價自動延長防狙擊,支援直接購買與成交價走勢;每筆出價由你的伺服器決定,遊戲幣和道具仍由你的遊戲管理。
拍賣場、交易所或玩家市集能讓遊戲經濟持續運轉,但只有在每個人同時看到同樣的東西時才會讓人覺得公平:有人出價的瞬間就看到新價格、每個畫面上的倒數都一樣,最後一秒也不會被人偷走。開源套件 @hibira-io/auction 在 Hibira 上提供這些功能,而每一筆出價都由你自己的伺服器決定。
玩家會得到什麼
- 拍賣品的上架、變價和下架會出現在每個打開的用戶端,不用重新整理。
- 倒數和伺服器時鐘一致,最後幾秒出價會延長時間,而不是被人狙擊。
- 被超過的當下就收到通知,可以直接購買,也看得到每件物品最近的成交價。

使用的功能
- 每個拍賣場一個公開或私有頻道(
auction-main),只有一種事件auction-update,帶著完整的拍賣品和版本號。 - 從你的伺服器呼叫 HTTP API(
trigger),每次變化只發布一次,不管有多少玩家在看。 - @hibira-io/auction:伺服器端負責檢查出價、延長最後時刻的拍賣並結標;用戶端保留每件拍賣品的最新版本,斷線重連後自動補齊。
步驟 1:在伺服器上建立拍賣場
道具和遊戲幣仍然由你的遊戲管理。拍賣場會請你凍結出價者的幣、在有人出更高價時退回,並在結標時轉移道具和幣:
import Pusher from 'pusher';
import { createAuctionHouse } from '@hibira-io/auction/server';
const hibira = new Pusher({ appId, key, secret, host: 'ws.hibira.io', useTLS: true });
const house = createAuctionHouse({
pusher: hibira,
name: 'main',
extendWithin: 30000, // a bid in the last 30 s adds time
reserve: async ({ userId, amount }) => {
if (!(await wallet.hold(userId, amount))) throw new Error('not enough gold');
},
release: async ({ userId, amount }) => wallet.unhold(userId, amount),
settle: async ({ listing }) => game.deliver(listing), // idempotent by listing.id
});
house.start(); // closes and settles ended auctions步驟 2:四個 API
玩家身分要從你自己的登入狀態取得,不要從請求內容讀取:
app.get('/auction', async (req, res) => res.json(await house.snapshot()));
app.post('/auction/:id/bid', requireLogin, async (req, res) => {
try {
res.json(await house.bid({ listingId: req.params.id, bidderId: req.user.id, bidder: { name: req.user.name }, amount: req.body.amount }));
} catch (err) {
res.status(err.status ?? 500).json({ error: err.code });
}
});
// The same for house.buyout() and house.list()步驟 3:在遊戲中顯示拍賣場
import { AuctionHouse } from '@hibira-io/auction';
const house = AuctionHouse.open(pusher, 'main', {
load: () => fetch('/auction').then((r) => r.json()),
});
house.on('change', ({ listings }) => render(listings));
setInterval(() => listings.forEach((l) => showTimeLeft(l, house.timeLeft(l))), 250);
bidButton.onclick = () => fetch(`/auction/${l.id}/bid`, { method: 'POST', body: JSON.stringify({ amount: l.minBid }) });house.prices(type) 會回傳某種物品最近的成交價,可以畫成價格走勢圖。斷線重連後拍賣場會重新載入快照,不會漏掉任何變化。
試試看
拍賣場範例 是一個完整的 Next.js 遊戲市集:NPC 商人、背包、直接購買、被超過通知和成交價,支援七種語言。在兩個視窗打開,在其中一個出價看看。
小提醒
- 每次變化算一則訊息,不管有多少玩家在看。大型拍賣場可以按分類或地區拆開(
name: 'weapons'),讓每個用戶端只載入它要顯示的部分。 - 有多台遊戲伺服器時,給拍賣場一個存在你資料庫上的
store;寫入是比較後再存,兩台伺服器不可能同時接受同一筆出價。 - 它轉移的是遊戲自己的幣和道具,不處理真錢。
- Unity、Godot 或任何 Pusher SDK 的用戶端都能訂閱同一個
auction-main頻道並呼叫同樣的 API。房間和配對請看多人遊戲房間與大廳。