NON-PRODUCTION

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

Minigame 1 người: cược, multiplier tăng theo đồng hồ server, cash out trước khi nổ. Client nói WebSocket binary protobuf trực tiếp crash_event — không lobby, không phòng, không bọc game_event.

1. Tổng quan

MụcGiá trị
ConnectGET /ws?access_token=<JWT> trên domain game crash
Protopackage crash_event · tải .proto
EnvelopeFrame binary = chính Request / Response. Không data_send, không room_id
Người chơi1 user = 1 socket = 1 ván. Không bàn chung
Đường congmultiplier = elapsed_seconds / 10, bắt đầu từ 0 (không phải 1.00×)
Tick~200ms một next khi đang chơi
TiềnTrừ bet lúc Play (BET). Cash out cộng floor(bet × multiplier) (WIN, gross). Crash = mất stake
HTTP gameplayKhông có. Chỉ health + /ws
Kết quả do đồng hồ server. RequestCashOut.timestamp client gửi chỉ để log, không quyết định thắng/thua. Disconnect không hủy ván — auto cash out / crash vẫn chạy. Reconnect gửi lại gameplay để restore.

cashout_at phải nằm trong [min_multiplier, max_multiplier] từ snapshot (mặc định 1.01 … 100 nếu game.json không khai báo). Bet chỉ gửi giá trị trong bets[].

2. Proto cho client

Tải file .proto rồi generate code (protoc / buf). Frame WS là binary protobuf, không JSON. Crash không bọc game_event.

FilePackageDùng cho
/crash/crash_event.protocrash_eventMỗi frame WS: Request / Response
GET /crash/crash_event.proto
# Host = domain DOCUMENT (trang docs này), không phải domain GAME.

3. Demo đồ thị

Ví dụ ván bet 1000, auto cash out 2.00×. Đường vàng = multiplier đang chạy. Nét đứt xanh = mục tiêu auto. Chấm đỏ = crash point server (client không biết trước).

1.50×
PROCESSING

elapse ≈ 15s · start_time (unix nano) · cashout_at = 2.00 · max_profit = 2000

next.multiplier cashout_at crash (chỉ khi status=Crash)

Animate theo start_time + tick next. Snap multiplier mỗi tick (~200ms). Đừng tự random điểm nổ. 10 giây = +1.0×.

4. WS envelope

GET /ws?access_token=<JWT>     // domain game crash
// mỗi frame binary = protobuf crash_event.Request  (C→S)
//                   hoặc crash_event.Response (S→C)
Khác sicbo / baccarat: không bọc game_event.data_send, không join phòng. Connect xong gửi gameplay ngay. Frame không phải JSON.

Handshake HTTP 200 JSON {"code": N} nếu không giữ được socket:

codeÝ nghĩa
0Closed (kết thúc session bình thường)
2Too many connections (CCU)
4Token expired / invalid — không upgrade
5Banned
6Server stopped

Một user một socket. Login máy khác → socket cũ đóng WS code 69 ("other player logged in your account"). Giữ socket mới.

Keepalive: server gửi binary 1 byte 0x00 ~15s; client trả 0x01 trong 25s. Frame 1 byte này không phải protobuf.

crash_event.Request { gameplay {} }
crash_event.Request { play { bet: 1000  cashout_at: 2.0 } }
crash_event.Request { cashout { timestamp: 1720000015000000000 } }

crash_event.Response { gameplay { ... } }
crash_event.Response { play { bet, cashout_at, max_profit } }
crash_event.Response { next { elapse, start_time, multiplier, status, ... } }
crash_event.Response { cashout { multiplier, profit, user_money } }
crash_event.Response { error { code, tag } }

5. RequestGameplay — snapshot

Gửi sau mỗi lần connect / reconnect. Server không tự đẩy snapshot lúc Connected. Nếu is_playing thì restore HUD, không gửi Play lại.

Request { gameplay {} }
FieldTypeClient dùng để
is_playingboolĐang có stake → hiện đồ thị + nút Cash out
current_betint64Bet đã chọn (kể cả lúc idle = lần Play trước)
current_cashout_multiplierfloatMục tiêu auto của ván đang chạy; 0 nếu idle
current_multiplierfloatHệ số tại thời điểm server trả snapshot
current_profitint64Ước lượng gross bet × current_multiplier — chưa credit
betsint64[]Mức cược hợp lệ — chỉ gửi đúng 1 giá trị này
show_betsint64[]Giá trị hiển thị UI (cùng index với bets)
user_moneyint64Chip hiện tại (đã trừ bet nếu đang chơi)
min_multiplierfloatSàn cashout_at
max_multiplierfloatTrần cashout_at
Response { gameplay {
  is_playing: true
  current_bet: 1000
  current_cashout_multiplier: 2.0
  current_multiplier: 1.50
  current_profit: 1500
  bets: [200, 1000, 2000, 10000]
  show_bets: [200, 1000, 2000, 10000]
  user_money: 499000
  min_multiplier: 1.01
  max_multiplier: 100
} }
Trong lúc đang chơi, reconnect không reload mức bet — bets đóng băng theo ván đang mở. Idle mới cập nhật config bet.

6. RequestPlay

Debit bet ngay. Một user chỉ 1 ván: Play khi is_playing → error code 1 tag 1.

FieldTypeÝ nghĩa
betint64Phải thuộc bets
cashout_atfloatAuto cash out ∈ [min_multiplier, max_multiplier]
ResponsePlayÝ nghĩa
bet, cashout_atEcho
max_profitfloor(bet × cashout_at) — số WIN tối đa nếu auto chạm đích (gross, stake đã trừ)
Request { play { bet: 1000  cashout_at: 2.0 } }

Response { play {
  bet: 1000
  cashout_at: 2.0
  max_profit: 2000
} }

Sau Play: khóa nút Play, trừ chip local = bet (hoặc đợi tick đầu / gửi lại gameplay nếu cần user_money chính xác — Play response không có money). Bắt đầu animate từ 0×.

7. Tick / ResponseNext

Server đẩy ~200ms khi ván đang chạy. Dùng để vẽ đồ thị. Không phải tín hiệu thắng.

FieldTypeClient
elapsefloatSố giây ván đã chạy (server)
start_timeint64Unix nano lúc BET thành công — gốc đường cong
multiplierfloatHệ số hiện tại. HUD chính
statusenumProcessing = 0 đang bay · Crash = 1 nổ
timestampint64Unix nano thời điểm server tính multiplier này
is_cashed_outboolTick Processing: luôn false. Cash out đi message cashout, không đi next
profitint64Tick / crash: 0. Đừng lấy làm chip
profit_multiplierfloatEcho multiplier trên tick — potential, chưa credit
Response { next {
  elapse: 15
  start_time: 1720000000000000000
  multiplier: 1.50
  status: Processing
  timestamp: 1720000015000000000
  is_cashed_out: false
  profit: 0
  profit_multiplier: 1.50
} }
Công thức local (chỉ interpolate giữa 2 tick): multiplier ≈ (now_aligned − start_time) / 10e9. Outcome chỉ tin status: Crash hoặc message cashout.

8. Cash out

Manual — RequestCashOut

Gửi khi đang Processing. Server lấy multiplier tại lúc handle request, không dùng field timestamp.

Request { cashout { timestamp: <unix nano, debug> } }

Response { cashout {
  multiplier: 1.50
  profit: 1500
  user_money: 500500
} }
FieldÝ nghĩa
multiplierHệ số được trả (thời điểm server)
profitChip cộng vào ví = floor(bet × multiplier) — gross
user_moneySố dư sau WIN. HUD chip = field này

Ví dụ: bet 1000 đã trừ lúc Play, cash out 1.50× → profit = 1500, net +500, user_money tăng 1500 so với sau Play.

Auto

Nếu multiplier chạm cashout_at trước crash, server tự gửi cùng ResponseCashOut (multiplier đúng bằng target, không phải tick trễ). Client không cần gửi cashout.

Gửi cash out sau khi ván đã nổ / đã settle: nhận error code 6 tag 2. Nếu crash xảy ra trước, client còn nhận next status: Crash (settle chạy trước khi xử lý cash out). Không spam — hàng đợi socket 8 slot, tràn là drop.

9. Crash

Không có message riêng. Server gửi ResponseNext với status: Crash. Stake đã trừ lúc Play, không hoàn, không WIN.

Response { next {
  elapse: 18.4
  start_time: 1720000000000000000
  multiplier: 1.84
  status: Crash
  timestamp: 1720000018400000000
  is_cashed_out: false
  profit: 0
  profit_multiplier: 1.84
} }

multiplier lúc này = crash point. Animate nổ tại điểm đó, hiện “CRASHED”, mở lại nút Play. Chip không đổi so với sau Play (đã mất bet).

Điểm nổ được sample lúc Play, client không bao giờ thấy trước. Một phần ván nổ dưới 1.0× — dưới sàn auto cash out nên luôn thua nếu không (và không thể) cash out sớm hơn min_multiplier.

10. Tiền

EventChip
Play OK−bet (BET). Response Play không echo money — trừ local hoặc gọi lại gameplay
Cash out (manual / auto)+profit (WIN gross). Tin user_money
Crash0 thêm. Stake đã mất
DisconnectVán tiếp tục. Auto / crash vẫn settle
Server shutdown / GCRefund stake — không có message (process đang tắt)
max_profit / profit là tiền cộng vào ví, không phải lãi ròng. Lãi ròng = profit − bet khi cash out; crash = −bet.

11. Luồng ghép

Connect /ws
gameplay
play
next × N
cashout hoặc next Crash
play tiếp
  1. Connect JWT trên domain crash. JSON code 2/4/5/6 → dừng. Socket cũ đóng 69 → coi như bị đá, giữ connection mới.
  2. Gửi gameplay. Render bets / show_bets, slider cashout_at trong min/max, chip = user_money.
  3. Nếu is_playing: restore đồ thị từ current_multiplier + start_time (tick kế sẽ tới), enable Cash out. Không Play.
  4. User chọn bet + auto target → play. Khóa Play. Animate từ 0×. Cập nhật chip −bet.
  5. Mỗi next Processing: set HUD = multiplier, vẽ điểm mới. Nút Cash out bật.
  6. Tap Cash out → cashout. Nhận cashout: dừng đồ thị, hiện profit, chip = user_money.
  7. Hoặc nhận auto cashout khi chạm target, hoặc next status: Crash → nổ, mất bet.
  8. Mở lại Play. Không history / leaderboard trên WS này.

Reconnect giữa ván: listen ngay (có thể nhận next / cashout / Crash do settle lúc Connected), rồi gửi gameplay để sync HUD.

12. Error codes

Nằm trong Response.error. tag cho biết request nào: 1 = Play, 2 = Cash out. Comment proto (RequestBet / TipDealer) là copy game khác — bỏ qua.

codetagKhi nàoClient
11Play khi đang có vánKhông gửi Play nếu is_playing
21Bet không thuộc betsChỉ chip từ snapshot
31Không đủ chipRefresh gameplay / money
61cashout_at ngoài min/max, hoặc lỗi trừ tiềnClamp slider theo min/max
62Cash out khi không có ván / đã crash / đã settle / gửi trùngKhóa nút sau Crash hoặc cashout
Response { error { code: 1  tag: 1 } }   // Play lúc đang bay
Response { error { code: 6  tag: 2 } }   // Cash out trễ / trùng

13. Checklist client