到上一篇為止我們已經知道 register_r
這類解析資料的 _r
類型方法是怎麼定義的,但是卻不知道當解析完畢後後直接呼叫的方法實際上是做什麼。
我們繼續以 src/protocol/authserver.rb
作為例子,因為這些行為都透過 .class_eval
動態的定義在 AuthServer
上,因此呼叫的方法(像是 register
)也應該是屬於 AuthServer
上的行為。
繼續在在原始碼中我們確實可以找到對應的行為實作
# ======================================
# 受信コマンド
# =====================================
# プレイヤーを登録
def register(name, email, salt, verifire, server_type)
SERVER_LOG.info("#{@@class_name}: [register] #{name} ,#{salt}, #{verifire}, #{server_type}")
regist_result(Player.regist(name, email, salt, verifire, server_type))
end
不過,如果我們去看其他的伺服器的原始碼,像是 src/protocol/dataserver.rb
反而會發現整個檔案內容是非常少的並沒有定義任何相關的行為,這可能是因為這些方法的數量比較多,因此 Unlight 把它放到了 Controller 裡面。
因此我們可以找到 include DataController
這行將 DataController 模組引入的程式碼,然後再到 src/controller/data_controller.rb
就可以找到 DataController
這個 Module,在模組裡面就定義了所有需要處理指令的對應行為。
Ruby 語言有一個叫做 Mixin (混合)的特性,因為相較於其他語言在繼承實作上只能單一繼承,但是如果要同時繼承多個物件的行為或者介面的話就難以實踐。取而代之的是 Mixin 機制,也就是我們可以將一個物件包含(include)一個模組,透過混合多個模組的行為來達成類似的效果。
在比較新版本的 Ruby on Rails 中,也導入了利用 Mixin 特性的 Concern 的概念用來輔助開發者將相似的功能抽離出來,在不同的物件上使用。
到這邊關於解析的部分已經告一段落,我們已經大致上了解了 Unlight 是如何把一堆封包轉換成一個在 Ruby 中可以實際執行的指令,在裡面其實我們可以發現不少我們熟悉的影子。
舉例來說,在 Unlight 的 ActionScript 客戶端中,也會實際存在 register
這個方法,當我們呼叫 register
方法後,就能夠實際上對應到在 Ruby 所寫的伺服器上面的 register
方法,這種作法在大部分的遊戲引擎大多會提供這種方式。這種類型的操作我們通常會稱為 RPC 不過很明顯的 Unlight 並沒有使用這個協定,不然以改寫 HTML5 版本為目標是很有機會使用 gRPC 等較新的機制來作為替代。
另一方面,一個指令編號對應一個 Controller 方法也容易讓人聯想到一般 Web 開發框架的 Router 機制,以 Ruby on Rails 作為例子就會類似這樣的定義:
# config/router.rb
mount AuthServer => '/auth'
# AuthServer (Engine)
post '/register' => 'auth#register'
雖然 RPC 或者 Router 都能夠解決這類問題,不過從遊戲跟 Web 的應用情境來看 PRC 這種設計方式似乎是更適合遊戲應用的。
推測 Unlight 會使用自己設計的規格大概跟線上遊戲早期受到網路速度的限制、保護遊戲不被攻擊等各種考量和遊戲業的習慣有關。
我的個人部落格是弦而時習之平常會把自己發現的一些新技巧紀錄在上面,也歡迎大家來逛逛。