NON-PRODUCTION

Sicbo — tài liệu ghép client

Mini-game 3 xúc xắc. Cược cửa Big / Small. Có leaderboard, history, sessions, logs trên cùng WS. Envelope lobby game_event; payload bàn proto sicbo_event. Frame binary, không JSON.

1. Tổng quan

MụcGiá trị
ConnectGET /ws?access_token=<JWT> trên domain game
Lobbyinternal/proto/game-event · package game_event
Gameplaypackage sicbo_event trong data_send.data
SideBig=0 (tổng ≥ 11) · Small=1 (tổng < 11)
Dice3 mặt 1–6. score = tổng. UI có thể hiện even/odd từ tổng, cửa cược API chỉ Big/Small
MoneyEcho bet trả user_money ngay. Finish: win_amount = win_bet_amount + returned_amount
1 userMột connection. Duplicate → lobby 102

State: Pending=0 · Countdown=1 · DealTime=2 · ShowdownTime=3 · BetTime=4.

2. Demo xúc xắc

4
5
6

score = 15 · win_side = Big

EVEN
ODD
BIG ≥11
SMALL <11

Chip vàng = cửa API thắng. Even/Odd là hiển thị tổng (15 lẻ) — không gửi trong RequestBet.side.

3. WS envelope (đầy đủ)

Frame binary protobuf. Handshake: 0 closed · 1 other device playing · 2 too many conn · 4 token expired · 5 banned.

GET /ws?access_token=<JWT>     // domain game sicbo
game_event.Request.data_send { room_id: 7  data: <bytes sicbo_event.Request> }
game_event.Response.game_message { room_id: 7  data: <bytes sicbo_event.Response> }
game_message còn user_joined / user_left / start_countdown / start_game / reset_game / auto_leave.

4. Lobby C→S / S→C

C→SField
room_config→ room_types, play_now, best_choice, disable_*
get_room_listbet
create_roombet, password, max_players, name
join_roomroom_id, password, is_viewer
join_any_roombet, max_players
leave_roomroom_id
find_roomroom_id
inviteroom_id, password, user_id
free_users_listbet
send_chat_messageroom_id, message, to[], is_private_chat
data_sendroom_id + bytes game hoặc auto_leave
S→CField
room_config / room_listsảnh / danh sách bàn
game_messagepayload bàn
errorcode + tag
chat_messagechat
invite / someone_invited_youmời

5. Gameplay proto sicbo_event

C→S Request (oneof)

MessageFieldGhi chú
bet TagBet=1side, bet_amountEcho + user_money + total_side_bet
leaderboardTop win ngày
historyLịch sử cược của mình
sessionsDanh sách phiên
logsLịch sử cửa thắng + current_session
session_commandssession, side, from, toTối đa 100 lệnh / page
room_state / last_messagesSync / chat cũ
cheatdices[]Non-prod
Request { bet { side: Big  bet_amount: 5000 } }
Request { session_commands { session: 8821  side: Big  from: 0  to: 50 } }

S→C ResponseBet (echo ngay khi cược)

FieldÝ nghĩa
user_id, side, bet_amountAi cược cửa nào
total_betTổng cược user này trên cửa
user_moneyChip còn lại sau trừ
total_side_betTổng toàn server trên cửa đó

S→C vòng chơi

MessageField
start_betdelay_millis, end_at (unix)
dealsession — mã phiên, khóa cược
update_statususer_big_count, user_small_count, big_total_bet, small_total_bet
finishdices[], win_side, score, win_amount, user_money, win_bet_amount, returned_amount
room_statestate, dices, score, win_side, bets[], bet_sides, big/small totals, session, max_bet, …
Response { start_bet { delay_millis: 30000  end_at: 1720000030 } }
Response { deal { session: 8821 } }
Response { finish {
  dices: [4, 5, 6]
  win_side: Big
  score: 15
  win_amount: 10000
  user_money: 505000
  win_bet_amount: 5000
  returned_amount: 5000
} }

room_state — restore

FieldClient
state, count_down_millis, state_start_time, state_end_timeĐồng hồ + khóa cửa
dices[], score, win_side, sideHiện nếu đang ShowdownTime
bets[], bet_sides[]Mệnh giá + cược của mình
big_total_bet, small_total_bet, user_big_count, user_small_countThanh cân cửa
session, max_betMã phiên; max_bet < 0 = không giới hạn
Response { bet {
  user_id: 1001  side: Big  bet_amount: 5000
  total_bet: 5000  user_money: 495000  total_side_bet: 1200000
} }
Response { update_status {
  user_big_count: 86  user_small_count: 41
  big_total_bet: 1200000  small_total_bet: 800000
} }
returned_amount = hoàn cân cửa. win_amount = tiền ăn + hoàn. Cập nhật chip = user_money trên finish (và echo bet). Không suy ra even/odd từ Side enum.

Bảng phụ

ResponseHistory.history[]: session, time, bet_side, win_side, bet, returned_amount, win_amount
ResponseSessions.sessions[]: time, session, dices, score, total_bet_big/small, total_returned_*, win_side, number_of_commands_*
ResponseSessionCommands: session, from, to, side, commands[{time, total_bet, returned, side, user_id, username}]
ResponseLeaderboard.members[]: rank, name, user_id, total_win
ResponseLogs: logs[{dices, score, win_side, session}], current_session

Lobby payload mẫu

Request { room_config {} }
Request { join_any_room { bet: 5000  max_players: 0 } }
Request { create_room { bet: 5000  password: ""  max_players: 100  name: "sicbo-1" } }
Request { data_send { room_id: 7  data: <sicbo_event.Request bet> } }

Một user một socket. Gửi join lần 2 khi đã trong phòng → lobby 114/119. Hết chip → 120.

6. Luồng ghép

Connect /ws
room_config
join_any_room
start_bet
bet
deal → finish
  1. Connect JWT trên domain sicbo. Close 1/2/4/5 → dừng.
  2. room_config rồi join. Restore room_state (session, totals, dices nếu đang showdown).
  3. start_bet: đếm end_at, enable Big/Small.
  4. Gửi bet Tag=1. Cập nhật chip từ echo user_money, vẽ total_side_bet.
  5. deal khóa cửa. Animate 3 xúc xắc theo finish.dices, highlight win_side, cộng win_amount.
  6. Mở panel: leaderboard / history / sessions / session_commands khi user tap.

7. Error codes

Handshake0 closed · 1 other device · 2 too many conn · 4 token expired · 5 banned
Lobby100 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
Gameplay tag=11 NotBetTime · 2 InvalidBet · 3 NotEnoughChip · 4 SideBetNotAllowed · 5 UserNotFound · 6 ActionNotAllowed

Khi nào chip đổi

EventChip
Echo betuser_money đã trừ bet_amount
finish thắng Big+win_bet_amount + returned_amount
finish thuachỉ +returned_amount (nếu cân cửa)

8. Checklist client