[转]天龙八部服务器端Lua脚本系统
一、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脚本系统的更多相关文章
- 使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍
一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...
- Redis进阶实践之十九 Redis如何使用lua脚本
一.引言 redis学了一段时间了,基本的东西都没问题了.从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入 ...
- Redis Lua 脚本使用
本文转载自Redis Lua 脚本使用 Lua 简介 Lua语言提供了如下几种数据类型:booleans(布尔).numbers(数值).strings(字符串).tables(表格). 下面是一些 ...
- redis原子性读写操作之LUA脚本和watch机制
最近在开发电商平台的子系统--储值卡系统,系统核心业务涉及到金额消费以及库存控制,因此为了解决建立在内存上高并发情况下的事务控制,使用了spring封装的RedisTemplate执行lua脚本进行原 ...
- Redis Lua脚本原理
2.6版本之后支持嵌入Lua脚本,客户端使用Lua脚本,直接在服务器端原子的执行多条命令 Lua脚本执行过程 创建并修改Lua环境 1 创建基础Lua环境 2 载入函数库 3 创建全局表格Lua 4 ...
- redis之lua脚本
背景介绍 redis数据库提供了一些管理功能比如 流水线:打包发送多条命令,并在一个回复里面接收所有被执行命令的结果.事务:一次执行多条命令,被执行的命令要么就全部都被执行,要么就一个也不执行.并且事 ...
- Java调用Lua脚本(LuaJava使用、安装及Linux安装编译)
依赖包(附件有下载): 包名 类型 操作系统 luajava-1.1.jar jar ALL libluajava-1.1.so .so linux luajava-1.1.dll .dll wind ...
- Redis学习-LUA脚本
最近在做K线的项目中,需要计算商品的分时数据.为了保证多台机器对同一商品的计算的有序性,所以在Redis中进行计算,同时为了保证在分时数据计算过程的原子性所以使用了LUA脚本,Redis内置了对LUA ...
- 基于Lua脚本解决实时数据处理流程中的关键问题
摘要 在处理实时数据的过程中需要缓存的参与,由于在更新实时数据时并发处理的特点,因此在更新实时数据时经常产生新老数据相互覆盖的情况,针对这个情况调查了Redis事务和Lua脚本后,发现Redis事务并 ...
随机推荐
- Android Handler传递参数动态更新UI界面demo
package com.example.demo_test; import android.app.Activity; import android.os.Bundle; import android ...
- Intellij IDEA 创建消息驱动Bean - 接收JMS消息
除了同步方式的调用之外,有时还需要异步调用,用来处理不需要即时处理的信息,例如短信.邮件等,这需要使用EJB中的独特组件——消息驱动Bean(Message-Driven Bean,MDB),它提供了 ...
- java类的加载以及初始化顺序
类的加载和初始化的了解对于我们对编程的理解有很大帮助,最近在看类的记载方面的问题.从网上查阅了若干文章,现总结如下: 我们通过一段代码来了解类加载和初始化的顺序: package com.classl ...
- python中的MySQL数据库操作 连接 插入 查询 更新 操作
MySQL数据库 就数据库而言,连接之后就要对其操作.但是,目前那个名字叫做qiwsirtest的数据仅仅是空架子,没有什么可操作的,要操作它,就必须在里面建立“表”,什么是数据库的表呢?下面摘抄自维 ...
- ListView(2)最简单的上拉刷新,下拉刷新
最简单的上拉刷新和下拉刷新,当listview滚动到底部时向上拉刷新数据.当listview滚动到最顶部时下拉刷新. 图1,上拉刷新 图2,下拉刷新 1,设置lisview,加载heade ...
- Java连接MySQL数据库及简单操作代码
1.Java连接MySQL数据库 Java连接MySql需要下载JDBC驱动MySQL-connector-java-5.0.5.zip(举例,现有新版本).然后将其解压缩到任一目录.我是解压到D盘, ...
- input默认提示取消
input 输入框有提示功能,当你之前输入过一些内容,你下次打入相关字符的时候,默认会有之前输入的一些相关的字符的提示,这个提示一般来说还是很好的,但是,有时候,我们想自己输入,不想要提示. 如果不需 ...
- 关于BigDecimal的四舍五入和截断 (2007-08-10 15:06:26)
关于四舍五入:ROUND_HALF_UP: 遇到.5的情况时往上近似,例: 1.5 ->;2ROUND_HALF_DOWN : 遇到.5的情况时往下近似,例: 1.5 ->;1 BigDe ...
- POJ1037A decorative fence(好dp)
1037 带点组合的东西吧 黑书P257 其实我没看懂它写的嘛玩意儿 这题还是挺不错的 一个模糊的思路可能会好想一些 就是大体的递推方程 dp1[][]表示降序 dp2[][]表示升序 数组的含义为长 ...
- bzoj1063
仔细观察可以发现,这个规划路径很像树链剖分 树链剖分的经典定理:任意一个点到根的所经过轻边不超过logn 而这个规划路径所走公路相当于轻边,也就是说,不便利度不会很大 那么直接dp即可,设f[x,i, ...