咱們的遊戲有這樣一種情景:客戶端中角色須要用到一些公會的數據,但服務器不會在玩家(創角後)一進入到遊戲裏就推送給玩家,而是須要客戶端本身在須要的時候向服務器請求公會的數據,以前的實現就是在請求消息的時候加一個回調函數,消息一回來就執行回調函數繼續後續的業務!但後面發現存在這樣的不足:服務器
1.有時會用到好多個參數,這就須要每次都把一些無關的參數傳給消息請求者,而後回調過來再把這些參數原封不動地傳回來,很繁瑣;app
2.這樣的回調寫法感受很不符合人類的順序思惟習慣,有點亂;函數
回調的lua代碼寫法相似:測試
--@callbackFunc帶的參數可能有(self, p1, p2, ..., [最後還有allianceData, 這個是取到數據後分發時加上的]) function AllianceProxy:requestAllianceData(callbackFunc) --handle send request msg --這裏使用一個uniqueKey往一個管理器中註冊保存這個回調 end function AllianceProxy:responseAllianceData(allianceData) --handle receive response msg --這裏根據上面uniqueKey分發消息,執行回調, 調用相似:callbackFunc(self, p1, p2, ..., allianceData) end --請求公會數據的寫法就是這樣: function Role:handleAllianceData() local function _callbackFunc(self, p1, p2, allianceData) --使用的到allianceData處理相關的業務邏輯 end AllianceProxy:requestAllianceData(packing(_callbackFunc, self, p1, p2)) --packing返回的仍然是一個function end
上述的參數self, p1, p2, ...等等徹底就不必往requestAllianceData中丟過去的,但就是由於收到回調後須要用到,做爲強迫症的我,以爲這種寫法很噁心,因此今天想到,這徹底能夠利用lua提供的協程機制來作這件事,大體思路的代碼以下:(注:下面這些代碼未通過編譯及測試,另外還未考慮協程恢復執行時若其主函數所在table被銷燬的狀況, 後續會完善下面的代碼)ui
--建立並運行一個協程 --@param mainFunc 協程主函數 function global:createAndRunningCo(mainFunc) self:assertFmt(type(mainFunc) == 'function', 'func=%s is not function', tostring(mainFunc)) local co = coroutine.create(mainFunc) local isSuccess, errMsg = coroutine.resume(co, co) self:assertFmt(isSuccess, 'one error happened in mainFunc:%s', errMsg) end function global:checkCoIsRunning(co) self:assertFmt(type(co) == 'thread') local curCo = coroutine.running() self:assertFmt(co == curCo, 'co[%s] is not running, current running coroutine is %s, please sure that co is running', co, curCo) end function global:yieldAndSaveCo(key, co) self:assertFmt(key ~= nil) self:checkCoIsRunning(co) if coT[key] == nil then coT[key] = {} end table.insert(coT[key], co) return coroutine.yield() end function global:resumeAndRemoveCo(key, ...) if coT[key] then for _, co in ipairs(coT[key]) do if coroutine.status(co) == 'suspended' then local isSuccess, errMsg = coroutine.resume(co, ...) self:assertFmt(isSuccess, 'one error happened in mainFunc:%s', errMsg) end end coT[key] = nil end end
local global = require('global') global:createAndRunningCo(function(co) local allianceData = Alliance:requestAllianceData(co) --do something end) function AllianceProxy:requestAllianceData(co) --send msg : request alliance Data return global:yieldAndSaveCo('allianceData', co) end function AllianceProxy:responseAllianceData(allianceData) --receive msg : response alliance data global:resumeAndRemoveCo('allianceData', allianceData) end
須要獲取公會數據的用戶就使用下面這樣的寫法則可:lua
global:createAndRunningCo(function(co) local allianceData = Alliance:requestAllianceData(co) --do something end)
而後在消息收發那裏作好相應的處理就好了,這個寫法跟前面的對比,很明顯,咱們順序的編寫相應的邏輯就好了,徹底不須要像前面的說等回調過來後反過頭來再執行相應的邏輯