iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 6
2
Software Development

從讀遊戲原始碼學做連線遊戲系列 第 6

Day 06 - 指令系統 - Unlight 的指令處理(一)

在上一篇我們了解指令是如何從封裝後客戶端發送到伺服器,我們依舊不清楚 Unlight 是如何將指令的內容轉換成可以被程式執行的動作。因此我們還需要了解 Unlight 是如何「執行」指令的。

先回來觀察看完整的 #receive_data 方法

# データの受信
def receive_data data
  a = data2command(data)
  @command_list += a unless a.empty?
  do_command
end

#data2command 解析完畢結構後,會將指令儲放到 @command_list 陣列裡面,然後接著呼叫 #do_command 方法來嘗試執行指令,因此我們要來看一下 #do_command 做了什麼才能讓 Unlight 執行指令上的動作。

# コマンドの実行
def do_command
  while cmd =@command_list.shift
    if cmd[0] > @func_list.size
      SERVER_LOG.error("#{@@class_name}: [invalid comanndNo.] >> #{cmd[0]}")
      # エラー数をカウントして
      if @error_count > COMMAND_ERROR_MAX
        SERVER_LOG.error("#{@@class_name}: [ErrorMAX disconnect!] >> #{cmd[0]}")
        logout
      else
        @error_count +=1
      end
    else
      begin
        @func_list[cmd[0]].call(cmd[1])
      rescue =>e
        SERVER_LOG.fatal("#{@@class_name}: [docommand:] fatal error #{e}:#{e.backtrace}")
      end
    end
  end
end

#do_command 方法中,會先嘗試將 @command_list 陣列裡面存放的指令盡可能的依序讀取到沒有新的指令為止,假設一次收到多個指令的時候才不會一時間少處理或者太慢處理。接下來會做一些檢查,像是用 cmd[0] > @func_list.size 會檢查指令是否存在。

如果指令確實存在的話,就會跑到 @func_list[cmd[0]].call(cmd[1]) 這段程式碼,透過 #call 將對應的方法執行,如果不存在的話則會紀錄錯誤的次數,太多次的話就判斷為有問題的使用者將它踢出伺服器。

關於 @func_list 我們會在後續登記可用指令的部分繼續討論。至於 #call 方法是 Ruby 的語言特性之一,有點類似我們在 C 與原使用的 Function Pointer 或者某些語言的 Func 類型物件,在前面我們有提到 Proc 物件就是這類物件的原型。

不過 cmd 這個來自於 #data2command 的變數又代表了怎樣的資訊,目前我們只知道他會有 cmd[0]cmd[1] 兩個元素,但是分別是什麼呢?

#data2command 這個方法中,我們會看到當指令到達結尾符號 \n 的時候,會將一些資訊存到 a 裡面,最後 #data2command 會回傳這個 a 陣列,而在文章中一開始的地方提到 #data2command 處理後的結果則是會被加入到 @command_list 陣列中。

if data[i+len+2] == "\n"
  d = @crypt.decrypt(data[i+2,len])
  a << [d[0,2].unpack('n')[0], d[2..-1]]
end

也就是說 [d[0, 2].unpack('n')[0], d[2..-1] 就是對應 cmd[0]cmd[1] 的數值,前面我們已經知道 Command ID 是一個 2 Bytes 的整數,因此 d[0, 2].unpack('n')[0] 的值就會是指令的編號,而剩下的部分直到結尾符號 \n 則會是 cmd[1] 的值,也就是指令的內容部分。

到這邊為止,我們大致上已經知道從客戶端發送資料到伺服器之後,是如何解析跟執行。但是該執行哪個指令跟執行的細節還不清楚,這就要再討論 Unlight 的 Command 系列物件是怎麼針對不同的伺服器登記可用的指令。

我的個人部落格是弦而時習之平常會把自己發現的一些新技巧紀錄在上面,也歡迎大家來逛逛。


上一篇
Day 05 - 指令系統 - Unlight 指令結構分析
下一篇
Day 07 - 指令系統 - Unlight 的指令處理(二)
系列文
從讀遊戲原始碼學做連線遊戲33

1 則留言

0
andy5343927
iT邦新手 5 級 ‧ 2019-09-20 23:58:50

是弦也大大欸~
身為一個大小姐前來支持一下

我要留言

立即登入留言