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ục | Giá trị |
|---|---|
| Connect | GET /ws?access_token=<JWT> trên domain game crash |
| Proto | package crash_event · tải .proto |
| Envelope | Frame binary = chính Request / Response. Không data_send, không room_id |
| Người chơi | 1 user = 1 socket = 1 ván. Không bàn chung |
| Đường cong | multiplier = elapsed_seconds / 10, bắt đầu từ 0 (không phải 1.00×) |
| Tick | ~200ms một next khi đang chơi |
| Tiền | Trừ bet lúc Play (BET). Cash out cộng floor(bet × multiplier) (WIN, gross). Crash = mất stake |
| HTTP gameplay | Không có. Chỉ health + /ws |
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.
| File | Package | Dùng cho |
|---|---|---|
/crash/crash_event.proto | crash_event | Mỗ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).
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)
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 |
|---|---|
0 | Closed (kết thúc session bình thường) |
2 | Too many connections (CCU) |
4 | Token expired / invalid — không upgrade |
5 | Banned |
6 | Server 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 {} }
| Field | Type | Client dùng để |
|---|---|---|
is_playing | bool | Đang có stake → hiện đồ thị + nút Cash out |
current_bet | int64 | Bet đã chọn (kể cả lúc idle = lần Play trước) |
current_cashout_multiplier | float | Mục tiêu auto của ván đang chạy; 0 nếu idle |
current_multiplier | float | Hệ số tại thời điểm server trả snapshot |
current_profit | int64 | Ước lượng gross bet × current_multiplier — chưa credit |
bets | int64[] | Mức cược hợp lệ — chỉ gửi đúng 1 giá trị này |
show_bets | int64[] | Giá trị hiển thị UI (cùng index với bets) |
user_money | int64 | Chip hiện tại (đã trừ bet nếu đang chơi) |
min_multiplier | float | Sàn cashout_at |
max_multiplier | float | Trầ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
} }
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.
| Field | Type | Ý nghĩa |
|---|---|---|
bet | int64 | Phải thuộc bets |
cashout_at | float | Auto cash out ∈ [min_multiplier, max_multiplier] |
| ResponsePlay | Ý nghĩa |
|---|---|
bet, cashout_at | Echo |
max_profit | floor(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.
| Field | Type | Client |
|---|---|---|
elapse | float | Số giây ván đã chạy (server) |
start_time | int64 | Unix nano lúc BET thành công — gốc đường cong |
multiplier | float | Hệ số hiện tại. HUD chính |
status | enum | Processing = 0 đang bay · Crash = 1 nổ |
timestamp | int64 | Unix nano thời điểm server tính multiplier này |
is_cashed_out | bool | Tick Processing: luôn false. Cash out đi message cashout, không đi next |
profit | int64 | Tick / crash: 0. Đừng lấy làm chip |
profit_multiplier | float | Echo 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
} }
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 |
|---|---|
multiplier | Hệ số được trả (thời điểm server) |
profit | Chip cộng vào ví = floor(bet × multiplier) — gross |
user_money | Số 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.
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
| Event | Chip |
|---|---|
| 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 |
| Crash | 0 thêm. Stake đã mất |
| Disconnect | Ván tiếp tục. Auto / crash vẫn settle |
| Server shutdown / GC | Refund 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 JWT trên domain crash. JSON code 2/4/5/6 → dừng. Socket cũ đóng 69 → coi như bị đá, giữ connection mới.
- Gửi
gameplay. Renderbets/show_bets, slidercashout_attrong min/max, chip =user_money. - Nếu
is_playing: restore đồ thị từcurrent_multiplier+start_time(tick kế sẽ tới), enable Cash out. Không Play. - User chọn bet + auto target →
play. Khóa Play. Animate từ 0×. Cập nhật chip −bet. - Mỗi
next Processing: set HUD =multiplier, vẽ điểm mới. Nút Cash out bật. - Tap Cash out →
cashout. Nhậncashout: dừng đồ thị, hiện profit, chip =user_money. - Hoặc nhận auto
cashoutkhi chạm target, hoặcnext status: Crash→ nổ, mất bet. - 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.
| code | tag | Khi nào | Client |
|---|---|---|---|
1 | 1 | Play khi đang có ván | Không gửi Play nếu is_playing |
2 | 1 | Bet không thuộc bets | Chỉ chip từ snapshot |
3 | 1 | Không đủ chip | Refresh gameplay / money |
6 | 1 | cashout_at ngoài min/max, hoặc lỗi trừ tiền | Clamp slider theo min/max |
6 | 2 | Cash out khi không có ván / đã crash / đã settle / gửi trùng | Khó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
- Tải proto: crash_event.proto.
- Domain crash, binary
crash_event— không lobby, không JSON gameplay HTTP. - Sau connect: luôn
gameplay. Restore nếuis_playing. - Bet ∈
bets;cashout_at∈[min_multiplier, max_multiplier]. - Đường cong từ 0, 10s / 1.0×. Snap theo
next.multiplier. - Thắng chỉ khi nhận
cashout. Crash =next.status == Crash, không cộng chip. profit/max_profitlà gross (stake đã trừ).cashout.timestampkhông ảnh hưởng kết quả — có thể gửi unix nano local.- Disconnect không hủy ván. Reconnect listen + gameplay. Socket cũ đóng 69.
- Pong
0x01cho ping0x00. Không spam cash out. - Không có top-win / history trên node này.