事件與資料模型
事件信封
json
{
"v": 1,
"type": "round.open",
"table": "B001",
"seq": 1532,
"prev": 1531,
"ts": "2026-09-24T03:00:30.000Z",
"game": "baccarat",
"shoe": "260924-03",
"round": 12,
"roundKey": "B001-260924-03-12",
"data": {}
}| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
v | int | 是 | 協定主版本,目前為 1;更大的版本回 UNSUPPORTED_VERSION |
type | string | 是 | 事件類型(見下表);本平台還不認得的類型會 ack 後忽略 |
table | string | 是 | 來源桌號,[A-Za-z0-9_.:-]{1,64} |
seq | int | 是 | 串流內嚴格遞增,≥ 1,可以不連號 |
prev | int | 是 | 同串流上一筆事件的 seq;第一筆為 0;必須小於 seq |
ts | string | 是 | 來源端事件時間,UTC ISO-8601 含毫秒(2026-09-24T03:00:30.000Z),且必須是存在的日期。來源主機必須以 NTP 校時 |
game | string | 已知類型必填 | baccarat、dragontiger 或 niuniu |
shoe | string | 靴、局事件必填 | 來源靴號,[A-Za-z0-9_.:-]{1,64};同一張桌內永久不重複(建議含日期)。牛牛沒有靴,這裡是場次(見牛牛) |
round | int | 局事件必填 | 本靴(牛牛為本場次)第幾局,1–100000 |
roundKey | string | 局事件必填 | 同一張桌內永久唯一,[A-Za-z0-9_.:-]{1,128};同一局的修正與作廢沿用 |
data | object | 是 | 依類型而定 |
- 未知的欄位一律忽略;新增欄位屬於相容變更,不升主版本。
- 「靴事件」:
shoe.start、shoe.end;「局事件」:round.open、round.close、card、reveal、round.result、round.correct、round.cancel(局事件也需要shoe)。
事件目錄
type | 時機 | data |
|---|---|---|
table.info | 連線後每桌送一次;內容變更時再送 | {name, game, decks?, dealer?, video?[], capabilities: {cardByCard, countdown, snapshot}} |
table.status | 狀態改變 | {status: "open"|"paused"|"maintenance"|"closed", reason?} |
table.snapshot | 無法重送時,或重連後主動對齊 | {status, phase: "idle"|"betting"|"closed"|"result", shoe?, round?, roundKey?, closesAt?, history: [{round, result}], gap} |
shoe.start | 新靴開始 | {decks?} |
shoe.end | 靴結束(選用) | {rounds} |
round.open | 開放下注 | {closesAt?, betSeconds?, lastInShoe?, dealer?} |
round.close | 停止下注 | {} |
card | 發出一張牌(選用,需 cardByCard 能力) | {pos, card, faceDown?} |
reveal | 牛牛逐家開牌(選用) | {hands: ["P1"]} |
round.result | 開牌結果(第一版) | {rev: 1, complete, result} |
round.correct | 修正已發布的結果 | {rev: n+1, complete, result, reason} |
round.cancel | 本局作廢 | {reason: "misdeal"|"dealer_error"|"device_error"|"table_closed"|"other", note?} |
dealer.change | 換荷官 | {dealer: {id, name, photoUrl?}} |
本平台的處理:
type | 處理 |
|---|---|
table.info | 更新桌檯目錄;未綁定的來源桌列為「已發現、未綁定」 |
table.status | 非 open 時立即停止收注 |
table.snapshot | 以快照重建狀態與本靴路單 |
shoe.start | 清空路單、通知玩家換靴 |
round.open | 開局並計算停止下注時間(見時間與下注時窗);lastInShoe: true 讓遊戲提示「本局後換靴」 |
round.close | 立即停止下注 |
card | 若仍在下注中立即停止下注;推播開牌動畫。牛牛帶 faceDown: true 的牌不公開牌面,只通知玩家「發了一張到這個牌位」 |
reveal | 公開這幾家暗發的牌(前台逐家翻牌);只用於牛牛 |
round.result | 驗證後結算 |
round.correct | 依來源信任等級與護欄自動重算,或維持原結果並列為爭議局(見信任等級) |
round.cancel | 結算前:全額退款;結算後:規則同 round.correct |
dealer.change | 顯示在遊戲畫面 |
欄位限制:name 1–128 字元;decks 1–16;betSeconds 1–600;dealer.id 1–64 字元、dealer.name 1–128 字元、dealer.photoUrl 必須是 https://;video 最多 8 筆,每筆 {protocol: "webrtc"|"flv"|"hls"|"agora"|"whep", url?, quality?: "sd"|"hd", auth: "none"|"token"|"referer"};reason、note 最多 500 字元;history 最多 200 筆;closesAt 為含毫秒的 UTC 時間;faceDown 為布林值;reveal 的 hands 為 1–4 個不重複的 B、P1、P2、P3。
補充規則:
- 同一個
roundKey在下注中再送一次round.open,視為更新倒數(例如荷官重設計時);停止下注後才送達就忽略。 - 沒有
round.open就直接收到結果(例如來源中途接上)時,只更新路單,該局不接受下注。 - 不能以第二個
round.result修改結果:必須用round.correct並遞增rev(round.result的rev固定為 1,round.correct的rev≥ 2,而且必須有reason)。同一個rev送出不同的結果時,本平台維持原結果並記錄為衝突。
遊戲資料模型
牌面編碼
<點數><花色>:點數 A 2 3 4 5 6 7 8 9 10 J Q K,花色 S 黑桃、H 紅心、D 方塊、C 梅花。例如 AS、10H、QD。
百家樂 result
json
{
"cards": { "P1": "2C", "B1": "4H", "P2": "3D", "B2": "2S", "P3": "10S" },
"player": 5,
"banker": 6,
"winner": "B",
"playerPair": false,
"bankerPair": false
}- 發牌位置
P1 B1 P2 B2 P3 B3,未發的牌省略。 player、banker為點數 0–9;winner為P、B、T(和)。complete: true時必須有完整牌面(至少P1 B1 P2 B2)。本平台會重算點數、輸贏、對子,並檢查補牌規則,不一致時回RESULT_INCONSISTENT,再依信任等級處理。complete: false時可以只給player、banker、winner、playerPair、bankerPair,選填cardCount(兩家合計張數 4–6)。- 上例是莊 6 點勝:閒 2+3=5 補 10 仍為 5;莊 4+2=6,閒第三張為 0,莊不補。
龍虎 result
json
{ "cards": { "D": "KH", "T": "9S" }, "winner": "D" }winner:D龍、T虎、TIE和。- 點數由牌面決定:A=1 … K=13(A 最小),不比花色;點數相同且花色相同為同花和。
complete: false時可以只給winner;這種情況下同花和與大小單雙(看各方的牌)無法判定,這些注會退款。先前已送過的card事件仍會用來判定。card事件的位置為D、T。
牛牛 result
json
{
"cards": {
"F": "7H",
"B-1": "KS", "B-2": "QD", "B-3": "10C", "B-4": "3S", "B-5": "5H",
"P1-1": "4C", "P1-2": "6D", "P1-3": "JS", "P1-4": "9C", "P1-5": "KH",
"P2-1": "2D", "P2-2": "8S", "P2-3": "QC", "P2-4": "AH", "P2-5": "2C",
"P3-1": "7D", "P3-2": "3H", "P3-3": "KD", "P3-4": "5C", "P3-5": "5D"
},
"hands": { "B": 8, "P1": 9, "P2": 3, "P3": 10 },
"winners": { "P1": "P", "P2": "B", "P3": "P" }
}- 牌位:頭牌
F;莊B-1~B-5;閒一P1-1~P1-5,閒二P2-1~P2-5,閒三P3-1~P3-5(-n是發到那一家的第幾張)。 hands:各家牌型代碼,0無牛、1–9牛幾、10牛牛、11五花牛、12炸彈、13五小牛(11–13 只在開啟特殊牌型的桌使用)。winners:P1、P2、P3各自對莊,P閒贏、B莊贏(沒有和局)。牌型與比牌規則見桌檯與局結果。complete: true時必須有 21 張(頭牌+四家各 5 張),hands可以省略。complete: false時至少要有winners(平倍就能結算)。翻倍要有贏的那一手的牌型才能結算,所以請盡量附上hands,沒有時翻倍的注退款。先前已送過的card事件仍會用來判定。- 本平台一律依牌面重算牌型與輸贏,來源宣告的
hands、winners只拿來比對。檢查項目:21 張不重複(一局一副牌)、牌型與輸贏符合牌面(特殊牌型關閉的桌出現 11–13 也算不符);逐張送card時另外檢查頭牌最先發、之後第 n 張的牌位照頭牌決定的順序、同一個牌位不重發、結果的牌與已發出的牌相同。任何一項不符都視為RESULT_INCONSISTENT,依信任等級處理。 - 發牌順序:頭牌點數 A 5 9 K 從莊先發、2 6 10 從閒一、3 7 J 從閒二、4 8 Q 從閒三,之後照 莊 → 閒一 → 閒二 → 閒三 輪流,每家 5 張。上例頭牌 7♥,所以依序發到
P2-1、P3-1、B-1、P1-1、P2-2…;莊牛8,閒一牛9 贏、閒二牛3 輸、閒三牛牛 贏。 - 場次:每局一副新牌、沒有靴,以
shoe當場次(例如每 60 局或換荷官時送shoe.start換一場),round是本場次第幾局;table.info的decks建議填1。
發牌與開牌的事件(建議逐張送,table.info 的 capabilities.cardByCard 為 true):
round.open→round.close(第一張牌送達時也會立即停止下注)。- 頭牌:
card {"pos": "F", "card": "7H"}。頭牌一律是明牌,F不能帶faceDown: true。 - 20 張依頭牌決定的順序發出,面朝下的牌帶
faceDown: true:card {"pos": "P2-1", "card": "2D", "faceDown": true}。本平台收下牌面但不公開,只通知玩家「發了一張到閒二」;不帶faceDown的牌就是明牌,照常顯示。 - 逐家開牌:
reveal {"hands": ["P1"]},建議依 閒一 → 閒二 → 閒三 → 莊 各送一次(一次也可以開好幾家);本平台公開這幾家的牌。reveal只用於牛牛(其他遊戲回INVALID_EVENT),和其他局事件一樣需要shoe、round、roundKey。 round.result(complete: true,21 張)。還沒開的家,本平台會依 閒一 → 閒二 → 閒三 → 莊 補開後再公開結果。
時間與下注時窗
- 來源的
closesAt是權威的下注截止時間。本平台實際停止下注的時間取下列三者最早的一個,再提前約 1 秒(吸收玩家端延遲):closesAt加上時鐘偏移估計- 收到
round.open的時間加上桌設定的最長下注秒數 - 收到
round.close或第一張card的時間
- 來源沒有
countdown能力時,以betSeconds或桌設定的秒數計時。 - 時鐘同步:心跳帶來源時間,本平台據此估算時鐘偏移並監控延遲。停止下注的時間依賴正確的時鐘,請務必以 NTP 校時。