Binh — tài liệu ghép client
Xếp 13 lá thành 3 chi (front 3 + mid 5 + back 5), ready, báo mậu binh, so chi + jackpot.
1. Tổng quan
| Mục | Giá trị |
|---|---|
| GAME_ID | binh |
| Proto | binh_event |
| Tags | TagSort=1 · TagReady=2 · TagNatural=3 |
| HandType | HighCard…StraightFlush (0–8) |
| Natural | None, ThreeFlushes, ThreeStraights, SixPairs, SameColor, Dragon, GrandDragon |
| Thứ tự cards[] | 3 lá đầu = chi trước · 5 tiếp = chi giữa · 5 cuối = chi sau |
| Connect | GET /ws?access_token= domain GAME |
ID lá bài: rank × 4 + suit. Rank 0=2 … 12=A. Suit 0=♠ 1=♣ 2=♦ 3=♥. Ví dụ 3♠ = 4. Sau khi báo natural không sort/ready nữa. Binh lủng (burned) thua cả 3 chi.
2. Demo bàn (CSS)
13 lá nhóm 3 chi — hiển thị 5–5–3 (sau / giữa / trước) đúng UI so bài.
Chi sau (5)
Chi giữa (5)
Chi trước (3)
3. Kết nối & envelope
Mọi frame WebSocket là binary protobuf — không JSON. Một user chỉ được một connection; login trùng → lobby error 102.
GET /ws?access_token=<JWT> # Host = domain GAME (không phải docs). Frame = bytes proto, không text JSON.
| Handshake close | Ý nghĩa — client phải làm |
|---|---|
0 | Closed — đóng bình thường, có thể reconnect |
1 | Other device — đang chơi máy khác, hiện toast, đừng spam reconnect |
2 | Too many — quá nhiều connection, đợi rồi thử lại |
4 | Expired — JWT hết hạn, lấy token mới rồi connect lại |
5 | Banned — tài khoản bị cấm, dừng retry |
Envelope lobby package game_event (internal/proto/game-event). Payload bàn nằm trong data_send.data (C→S) và game_message.data (S→C) — bytes của proto game.
Request/Response. (2) Nếu oneof là data thì unmarshal tiếp proto game. room_id trên envelope phải khớp bàn đang ngồi. Cheat chỉ non-prod.4. Lobby C→S (game_event.Request)
| oneof | Field | Mô tả |
|---|---|---|
room_config | (empty) | Lấy config sảnh ngay sau handshake |
get_room_list | bet int64 | List bàn theo đúng mức cược |
create_room | bet int64, password string, max_players int32, name string | Tạo bàn. password rỗng = public |
join_room | room_id int32, password string, is_viewer bool | Vào bàn chỉ định. Viewer tạm để false |
join_any_room | bet int64, max_players uint32 | Matchmaking. max_players=0 = mọi size |
leave_room | room_id int32 | Rời bàn ngay |
find_room | room_id int32 | Tra cứu trước khi join (private?) |
invite | room_id, password, user_id | Mời user rảnh |
free_users_list | bet int64 | User rảnh cùng mức cược, không đang bàn khác |
send_chat_message | room_id, message, to[] int32, is_private_chat | Chat bàn; whisper khi is_private_chat + to |
data_send | room_id + oneof data bytes | auto_leave | Mọi action gameplay. auto_leave = đăng ký out cuối ván |
create_room { bet: 1000, password: "", max_players: 4, name: "ban-1" }
join_room { room_id: 42, password: "", is_viewer: false }
data_send { room_id: 42, data: <marshal(game Request)> }
data_send { room_id: 42, auto_leave: {} }
5. Lobby S→C (game_event.Response)
| oneof | Field | Mô tả |
|---|---|---|
error | code uint32, tag uint32 | Lỗi lobby. tag = request gây lỗi (bảng dưới) |
game_message | room_id, create_time, oneof msg | Tin từ bàn |
chat_message | room_id, user_id, message, name, vip | Chat broadcast |
room_list | bet, rooms[] | Danh sách bàn |
room_config | xem bảng RoomType + flag | UI sảnh |
find_room | room_id, is_private | true → hiện ô mật khẩu |
free_users_list | players[] {user_id, avatar, name, vip} | Danh sách mời |
invite | user_id | Ack đã gửi lời mời |
someone_invited_you | user_id, name, avatar, room_id, password | Push khi bị mời — join_room với password này |
RoomType (trong room_config)
| Field | Ý nghĩa |
|---|---|
bet, ccu, joinable | Mức cược, số người online, có vào được không |
vip_min/max, level_min/max | Điều kiện VIP / level |
chip_amount_min/max | Sàn/trần chip để ngồi bàn |
number_of_played_games_min/max | Số ván đã chơi |
Flag room_config: disable_create · disable_find · disable_get_list · disable_select (chỉ Play now) · play_now · best_choice (bet gợi ý). Room: room_id, is_private, bet, create_time, metadata map, name. metadata thường có max_players, number_of_players, label.
game_message.msg
| oneof | Field | Client |
|---|---|---|
data | bytes | Unmarshal proto game Response |
user_joined | user_id, name, chip, avatar, seat, room_id, state, vip, level | state 0=view · 1=play. Seat 0..max |
user_left | user_id, disconnect | disconnect=true nếu mất WS giữa ván |
start_countdown | seconds, data bytes | Đếm ngược; data có thể chứa payload game |
start_game | players[] (cùng field user_joined trừ room_id), data | Khóa ghế, bắt đầu ván |
reset_game | players[] | Ván xong, bàn về pending |
auto_leave | user_id, auto_exit | Ack đăng ký thoát cuối ván |
error.tag — gói nào gây lỗi
| tag | Request | tag | Request |
|---|---|---|---|
| 100 | room_config | 106 | data_send |
| 101 | create_room | 107 | send_chat_message |
| 102 | join_room | 108 | find_room |
| 103 | join_any_room | 109 | free_users_list |
| 104 | get_room_list | 110 | invite |
| 105 | auto_leave |
Luồng sảnh (mọi game WS này)
- Mở WS
GET /ws?access_token=trên domain GAME. Đọc close code nếu fail. - Gửi
room_config. Render mức cược; ẩn nút theo disable_* ; Play now nếuplay_now. - Tuỳ UI:
get_room_list/find_room/create_room/join_any_room/join_room. - Ngồi bàn: nhận
user_joined(kể cả mình), có thểroom_statetronggame_message.data. - Đủ người:
start_countdownrồistart_game. Từ đây chỉ gửi action quadata_send.data. - Chat:
send_chat_message→chat_message. Mời:free_users_list→invite→ đối phương nhậnsomeone_invited_you. - Hết ván:
reset_game. Rời:leave_roomhoặcdata_send.auto_leave(out sau ván).
game_message.data = room_state proto game. Đừng tạo phòng mới. Một user một socket — socket cũ bị đóng với handshake 1 hoặc lobby 102.| Cấm | Lý do |
|---|---|
| JSON trên WS | Server chỉ unmarshal protobuf binary |
| Hai tab cùng account | 102 duplicated login / handshake 1 |
| data_send khi chưa join | 118 not in room / 103 not found |
| create_room bet lạ | 115 bet not found |
100 missing payload · 102 duplicated login · 103 room not found · 108 bad password · 113 room full · 114 in other room · 115 bet not found · 120 not enough money. Bảng đầy đủ mục Errors.6. Gameplay C→S (proto binh_event)
Marshal message dưới thành bytes, gửi trong data_send.data.
| oneof | Field | Tag |
|---|---|---|
sort | cards[] đúng 13 id, thứ tự 3+5+5 | TagSort=1 |
ready | ready bool — true khóa, false xếp lại | TagReady=2 |
report_natural | cards[], natural | TagNatural=3 — chỉ khi allow_report_natural / is_natural |
jackpot_history | — | Lịch sử hũ |
sort { cards: [/* 3 front + 5 mid + 5 back */] } // TagSort=1
ready { ready: true } // TagReady=2
report_natural { cards: [...], natural: Dragon } // TagNatural=3
7. Gameplay S→C
Nằm trong game_message.data. Reconnect: unmarshal room_state trước, rồi sync UI.
| oneof | Field | Khi nào |
|---|---|---|
deal | cards[13], is_natural, natural | Chia bài. is_natural → hiện nút báo binh |
player_turn | seconds, state_end_at | Bắt đầu giờ xếp bài |
sort | cards[] echo | Ack sort của mình |
ready | user_id, ready | Ai đó khóa/mở chi |
report_natural | natural | Ack báo binh |
pre_showdown | — | Khóa UI, chuẩn bị so |
finish | players[{user_id,amount,user_money,cards,total_point,hands[],hand_points,burned,hand_bonuses,scooped_players,is_scooping_all,scooping_score,natural,is_jackpot,jackpot_amount,…}], jackpot | So 3 chi. Anim: natural → từng chi → sập làng → tiền |
room_state | cards, natural, allow_report_natural, bonus_config, players[].ready | Reconnect giữa xếp bài |
8. Luồng ghép
- Join bàn,
deal13 lá. - Kéo thả 3 chi, gửi
sort(debounce).ready{true}khi xong; có thể unready. - Nếu
is_natural:report_natural— sau đó không sort nữa. pre_showdownrồifinish: (1) mậu binh (2) từng chi + bonus (3) sập / sập làng (4) jackpot.
9. Error codes
| code | Nguồn | Ý nghĩa |
|---|---|---|
| 0 / 1 / 2 / 4 / 5 | Handshake | closed · other device · too many · expired · banned |
| 100 · 102 · 103 · 108 · 113 · 114 · 115 · 120 | Lobby | missing payload · duplicated login · room not found · bad password · room full · in other room · bet not found · not enough money |
| 1 WrongState | tag 1/2/3 | Không trong Playing |
| 2 InvalidCard | TagSort / TagNatural | Không đủ 13 / lá không thuộc tay |
| 3 InvalidNatural | TagNatural | Loại mậu binh không khớp bài |
10. Checklist client
- Gửi đúng thứ tự 3+5+5; UI có thể đảo 5-5-3 khi vẽ.
- Chi sau ≥ chi giữa ≥ chi trước — server phạt burned nếu lủng.
- Nguồn chip:
finish.players[].user_money+jackpot_amount. - bonus_config từ room_state để tooltip hệ số.