回撥事件
遊戲房間的事件通過事件回撥發給你的服務端:房間建立、開局、玩家拿到座位、連上和斷線、離開、房間結束。大多數遊戲只需要處理 game_room.closed——它帶著結算結果和每個玩家的線上時長,用來發獎勵、記戰績、核對計費。
在控制台「回撥」頁添加回調地址,在事件型別中勾選需要的 game_room.* 事件。簽名校驗、重試、去重和其他事件完全相同,見回撥安全。

ts
import { CallbackHandler, MemoryDedupStore, MemoryNonceStore } from '@deeprespond/im-server-sdk/callback';
const handler = new CallbackHandler({
secrets: { [process.env.IM_CALLBACK_ENDPOINT_ID!]: [process.env.IM_CALLBACK_SECRET!] },
nonceStore: new MemoryNonceStore(),
dedupStore: new MemoryDedupStore(), // 多台服务器时换成共享的存储
});
handler.on('game_room.closed', async (_event, data) => {
// data.result 是你结束房间时给的结算结果;房间超时、全员离开等自动结束时为 null
await saveMatch(data.room_id, data.close_reason, data.result);
for (const m of data.members) await addPlayMinutes(m.username, m.billable_minutes);
});其他語言的寫法見 Go(EventHandlers.GameRoomClosed)、Python(@handler.on_event("game_room.closed"))、Java(handler.on("game_room.closed", ...)),Node.js 的完整說明見 Node.js 回撥。
事件一覽
| 事件 | 什麼時候 | 是否常用 |
|---|---|---|
game_room.created | 房間建立成功,已分配到遊戲節點 | 按需 |
game_room.started | 開局,遊戲節點開始推進幀 | 按需 |
game_room.member_joined | 玩家拿到座位(客戶端呼叫了加入) | 按需 |
game_room.member_connected | 玩家第一次連上游戲節點 | 頻繁,按需訂閱 |
game_room.member_disconnected | 玩家斷線,重連視窗內可以回來 | 頻繁,按需訂閱 |
game_room.member_left | 玩家離開:主動離開、超時、被移出、沒按時連上、房間結束 | 按需 |
game_room.closed | 房間結束,帶結算結果和每個玩家的線上時長 | 建議訂閱 |
公共欄位
每個事件的 data 都有:
| 欄位 | 說明 |
|---|---|
room_id | 房間 ID |
version | 房間版本,每次狀態變化加一。事件可能亂序或重複到達,用它判斷新舊 |
ext | 建房時的擴充套件欄位,原樣帶回 |
origin | 誰引起的:server 你的服務端、client 玩家、platform 平臺、system 系統(超時、節點等) |
事件外層的 id、type、occurred_at 等見事件回撥。
game_room.created
| 欄位 | 說明 |
|---|---|
region | 所在大區 |
max_players、sync_mode、tick_rate | 建立時的設定 |
created_at | 建立時間 |
game_room.started
| 欄位 | 說明 |
|---|---|
started_at | 開局時間 |
player_count | 開局時在座的人數 |
game_room.member_joined
| 欄位 | 說明 |
|---|---|
username、seat | 玩家和座位 |
joined_at | 拿到座位的時間 |
玩家拿到座位後 60 秒內沒有連上游戲節點,會以 connect_timeout 離開。
game_room.member_connected
| 欄位 | 說明 |
|---|---|
username、seat | 玩家和座位 |
transport | 連線方式:udp 或 ws |
at | 連上的時間 |
只在這次加入第一次連上時發出,斷線重連回來不再發出。
game_room.member_disconnected
| 欄位 | 說明 |
|---|---|
username、seat | 玩家和座位 |
reason | timeout 5 秒沒有收到資料;network 連線斷開 |
at | 斷線的時間 |
game_room.member_left
| 欄位 | 說明 |
|---|---|
username、seat | 玩家和座位 |
reason | leave 主動離開;timeout 斷線超過重連視窗;removed、kicked 被移出;connect_timeout 拿到座位後沒按時連上;room_closed 房間結束 |
connected_ms | 這次加入累計的線上時長(毫秒) |
left_at | 離開的時間 |
game_room.closed
json
{
"room_id": "rank-8812",
"version": 6,
"origin": "server",
"ext": {"match_id": "m-8812"},
"close_reason": "closed_by_server",
"created_at": "2026-11-10T08:00:00.000Z",
"started_at": "2026-11-10T08:00:15.000Z",
"closed_at": "2026-11-10T08:31:02.000Z",
"duration_ms": 1847000,
"result": {"winner": "alice", "scores": {"alice": 12, "bob": 9}},
"members": [
{"username": "alice", "seat": 0, "connected_ms": 1845200, "billable_minutes": 31, "leave_reason": "room_closed"},
{"username": "bob", "seat": 1, "connected_ms": 1790100, "billable_minutes": 30, "leave_reason": "room_closed"}
]
}| 欄位 | 說明 |
|---|---|
close_reason | 結束原因,見房間的狀態 |
created_at、started_at、closed_at | 時間;沒有開局時 started_at 為 null |
duration_ms | 開局到結束的時長(毫秒);沒有開局為 0 |
result | 你結束房間時給的結算結果;自動結束時為 null |
members | 每次加入一項(同一座位換過人時,前後兩人各一項),按座位和加入順序 |
members[].connected_ms | 這次加入累計的線上時長(毫秒) |
members[].billable_minutes | connected_ms 按分鐘向上取整,供你核對和給玩家計時。賬單按天彙總後取整,與逐局相加可能略有差異,見計費 |
members[].leave_reason | 離開原因,同 game_room.member_left 的 reason |
怎麼用:
- 用
room_id或ext裡的對局 ID 找到你的對局,按result發獎勵、記戰績。同一個事件可能重發,按事件id去重。 result為null說明房間不是由你結束的(超時、全員離開、節點故障),按你的規則判平局或作廢。- 節點故障(
node_lost)時線上時長按節點最後一次上報計算,最多少算 10 秒。
