一、Lua脚本功能接口

1. LuaInterface.h/.cpp声明和实现LuaInterface。

LuaInterface成员如下:

//脚本引擎

FoxLuaScriptmLua ;

//注册器

LuaCFuncRegistermFuncRegister;

//场景关联

Scene*mOwner;

//已经读取的脚本表

IDTablem_ScriptTable ;

主要方法:

VOIDInit(Scene* pScene);//完成Lua脚本环境的初始化和C导出函数的注册

Scene* GetOwner();

执行Lua脚本的C++接口,提供多达8个参数支持。

INTExeScript( ScriptID_t scriptid, CHAR* funcname ) ;

INTExeScript_D( ScriptID_t scriptid, CHAR* funcname, INT Param0 ) ;

INTExeScript_DD( ScriptID_t scriptid, CHAR* funcname, INT Param0, INT Param1 ) ;

INTExeScript_DDD( ScriptID_t scriptid, CHAR* funcname, INT Param0, INT Param1, INT Param2 ) ;

INTExeScript_DDDD( ScriptID_t scriptid, CHAR* funcname, INT Param0, INT Param1, INT Param2, INT Param3 ) ;

LuaInterface::Init里面会初始化mLua引擎,注册C++提供给Lua脚本的函数(LuaCFuncRegister),并加载ScriptGlobal.lua脚本。

2. LuaCFuncRegister.cpp里面对所有导出到Lua的C++函数进行注册。

struct _Str2Func functbl[] =

{

{"AddEventList",FuncProto(LuaFnAddNumText)},

{"GetMission", FuncProto(LuaFnGetMission)},

{"GetMissionCount", FuncProto(LuaFnGetMissionCount)},

{"SetMissionByIndex", FuncProto(LuaFnSetMissionByIndex)},

{"AddMission", FuncProto(LuaFnAddMission)},

{"AddMissionEx", FuncProto(LuaFnAddMissionEx)},

{"SetMissionEvent", FuncProto(LuaFnSetMissionEvent)},

...

};

这些C++函数的实现是在下列头文件中进行的:

#include "LuaFnTbl_Mission.h"

#include "LuaFnTbl_Misc.h"

#include "LuaFnTbl_Ability.h"

#include "LuaFnTbl_Attr.h"

#include "LuaFnTbl_Pet.h"

#include "LuaFnTbl_Battle.h"

#include "LuaFnTbl_Shop.h"

#include "LuaFnTbl_PetPlacard.h"

#include "LuaFnTbl_Scene.h"

#include "LuaFnTbl_Team.h"

#include "LuaFnTbl_DoAction.h"

#include "LuaFnTbl_Relation.h"

#include "LuaFnTbl_Guild.h"

#include "LuaFnTbl_City.h"

这些函数并不是功能的真正实现地方,真正的实现代码在Scene、Obj_Human等地方。这里只是集中转调而已。

3. 注册完成后,在Lua脚本中就可以使用类似AddMission接口调用C++里面功能。

二、Lua脚本位置

所有脚本在Bin\Public\Data\Script子目录中。

Bin\Public\Data\Script.dat是索引,里面保存了ScriptID和对应的脚本文件名。如:

888888=\scene.lua

888889=\mail.lua

888890=\player_login.lua

...

脚本ID是6位的。

三、脚本索引的初始化

每个场景都会进行脚本初始化,具体是在Scene::Load里面,在在m_pLuaInterface初始化之后。

m_pLuaInterface->Init(this);

if( !m_pScriptFileMgr->IsInit() )

{

m_pScriptFileMgr->Init( FILE_SCRIPT, FALSE);

}

Log::SaveLog( SERVER_LOGFILE, "Load ../Public/Data/script.dat OK!" );

m_pScriptFileMgr->Init将"888888=\scene.lua"拆开,保存ID和文件名到SFileData里面。所有的SFileData用SFileDataLink串起来。

四、脚本加载和调用

每个脚本的调用都是通过INT LuaFnCallScriptFunction(Lua_State* L);来进行的。该函数是一个C++函数,脚本里面调用名是CallScriptFunction,注册如下:

{"CallScriptFunction", FuncProto(LuaFnCallScriptFunction)},

LuaFnCallScriptFunction的实现在文件LuaFnTbl_Misc.h里。

可以看到在,此函数:

l 把SFileData添加到pScene->GetLuaInterface()->m_ScriptTable表里面;

pSFileData = pScene->GetLuaInterface()->GetOwner()->GetScriptFileMgr()->GetFileData(scriptId);

pScene->GetLuaInterface()->m_ScriptTable.Add( scriptId, pSFileData ) ;

l 然后加载脚本;

pScene->GetLuaInterface()->mLua.Load( const_cast<CHAR*>(filename) ) ;

l 最后调用脚本。

五、典型脚本的结构

见ScriptDef.h,定义了一些脚本接口函数,如OnDefaultEvent,对于脚本805007,就是:

function x805007_OnDefaultEvent( sceneId, selfId,targetId );

有一些调用没有在这里定义宏,直接写在C++代码里面,如OnScenePlayerLogin。

#defineDEF_EVENT_ENTRY_FUNC_NAME("OnDefaultEvent")//脚本进入函数

#defineDEF_ON_KILL_OBJECT_FUNC_NAME("OnKillObject")

#defineDEF_ON_ITEM_CHANGED_FUNC_NAME("OnItemChanged")

#defineDEF_ON_PET_CHANGED_FUNC_NAME("OnPetChanged")

#defineDEF_ON_ENTER_AREA_FUNC_NAME("OnEnterArea")

#defineDEF_ON_LEAVE_AREA_FUNC_NAME("OnLeaveArea")

#defineDEF_EVENT_ON_TIMER("OnTimer")

#defineDEF_MISSION_ACCEPT("OnMissionAccept")//接受任务

#defineDEF_MISSION_ABANDON("OnAbandon")//放弃任务

#defineDEF_MISSION_REFUSE("OnMissionRefuse")// 拒绝接受任务

#defineDEF_MISSION_SUBMIT("OnMissionSubmit")//任务完成后,提交任务

#defineDEF_MISSION_CHECK("OnMissionCheck")//任务完成条件检查

#defineDEF_MISSION_CONTINUE("OnMissionContinue")//任务没完成,继续

六、样例分析

大理NPC赵天师脚本分析

脚本名:Script\obj\dali\odali_xinshoutian.lua,汗,居然叫这个名字,找了半天,一般的命名都是拼音。

--赵天师

--脚本号

x002030_g_scriptId = 002030

--所拥有的事件ID列表

x002030_g_eventList={210200,210204,210205,210208,210210,210212,210213,210214,210216,210217,210220,210223, 210224, 210225, 210229, 210230, 210232, 210238, 210239, 210237, 210240, 200080, 200083, 200086, 200091, 200094,200095,210241,050022}

一般情况,每个event对于一个任务,也是一段脚本实现的。如210200对于:

;大理城新手指导任务

210200=\event\dali\edali_zhidao_0200.lua

--找人任务

--赵天师寻找蒲良

NPC脚本触发接口函数是xxx_OnDefaultEvent,在AI_Human的PushCommand_DefaultEvent里面触发。

ORESULT PushCommand_DefaultEvent( ObjID_t idNPC );

pCharacter->getScene()->GetLuaInterface()->ExeScript_DDD(

idScript,

DEF_EVENT_ENTRY_FUNC_NAME,

(INT)pCharacter->getScene()->SceneID(),

(INT)pCharacter->GetID(),

(INT)pNPC->GetID() ) ;

[转]天龙八部服务器端Lua脚本系统的更多相关文章

  1. 使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  2. Redis进阶实践之十九 Redis如何使用lua脚本

    一.引言               redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入 ...

  3. Redis Lua 脚本使用

    本文转载自Redis Lua 脚本使用 Lua 简介 Lua语言提供了如下几种数据类型:booleans(布尔).numbers(数值).strings(字符串).tables(表格). 下面是一些 ...

  4. redis原子性读写操作之LUA脚本和watch机制

    最近在开发电商平台的子系统--储值卡系统,系统核心业务涉及到金额消费以及库存控制,因此为了解决建立在内存上高并发情况下的事务控制,使用了spring封装的RedisTemplate执行lua脚本进行原 ...

  5. Redis Lua脚本原理

    2.6版本之后支持嵌入Lua脚本,客户端使用Lua脚本,直接在服务器端原子的执行多条命令 Lua脚本执行过程 创建并修改Lua环境 1 创建基础Lua环境 2 载入函数库 3 创建全局表格Lua 4 ...

  6. redis之lua脚本

    背景介绍 redis数据库提供了一些管理功能比如 流水线:打包发送多条命令,并在一个回复里面接收所有被执行命令的结果.事务:一次执行多条命令,被执行的命令要么就全部都被执行,要么就一个也不执行.并且事 ...

  7. Java调用Lua脚本(LuaJava使用、安装及Linux安装编译)

    依赖包(附件有下载): 包名 类型 操作系统 luajava-1.1.jar jar ALL libluajava-1.1.so .so linux luajava-1.1.dll .dll wind ...

  8. Redis学习-LUA脚本

    最近在做K线的项目中,需要计算商品的分时数据.为了保证多台机器对同一商品的计算的有序性,所以在Redis中进行计算,同时为了保证在分时数据计算过程的原子性所以使用了LUA脚本,Redis内置了对LUA ...

  9. 基于Lua脚本解决实时数据处理流程中的关键问题

    摘要 在处理实时数据的过程中需要缓存的参与,由于在更新实时数据时并发处理的特点,因此在更新实时数据时经常产生新老数据相互覆盖的情况,针对这个情况调查了Redis事务和Lua脚本后,发现Redis事务并 ...

随机推荐

  1. C++:析构函数

    析构函数的特点: 1.析构函数与类名相同,但它前面必须加上波浪号~ 2.析构函数不返回任何值,在定义析构函数时,是不能说明它的类型的,甚至说明void类型也不能 3.析构函数没有参数,因此不能被重载. ...

  2. pinyin4j

    最近在倒腾与搜索相关的拼音检查技术,顺便看了一下中文转拼音开源插件pinyin4j的源码,参考资料:http://blog.csdn.net/hfhwfw/archive/2010/11/23/603 ...

  3. 实例学习写Makefile文件

    目录 0. 扫盲 1. 编译,链接 2. Makefile文件执行 3. Makefile书写规则 4. 案例 5. Makefile是如何工作的 6. 拔高,参考 0. 扫盲 Linux 环境下的程 ...

  4. C/C++技巧

    C中如何调用C++函数 将 C++ 函数声明为``extern "C"''(在你的 C++ 代码里做这个声明),然后调用它(在你的 C 或者 C++ 代码里调用).例如: // C ...

  5. Java开发工具MyEclipse的设置自动联想功能

    最近初学Java,正在使用MyEclipse来编写新的项目,刚开始打开MyEclipse感觉这个工具既陌生又熟悉,熟悉之处在于编辑器的几大共通之处它都具备,比如说基本的设置.编辑区.调试区都是类似的, ...

  6. MTK6577+Android4.04编译

    MTK6577+Android4.04编译 编译命令 ./mk new 出错信息如下: **********checkingEnv************ Your building environm ...

  7. 函数fsp_get_space_header

    /**********************************************************************//** Gets a pointer to the sp ...

  8. Qt之进程间通信(共享内存)

    简述 上一节中,我们分享下如何利用Windows消息机制来进行不同进程间的通信.但是有很多局限性,比如:不能跨平台,而且必须两个进程同时存在才可以,要么进程A发了消息谁接收呢? 下面我们来分享另外一种 ...

  9. Java Web编程的主要组件技术——Struts入门

    参考书籍:<J2EE开源编程精要15讲> Struts是一个开源的Java Web框架,很好地实现了MVC设计模式.通过一个配置文件,把各个层面的应用组件联系起来,使组件在程序层面联系较少 ...

  10. [Sciter系列] MFC下的Sciter–2.Sciter中的事件,tiscript,语法

    [Sciter系列] MFC下的Sciter–2.Sciter中的事件,tiscript,CSS部分自觉学习,重点说明Tiscript部分的常见语法和事件用法. 本系列文章的目的就是一步步构建出一个功 ...