iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
自我挑戰組

Robot Framework 與 Websocket 協議測試系列 第 8

待測系統命令訊息解析

  • 分享至 

  • xImage
  •  

前言

講完封包的標頭格式,再來就是遊戲的關鍵資料結構-- Protobuf 命令訊息,也是跟 JSON 的最大差別--強制型態確認,這個至關重要,後續所有伺服器跟客戶端的互動都是基於這些命令定義,也是開發自動測試腳本的主要關注點,今天會把遊戲用到的幾個命令訊息一一拆解說明。

回顧遊戲流程

雖然是兩天前的內容,不過為了快速查閱還是放一份在這,遊戲流程從高階的觀點可以這樣看:

  1. 玩家端連線登入
  2. 等待伺服器通知開局
  3. 玩家下注並發送完成信號
  4. 莊家開獎,決定中獎號碼
  5. 莊家計算派彩並通知玩家更新帳號餘額
  6. 回到步驟一,等待下一次開局

實際上,稍微把上述階段跟實際命令展開,可以得到以下彙整表:

階段 客戶端請求 服務端回應
登入 LoginRequest LoginResponse
進房間 RoomJoinRequest RoomJoinResponse
取得快照 SnapshotRequest SnapshotResponse
下注 BetPlacementRequest BetPlacementResponse
下注結束 BetFinishedRequest BetFinishedResponse
開獎與派彩結果 ReckonResultRequest ReckonResultResponse

稍微解釋一下快照,完成登入跟進入房間後,需要取得目前遊戲的狀態,在業界術語就是快照,這是初始化過程或者遊戲狀態同步很重要的一個命令訊息

接下來,就會一一拆解命令訊息

檔頭

// game_messages.proto
syntax = "proto3";

package gaming;

第一行:syntax = "proto3";作用
指定 Protobuf 語法版本:告訴編譯器使用 Protocol Buffers 的第3版語法
必須放在文件最開頭(除了註釋)

第二行:package gaming;
定義命名空間:避免不同文件中的消息類型名稱衝突
組織代碼結構:將相關的消息類型分組

登入

// Authentication Messages
message LoginRequest {
    string username = 1;
    string password = 2;
}

message LoginResponse {
    bool success = 1;
    string message = 2;
    string session_token = 3;
    int64 user_id = 4;
    int64 balance = 5;
}

玩家端使用 LoginRequest 登入時,要帶入兩個參數,帳號跟密碼,這個應該不需多做解釋
服務端會套用 LoginResponse 回應,內容包括:

  1. success:執行狀態成功與否
  2. message:狀態值對應的成功失敗說明訊息
  3. session_token:這次連線的 session token,僅供參考後續沒有延續擴展使用
  4. user_id:玩家的 ID 編號
  5. balance:目前的帳戶餘額,目前設計無持久儲存,一進入就是給一百萬

進房間

// Room Management Messages
message RoomJoinRequest {
    int32 room_id = 1;
}

message RoomJoinResponse {
    bool success = 1;
    string message = 2;
    int32 room_id = 3;
    int32 player_count = 4;
    int64 jackpot_pool = 5;
}

登入遊戲完成認證後,下一步就是進入指定的遊戲房間,RoomJoinRequest 輸入的參數也很簡單,就是哪一間房間
RoomJoinResponse 出參為求擬真,會回傳以下內容:

  1. room_id: 進入的房間id
  2. player_count: 該房間目前的玩家人數
  3. jackpot_pool: 當前的 Jackpot 獎池累積額,不過這次沒有設計抽水累計機制,應該都是零

取得快照

// Game State Messages
message SnapshotRequest {
    // Empty message
}

message SnapshotResponse {
    int64 user_balance = 1;
    repeated Bet active_bets = 2;
    int32 current_room = 3;
    int64 jackpot_pool = 4;
    GameRoundStatus round_status = 5;
}

message Bet {
    int32 dice_face = 1;
    int64 amount = 2;
    string bet_id = 3;
    string round_id = 4;
}

enum GameRoundStatus {
    NO_ACTIVE_ROUND = 0;
    BETTING_PHASE = 1;
    WAITING_RESULTS = 2;
}

SnapshotRequest 輸入參數很簡單,就是不需要參數
SnapshotResponse 取得快照的返回值這邊又稍微複雜一點,可以看到應用了 Protobuf 的引用跟陣列性質

  1. repeated Bet active_bets: 有 repeated 字樣表示使用是包含零個或多個 Bet 結構的資料,Bet 在下面有單獨定義
  2. Bet: 當前的下注狀況,不過以這次電子遊戲的設計架構,每個玩家都是自己單獨對莊家,就沒有這些累計數字,有意義的就是 round_id 該局的代號
  3. GameRoundStatus: 一樣是個外部參考定義,在下面有說明,可以指示當前是休息中、下注中、還是等待開獎狀態,一樣在實作上應該都是玩家一進入房間就是可以下注狀態

下注 & 下注結束

// Betting Messages
message BetPlacementRequest {
    int32 dice_face = 1;  // 1-6
    int64 amount = 2;     // Bet amount
    string round_id = 3;  // Game round identifier
}

message BetPlacementResponse {
    bool success = 1;
    string message = 2;
    string bet_id = 3;
    int64 remaining_balance = 4;
    string round_id = 5;
}

message BetFinishedRequest {
    string round_id = 1;  // Game round identifier
}

message BetFinishedResponse {
    bool success = 1;
    string message = 2;
    string round_id = 3;
}

下注階段可細分兩個: 下注中跟結束下注
BetPlacementRequest 下注中的輸入參數就是:

  1. dice_face: 押注的數字,範圍是 1-6
  2. amount: 下注額
  3. round_id: 局號,兩邊對照檢查用,要套用快照拿到的局號來用,這個用法很重要,後面會重複出現

BetPlacementResponse 回傳值有:

  1. bet_id: 注單ID
  2. remaining_balance: 下注後帳戶餘額
  3. round_id: 局號

可以發現上述下注動作一次只能押注一個數字,不過結束前可以重複執行達到多數字押注的目標

下注完畢後,使用 BetFinishedRequest 通知服務端下注完成,參數只有一個--局號
BetFinishedResponse 回傳值一樣只有一個參數--局號

開獎與派彩

// Result Messages
message ReckonResultRequest {
    string round_id = 1;  // Game round identifier
}

message ReckonResultResponse {
    int32 dice_result = 1;           // 1-6
    repeated BetResult bet_results = 2;
    int64 total_winnings = 3;
    int64 new_balance = 4;
    int64 updated_jackpot_pool = 5;
    string round_id = 6;
}

message BetResult {
    string bet_id = 1;
    int32 dice_face = 2;
    int64 bet_amount = 3;
    bool won = 4;
    int64 payout = 5;
    string round_id = 6;
}

通知下注結束後,再來就是等待開獎
首先用 ReckonResultRequest 請求開獎結果,,參數只有一個--局號
ReckonResultResponse 會回應以下內容:

  1. dice_result: 開獎結果,是哪個數字
  2. repeated BetResult bet_results: 零到多組派彩結果
  3. total_winnings: 總贏分
  4. new_balance: 更新後的帳戶餘額
  5. updated_jackpot_pool: 更新後的 Jackpot 獎池累積額,但應該都是零
  6. round_id: 供檢查用的局號

小結

至此,有命令訊息定義,玩家跟服務端雙方就能按此規格互相通訊了,理論定義花了不少篇幅,不過相信對於讀者的整體理解是有幫助的
下一章結就是開始 Python 端的實作,逐步按照規劃把服務器端做出來、一一測試然後包裝成 Robot Framework 的結構


上一篇
待測系統的網路封包標頭解析
下一篇
Protobuf Python 端的編譯與序列化/反序列化/編解碼處理
系列文
Robot Framework 與 Websocket 協議測試10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言