[lua] 游戏客户端逻辑使用lua协程

  咱们的游戏有这样一种情景:客户端中角色须要用到一些公会的数据,但服务器不会在玩家(创角后)一进入到游戏里就推送给玩家,而是须要客户端本身在须要的时候向服务器请求公会的数据,以前的实现就是在请求消息的时候加一个回调函数,消息一回来就执行回调函数继续后续的业务!但后面发现存在这样的不足:服务器

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)
而后在消息收发那里作好相应的处理就好了,这个写法跟前面的对比,很明显,咱们顺序的编写相应的逻辑就好了,彻底不须要像前面的说等回调过来后反过头来再执行相应的逻辑
相关文章
相关标签/搜索