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

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

1.有时会用到好多个参数,这就需要每次都把一些无关的参数传给消息请求者,然后回调过来再把这些参数原封不动地传回来,很繁琐;

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被销毁的情况, 后续会完善下面的代码)

--创建并运行一个协程
--@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

需要获取公会数据的用户就使用下面这样的写法则可:

global:createAndRunningCo(function(co)
    local allianceData = Alliance:requestAllianceData(co)

    --do something
end)
然后在消息收发那里做好相应的处理就行了,这个写法跟前面的对比,很明显,我们顺序的编写相应的逻辑就行了,完全不需要像前面的说等回调过来后反过头来再执行相应的逻辑
 

转载于:https://www.cnblogs.com/AlphaAI/p/6443421.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值