PvP · WS protobuf

Bork Deng — tài liệu ghép client

PvP bài đối banker: cược → chia bài → rút/sẵn sàng → so bài. Có jackpot. Client nói WebSocket binary protobuf với domain GAME.

1. Tổng quan

MụcGiá trị
GAME_IDborkdeng
Protoborkdeng_event
TagsTagBet=1 · TagDraw=2 · TagReady=3
StatePending=0 · Countdown=1 · BetTime=2 · ShowdownTime=3 · PlayTime=4
CombinationNormal=0 · StraightFlush=1 · TripleFace=2 · ThreeOfAKind=3 · Bork=4
ConnectGET /ws?access_token= trên domain GAME

ID lá bài: rank × 4 + suit. Rank 0=2 … 12=A. Suit 0=♠ 1=♣ 2=♦ 3=♥. Ví dụ 3♠ = 4. Banker ngồi cố định; player cược rồi nhận 2 lá. drawable thì rút thêm hoặc ready. Bork lật ngay (deal_bork / is_bork).

2. Demo bàn (CSS)

Bàn oval: banker đối diện 2 ghế player. Lá ngửa = đã chia; lá xanh = úp.

BANKER
K♠
9♥
P1
A♦
8♣
P2
?
?

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
0Closed — đóng bình thường, có thể reconnect
1Other device — đang chơi máy khác, hiện toast, đừng spam reconnect
2Too many — quá nhiều connection, đợi rồi thử lại
4Expired — JWT hết hạn, lấy token mới rồi connect lại
5Banned — 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.

C→S game_event.Request
data_send.data = bytes game Request
S→C game_event.Response
game_message.data = bytes game Response
Unmarshal 2 lớp: (1) lobby 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)

oneofFieldMô tả
room_config(empty)Lấy config sảnh ngay sau handshake
get_room_listbet int64List bàn theo đúng mức cược
create_roombet int64, password string, max_players int32, name stringTạo bàn. password rỗng = public
join_roomroom_id int32, password string, is_viewer boolVào bàn chỉ định. Viewer tạm để false
join_any_roombet int64, max_players uint32Matchmaking. max_players=0 = mọi size
leave_roomroom_id int32Rời bàn ngay
find_roomroom_id int32Tra cứu trước khi join (private?)
inviteroom_id, password, user_idMời user rảnh
free_users_listbet int64User rảnh cùng mức cược, không đang bàn khác
send_chat_messageroom_id, message, to[] int32, is_private_chatChat bàn; whisper khi is_private_chat + to
data_sendroom_id + oneof data bytes | auto_leaveMọ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)

oneofFieldMô tả
errorcode uint32, tag uint32Lỗi lobby. tag = request gây lỗi (bảng dưới)
game_messageroom_id, create_time, oneof msgTin từ bàn
chat_messageroom_id, user_id, message, name, vipChat broadcast
room_listbet, rooms[]Danh sách bàn
room_configxem bảng RoomType + flagUI sảnh
find_roomroom_id, is_privatetrue → hiện ô mật khẩu
free_users_listplayers[] {user_id, avatar, name, vip}Danh sách mời
inviteuser_idAck đã gửi lời mời
someone_invited_youuser_id, name, avatar, room_id, passwordPush khi bị mời — join_room với password này

RoomType (trong room_config)

FieldÝ nghĩa
bet, ccu, joinableMứ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/maxSàn/trần chip để ngồi bàn
number_of_played_games_min/maxSố 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

oneofFieldClient
databytesUnmarshal proto game Response
user_joineduser_id, name, chip, avatar, seat, room_id, state, vip, levelstate 0=view · 1=play. Seat 0..max
user_leftuser_id, disconnectdisconnect=true nếu mất WS giữa ván
start_countdownseconds, data bytesĐếm ngược; data có thể chứa payload game
start_gameplayers[] (cùng field user_joined trừ room_id), dataKhóa ghế, bắt đầu ván
reset_gameplayers[]Ván xong, bàn về pending
auto_leaveuser_id, auto_exitAck đăng ký thoát cuối ván

error.tag — gói nào gây lỗi

tagRequesttagRequest
100room_config106data_send
101create_room107send_chat_message
102join_room108find_room
103join_any_room109free_users_list
104get_room_list110invite
105auto_leave

Luồng sảnh (mọi game WS này)

  1. Mở WS GET /ws?access_token= trên domain GAME. Đọc close code nếu fail.
  2. Gửi room_config. Render mức cược; ẩn nút theo disable_* ; Play now nếu play_now.
  3. Tuỳ UI: get_room_list / find_room / create_room / join_any_room / join_room.
  4. Ngồi bàn: nhận user_joined (kể cả mình), có thể room_state trong game_message.data.
  5. Đủ người: start_countdown rồi start_game. Từ đây chỉ gửi action qua data_send.data.
  6. Chat: send_chat_messagechat_message. Mời: free_users_listinvite → đối phương nhận someone_invited_you.
  7. Hết ván: reset_game. Rời: leave_room hoặc data_send.auto_leave (out sau ván).
Reconnect giữa ván: giữ cùng JWT, join_room lại (cùng room_id). Server trả 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ấmLý do
JSON trên WSServer chỉ unmarshal protobuf binary
Hai tab cùng account102 duplicated login / handshake 1
data_send khi chưa join118 not in room / 103 not found
create_room bet lạ115 bet not found
Lỗi lobby: 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 borkdeng_event)

Marshal message dưới thành bytes, gửi trong data_send.data.

oneofFieldTag / ghi chú
betamount int64TagBet=1. Chỉ trong BetTime, ≤ max_bet
drawTagDraw=2. Rút 1 lá khi drawable
readyTagReady=3. Dừng rút, chờ so bài
jackpotHỏi số dư hũ
jackpot_historyLịch sử ăn hũ

Cheat (start_cheat / cheat) chỉ non-prod. Production bỏ qua.

// C→S data_send.data = borkdeng_event.Request
bet  { amount: 5000 }          // TagBet=1
draw { }                       // TagDraw=2
ready { }                      // TagReady=3
jackpot { }
jackpot_history { }

7. Gameplay S→C

Nằm trong game_message.data. Reconnect: unmarshal room_state trước, rồi sync UI.

oneofField chínhKhi nào
room_statestate, countdown, bet, players[], cards, max_bet, banker_cards, jackpot_amountJoin / reconnect
start_bettime, end_atMở cửa cược
betuser_id, seat, amount, total_bet, user_moneyAi đó cược — cập nhật chip
dealcards[], combination, drawable, time, end_at, is_borkChia bài tay mình
deal_borkcards[], user_id, seatNgười khác bork, lật bài họ
drawuser_id, seat, card, combination, drawableAi đó rút thêm
readyuser_id, is_bork, cards[]Ai đó sẵn sàng
show_downbanker_cards, banker_combination, player_results[{cards,combination,win_amount,user_money,user_id,seat,win_type,multiplier,is_jackpot,jackpot_amount,total_bet}], banker_win_amount, jackpot_amountKết quả. win_type: 0 hòa · 1 thắng · −1 thua
jackpot / jackpot_historyamount · jackpots[{user_id,name,amount,bet,time,avatar}]UI hũ
errorcode, tag, msg, show_typeshow_type 0 ẩn · 1 toast · 2 popup

8. Luồng ghép

  1. WS GET /ws?access_token=. Gửi room_config rồi join_any_room / create_room / join_room.
  2. Nhận user_joined, start_countdown, rồi start_game.
  3. start_bet → gửi bet{amount}. Đợi echo bet + user_money.
  4. deal: render cards. Nếu is_bork lật luôn. Nếu drawable cho nút rút / sẵn sàng tới end_at.
  5. draw hoặc ready. Người khác: animate theo seat.
  6. show_down: so với banker, cộng win_amount / jackpot_amount từ player_results.
  7. Rời: leave_room hoặc data_send.auto_leave.

9. Error codes

codeNguồnÝ nghĩa
0 / 1 / 2 / 4 / 5Handshakeclosed · other device · too many · expired · banned
100LobbyMissing payload
102LobbyDuplicated login
103LobbyRoom not found
108LobbyBad password
113LobbyRoom full
114LobbyĐang ở phòng khác
115LobbyBet không tồn tại
120LobbyKhông đủ tiền
1 WrongStateGame · tag 1/2/3Sai phase (cược lúc PlayTime, rút lúc BetTime…)
2 NotTurnGameKhông phải lượt / không được rút
3 AlreadyReadyGame · TagReadyĐã ready rồi

10. Checklist client