易语言教程_易语言源码_易语言视频教程_易语言论坛

 找回密码
 点击注册

Vip新手入门区
新手学习指南  学员作品展示 Vip课程总纲  Vip绝密课程系列

Vip相关下载区
Vip模块下载   Vip模块绑定   Vip模块例子 魔鬼插件下载  魔鬼插件例子  教程工具下载

Vip论坛服务区
教程问题提问区   模块问题提问区 技术交流区   魔鬼插件建议   忘记密码找回

VIP会员办理QQ: 8643245   
【请先加好友,然后到好友列表双击联系客服,办理VIP会员。】
【基础篇】易语言辅助入门基础教程
VIP模块办理QQ: 7189694 办理正版魔鬼作坊VIP模块 【基础篇】OD与CE入门基础教程
办理【终身VIP会员】“秒杀价” 仅需 RMB278.00元… 【基础篇】零基础绝密汇编语言入门课程 (共26课已完成)…
办理VIP详情…猛击这里查看详情 【基础篇】VIP辅助入门基础教程-新手必学 已发布10课 ……
VIP教程免费试看章节…猛击下载 【第1款】制作“辅助挂”教程目录查看(共107+16_x64下更新课已完成)…
亲爱的VIP学员,请到此写下你学习的感受与发布作品截图… 【第2款】制作“任务挂”教程目录查看(共77+1_x64下更新课已完成)…
卍解吧!不用bp send类封包断点找CALL的各种通杀思路 【第3款】驱动过保护技术课程(共38课已完成)…
【绝密教程】VIP绝密教程系列---注意:随时会更新! 【第4款】VIP邪恶二叉树辅助课程 (共31+17_x64下更新课已完成)…
【精品第13款】3D射击游戏与页游透视 智辅课程 已完成17课… 【第5款】零基础易语言按键辅助教程 (30课已完成)…
【精品第14款】变态功能辅助是如何炼成的 已完成36课… 【第6款】从零开始学习封包辅助技术教程(20课已完成) …
【精品第15款】DNF商业变态辅助的修炼之路 已完成27课… 【第7款】大杀特杀分析来源与CALL吸血鬼课程 (56课已完成)
【精品第16款】中控台多线程多开自动化商业辅助课程 已完成66课… 【第8款】完全零基础网页辅助课程(40课已完成)
【全新精品第17款】检测原理与过游戏内存检测技术课程 已发布9课… 【第9款】自动登录与操控LUA技术课程 (共46+8_x64下更新课已完成)…
【全新精品第18款】手游全自动化任务脚本辅助课程 已发布25课…… 【第10款】网页辅助封包脱机进阶课程 已完成30课…
【全新精品第19款】D3D方框骨骼透视与自瞄辅助课程进阶篇 已发布34课…… 【第11款】VC++ Lua脚本辅助课程 已完成112课…
【全新精品第20款】 X64模拟器吃鸡游戏方框透视自瞄辅助课程 发布中... 【第12款】网游脱机封包智辅课程 已完成35课…
查看: 1632|回复: 1

LUA协程和多任务笔记

[复制链接]

6

主题

3

回帖

11

积分

编程入门

Rank: 1

魔鬼币
50
发表于 2015-10-21 14:18:47 | 显示全部楼层 |阅读模式
最近在学习lua多任务, 用于智辅游戏服务器消息的处理, 因为脚本消息很多,
每分钟有几十条到上百条, 如果不能多任务并行处理, 会拖慢游戏,也不实用
整理下, 做个笔记, 以免忘了, 代码也是百度来的, 改改能用
lua用5.3.1版, 和我原来的5.1版本有不兼营, 按网上的方法改成支持中文变量
这样挺好的, 代码也不用注释, 取名字方便,也短, 不然如果用英文
背包-->bag 血-->HP 兰-->MP 还好翻译好记
怪物-->monster 人物-->human 就不有点长,不好记
地面物品-->dropeditem 装备-->useitem 狂欢应典活动-->KHQD 太不直观了
xx地图 xxNPC xx任务 就十分难翻译了,
闲话结束, 正文开始
----------------------------------------------

--LUA协程和多任务
--3个同时运行的协程为例
--每隔一定的间隔输出文字, 协程状态
--第1个 隔101毫秒 输出5次
--第2个 隔101毫秒 输出2次
--第3个 隔101毫秒 输出3次
--实现协程的关键是要 延时 = mylib.delay 这个函数
--标准库里没有这个函数 用C扩展为DLL库来使用
--先启用定时器, 然后把协程挂起(yield), 定时器时间到了再唤醒(resume)
--这样就能实现多个任务同时运行
--协程一次只能有1个运行(running), 其它都是在挂起状态(suspended)
--当协程运行结束后, 就是停止状态(dead)
--协程挂起(yield), 唤醒(resume), 应用有一定限制,就是不能在C和LUA间交叉使用
--即在C中挂起的,就要在C中唤醒, Lua中挂起的,也要在LUA中唤醒
--协程的开销不大, 初略估计了下, 开启运行2万多个协程,结束后故意不消毁,内存约增加20多M
--1个协程的开销约1k多内存

--Lua脚本
延时 = mylib.delay

function 显示(a,b)
  print(a,b,'co1='..coroutine.status(co1),'co2='..coroutine.status(co2),'co3='..coroutine.status(co3))
end

function 协程(序号,次数,毫秒)
    for i=1,次数 do
        延时(毫秒) 显示(序号,i*毫秒 )
    end
    显示(序号,'结束' )
end

co1=coroutine.create(协程) coroutine.resume(co1, '脚本1', 5, 101)
co2=coroutine.create(协程) coroutine.resume(co2, '脚本2', 2, 301)
co3=coroutine.create(协程) coroutine.resume(co3, '脚本3', 3, 501)

--运行结果
036CBF54 脚本1  101     co1=running     co2=suspended   co3=suspended
036CBF54 脚本1  202     co1=running     co2=suspended   co3=suspended
036CC01C 脚本2  301     co1=suspended   co2=running     co3=suspended
036CBF54 脚本1  303     co1=running     co2=suspended   co3=suspended
036CBF54 脚本1  404     co1=running     co2=suspended   co3=suspended
036CC0E4 脚本3  501     co1=suspended   co2=suspended   co3=running
036CBF54 脚本1  505     co1=running     co2=suspended   co3=suspended
036CBF54 脚本1  结束    co1=running     co2=suspended   co3=suspended
036CC01C 脚本2  602     co1=dead        co2=running     co3=suspended
036CC01C 脚本2  结束    co1=dead        co2=running     co3=suspended
036CC0E4 脚本3  1002    co1=dead        co2=dead        co3=running
036CC0E4 脚本3  1503    co1=dead        co2=dead        co3=running
036CC0E4 脚本3  结束    co1=dead        co2=dead        co3=running

--延时 = mylib.delay 的C代码 用C++Builder 6环境
--调用delay时,首先创建1个定时器
  int id = SetTimer(NULL, NULL, ms, (TIMERPROC)LuaTimerProc);
--然后保存协程句柄,定时器id到TList LuaTimerList,到定时器回调时有用
  LuaTimerList->Add((void*)L);
  LuaTimerList->Add((void*)id);
--然后,挂起协程
--时间到了,定时器回调函数运行
--因为定时器只用一次就够了, 故销毁之
    KillTimer(hWnd, uIDEvent);
--在TList LuaTimerList找到对应的记录,获得协程句柄,唤醒之
    lua_resume(L, 0, 0);
--注意, 在dll退出时, 记得销毁LuaTimerList, 不然内存略有泄漏
    case DLL_PROCESS_DETACH:
        delete LuaTimerList;
        break;
--在lua中使用方法, (编译后的库名为mylib.dll)
    mylib = require('mylib')
    mylib.delay(100)  --延时100ms
--函数只能在协程内使用, 在主线程使用会出错
--不过没关系, 可以让所有脚本都在协程运行,按下列方式即可
function f()
--------------------
--这里插入要执行的内容
--------------------
end
co=coroutine.create(f)
coroutine.resume(co)



//---------------------------------------------------------------------------
//Lua扩展库测试

#pragma hdrstop

//---------------------------------------------------------------------------

#pragma package(smart_init)
#include <vcl.h>
#include <math.h>
#include <windows.h>
#include "LuaMylib.h"

TList *LuaTimerList;

//void _stdcall LuaTimerProc(int hwnd, int uMsg, int idEvent, int time)
void   CALLBACK   LuaTimerProc(HWND hWnd, UINT nMsg, UINT uIDEvent, DWORD dwTime)
{
    KillTimer(hWnd, uIDEvent);
    for (int i=(LuaTimerList->Count / 2) -1;i>=0; i--)
    {
        UINT id = (UINT)LuaTimerList->Items[i*2+1];
        if (id == uIDEvent)
        {
            lua_State *L = (lua_State*)LuaTimerList->Items[i*2];
            LuaTimerList->Delete(i*2);
            LuaTimerList->Delete(i*2);
            lua_resume(L, 0, 0);
        }
    }
}

static int delay (lua_State *L) {
  if (lua_gettop(L) == 0) return 0;
  int ms = lua_tointeger(L, 1);
  int id = SetTimer(NULL, NULL, ms, (TIMERPROC)LuaTimerProc);
  if (LuaTimerList == NULL )LuaTimerList = new(TList);
  LuaTimerList->Add((void*)L);
  LuaTimerList->Add((void*)id);
  lua_pop(L, 1);//弹出参数
  return lua_yield(L, 0);
}


static const luaL_Reg mylib[] = {
  {"delay",   delay},
  {NULL, NULL}
};


/*
** Open test library
*/
LUALIB_API int luaopen_mylib (lua_State *L) {
    luaL_newlib(L, mylib);
    return 1;
}

6

主题

3

回帖

11

积分

编程入门

Rank: 1

魔鬼币
50
 楼主| 发表于 2015-10-21 14:19:14 | 显示全部楼层
--C中实现协程
--以脚务器消息接收为例
--编写一个消息处理的函数Lua(伪代码)
function Recv(Recog, Ident, Param, Tag, Series, buf, len)
    --if 定义[Ident] and 定义[Ident].过滤==1 then return end;
    print('收',翻译(Ident,Recog,Param,Series,Tag,len,buf))
    mylib.delay(5000)
    --print('协程结束')
    回收协程()
end

--编写一个消息转发Lua的C函数 相当于Lua下列语句,挂到消息接收上
static _stdcall void SocketRecvHook(int buf, int len)
local co=coroutine.create(recv)
...转化内存数据到变量
coroutine.resume(co, Recog, Ident, Param, Tag, Series, buf, len)
库名.copool=co //必须, 不然协程被当垃圾回收出错, 也可以留在栈里

--如此每收到1个消息就开启1个协程, 所以协程数量增长很快,
--如果协程运行结束, 就要进行回收, 即可在C中编写,也可在LUA中
function 回收协程()
    local 总数=0
    local 回收=0
    for i in pairs(mir.copool) do
        总数 = 总数+1
        if coroutine.status(mir.copool[i])=='dead' then
            mir.copool[i]=nil --垃圾回收器会自动回收该协程
            回收=回收+1
        end
    end
    --if 回收>0 then print('协程总数,回收,剩余=',总数,回收,总数-回收) end
end


--C代码如下
static _stdcall void SocketRecvHook(int buf, int len)
{
    //调用原来的程序
    OrgSocketRecvDecode(buf, len);

    //调用LUA程序
    PTDefaultMessage pm = (PTDefaultMessage)(buf+4);
    //co=coroutine.create(recv)
    lua_getglobal(L, "coroutine");  //--->+1
    lua_getfield(L, -1, "create"); //调用函数coroutine.create//--->+2
    //获得self.recv
    lua_pushlightuserdata(L, (void*)&Key); //压入地址   //--->+3
    lua_gettable(L, LUA_REGISTRYINDEX);//table在栈顶    //--->+4
    lua_getfield(L, -1, "recv"); //self.Recv           //--->+5
    lua_remove(L, -2);//移除table                      //--->+4
    if (lua_isfunction(L, -1))
    {
    lua_call(L, 1, 1);//1个参数,1个结果->co            //--->+2
    //库名.copool=co
    savepool(IntToStr(GetTickCount())+"_R_"+IntToStr(pm->Ident) );
    //coroutine.resume(co,参数)
    lua_getglobal(L, "coroutine");
    lua_getfield(L, -1, "resume"); //调用函数coroutine.resume
    lua_pushvalue(L, -3);//复制co
    lua_pushinteger(L, pm->Recog);//1
    lua_pushinteger(L, pm->Ident);//2
    lua_pushinteger(L, pm->Param);//3
    lua_pushinteger(L, pm->Tag);//4
    lua_pushinteger(L, pm->Series);//5
    lua_pushinteger(L, buf + 16);//6
    lua_pushinteger(L, len - 16);//7
    lua_call(L, 1+7, 0);//1+7个参数,0个结果->co
    lua_pop(L, 3);
    }
    else
    {
        lua_pop(L, 3);
    }
}
您需要登录后才可以回帖 登录 | 点击注册

本版积分规则

魔鬼作坊|易语言教程|易语言源码|易语言论坛|易语言视频教程| 论坛导航|免责申明|手机版||网站地图
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表魔鬼作坊立场!
任何人不得以任何方式翻录、盗版或出售本站视频,一经发现我们将追究其相关责任!
我们一直在努力成为最好的编程论坛!
Copyright© 2010-2019 All Right Reserved.
快速回复 返回顶部 返回列表