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

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

[lua] 游戏客户端逻辑使用lua协程的更多相关文章

  1. lua:写了个基于协程的task调度库

    写了一个(不完整的)基于协程的task调度库 sample code如下 my_spawn( function () print('f: 1') local t1 = my_spawn( functi ...

  2. Cocos2d-x lua游戏开发之安装Lua到mac系统

    注意:mac ox .lua version :5.15 下载lua官网的lua, 注意:最好是5.15下面.5.2的lua不支持table的getn()方法,这让我情何以堪.(获取table长度.相 ...

  3. Openresty Lua协程调度机制

    写在前面 OpenResty(后面简称:OR)是一个基于Nginx和Lua的高性能Web平台,它内部集成大量的Lua API以及第三方模块,可以利用它快速搭建支持高并发.极具动态性和扩展性的Web应用 ...

  4. lua编程之协程介绍

    一,lua协程简介 协程(coroutine),意思就是协作的例程,最早由Melvin Conway在1963年提出并实现.跟主流程序语言中的线程不一样,线程属于侵入式组件,线程实现的系统称之为抢占式 ...

  5. 《Lua游戏开发实践指南》读后感

    书籍地址:http://book.douban.com/subject/20392269/ 一句话点评该书:想用Lua作游戏脚本开发的同学值得一读! (一)本书特点 市面专门讲Lua的中文书籍非常少, ...

  6. python协程--yield和yield from

    字典为动词“to yield”给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 next(...) 的 ...

  7. Unity3D中的线程与协程

    线程 Unity3D是以生命周期主线程循环进行游戏开发. Unity3D中的子线程无法运行Unity SDK(开发者工具包,软件包.软件框架)跟API(应用程序编程接口,函数库). 限制原因:大多数游 ...

  8. Kotlin协程解析系列(上):协程调度与挂起

    vivo 互联网客户端团队- Ruan Wen 本文是Kotlin协程解析系列文章的开篇,主要介绍Kotlin协程的创建.协程调度与协程挂起相关的内容 一.协程引入 Kotlin 中引入 Corout ...

  9. 45、concurrent.futures模块与协程

    concurrent.futures  —Launching parallel tasks    concurrent.futures模块同时提供了进程池和线程池,它是将来的使用趋势,同样我们之前学习 ...

随机推荐

  1. IOS苹果手机上 iframe 滚动失效条问题,局部滚动开启弹性滚动!

    html:bo<div class="scroll-wrapper"> <iframe src=""></iframe> & ...

  2. Oracle基础学习(二)v$session中Command的数字含义

    v$session中Command的数字含义. 1 CREATE TABLE 2 INSERT 3 SELECT 4 CREATE CLUSTER 5 ALTER CLUSTER 6 UPDATE 7 ...

  3. 消息队列NetMQ 原理分析2-IO线程和完成端口

    消息队列NetMQ 原理分析2-IO线程和完成端口 前言 介绍 目的 IO线程 初始化IO线程 Proactor 启动Procator线程轮询 处理socket 获取超时时间 从完成端口获取处理完的状 ...

  4. .Net程序员学用Oracle系列(11):系统函数(下)

    1.聚合函数 1.1.COUNT 函数 1.2.SUM 函数 1.3.MAX 函数 1.4.MIN 函数 1.5.AVG 函数 2.ROWNUM 函数 2.1.ROWNUM 函数简介 2.2.利用 R ...

  5. shell 快速入门

    1: 脚本开始行 #!/bin/bash 这一行表明,不管用户选择的是那种交互式shell,该脚本需要使用bash shell来运行. 由于每种shell的语法大不相同,所以这句非常重要. 2:变量 ...

  6. 日志组件 logback

    一.简介 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- classic和logback-access.logb ...

  7. C语言一维数组转换为二维数组

    一维转二维代码示例: #include <stdio.h> #include <stdlib.h> #define ROW 3 #define COL 2 int main(i ...

  8. java 多线程安全问题-同步代码块

    /* 多线程的安全问题: while(true) { if(tick>0) { //线程0,1,2,3在余票为1时,都停滞在这里,之后分别获得CPU执行权,打印出0,-1,-2等错票 Syste ...

  9. C语言陷阱:浮点运算

    在Stack overflow上看到这样一个问题. 计算如下表达式的值: P=(1/2-3/4)*(5/6-7/8)*…*[n/(n-1) - (n+2)/(n+3)]. 程序如下: #include ...

  10. Python sphinx-build在Windows系统中生成Html文档

    看到前同事发布的“Markdown/reST 文档发布流水线”基于TFS.Docker.Azure等工具和平台进行文档发布的介绍说明,不得不在心中暗暗竖起大拇指.这套模式,实现了文档编写后版本管理.发 ...