操作原理(一)
服务端:服务器源文件
客户端:客户所操作的程序(既是游戏客户端)
接口:既是某项功能(例如:鼠标点击,文字发送,战斗,观战,人物动作等)返回的值
ABlua:在源代码中添加的整套引擎作为回调接口
--
lua所实现的功能是基于服务端源码添加的接口
由该接口与客户端发送封包实现功能
源码里是否有ABlua回调接口?
例如:源码里的gmsv/battle.c文件(既是战斗回调文件)
以下为简单描述C给予lua接口过程
BATTLE_WatchEntry ( ) 函数 (函数:利用括号里的值得出不同结果) --这里称它为函数A
即为客户端点击观战按钮所发送给服务器的封包 括号里的参数即为客户端封包发送的内容
charaindex=我自己 todindex=对方 (这两个参数是由玩家登陆服务器时所得到)
服务器要回调给客户端,必须由这个函数A的值所决定
利用客户端发送的两个参数进行判断(int为整数,所以二者都是整数)
而函数A 前面的int 意味着 这个函数最后的结果为 函数A == 整数
在这里不讲解过程 结果为如果 函数A == 0 则不允许观战,如果 函数A==1则 进入观战
可以看到下面 ifdef里 函数A 的结果 交给了 ABlua 的 BattleWatch() 函数 --在这里称它为函数B
函数A 的 charaindex和toindex 两个参数 也赋予了函数B 最后让ABlua去进行判断 让函数B的值去赋予函数A
实现函数B 即为ABlua回调接口,必须在\gmsv\mylua源码里添加
这样观战的接口既可用lua去实现
以上叙述是简单描述Ablua原理,并非添加接口的方法
简介(二)
Lua是什么? ABlua是什么?
Lua是一门语言,ABlua是在源码里用C语言写的接口,该接口给予lua文件去调试
为什么用Lua?
Lua是基于接口拓展的一个方式,实现便捷更新,修改
源码C可以直接实现所有操作,并创作功能.而Lua的诞生是让更多人能够轻易接触
会Lua一定可以写石器lua?
Noooo~
Lua是一门语言,石器Lua是石器源码所写的接口,接口反还的值是需要去独个学习并了解的
代码的唯一标准排第一永远是基于对游戏的了解程度,游戏的操作方式
再是语言基础与逻辑思考
什么是Bug?如何避免Bug?
没有在关键的步骤做到决定性的判断,这就是上个问题中对游戏了解程度起到了关键性的作用
只有不同角度去思考如何做到最好的判断,这世界上没有完整的代码,只有更完善的代码
如果你不懂得Lua的运作过程,那打开后如同一篇外语文章,你看到的,只会是里面的阿拉伯数字
很多人学习lua的时候遇到同一个问题,这个英文是不是要硬记它是什么意思,代表什么
其实,并非如此
你看到的英文,除了接口,不是函数,就是变量
运作过程(三)
相信已经有不少人看过Lua后得出的结论
哪里是开头?哪里是结束?什么时候才用到这个文件?
是每个玩家都在用?排队用?还是一起用?
答案: 在服务器启动时,优先从函数main()启动和结束
在上图函数 main() 里 多了Create这个函数
这时脚本会运行到函数 Create() 处
函数main()里Create括号里的参数 --"测试",100000,2000,58,56,6
就是函数 Create() 括号里的变量 --name, metamo, floor, x, y, dir
既然是变量,这些名字也就是自己决定,并非是固定(函数名也不是固定的)如下图
脚本运行到函数 Create()后 触发了ABlua接口的npc.CreatNpc
并发送这6个参数到服务端,在2000地图,58,56坐标创立了名字为"测试",方向为6 的NPC
函数 Create() end 结束后 返回函数main() 并以end结束
实践与运用(四)
在第三章提到npc.CreateNpc
CreateNpc是npc库中的一个接口 (具体请查看\gmsv\mylua\npcbase.c文件)
上图为npc库接口
在第三章知道如何服务器启动后生成NPC
下面内容是如何与创造的NPC之间传送封包
在接口npc.Createnpc()生成后,它得到一个整数值
这个整数就代表NPC编号,除非服务器重启再次执行一次
npc.Createnpc(), 否者该编号不会改变
人物,宠物和NPC都是一样,每一次登录,都会得到一个编号
这个编号一定是大于0的整数,直到登出后编号消失
上图的变量npcindex = npc.Createnpc()
既是npcindex=NPC编号, 再由char.setFunctionPointer() --给对象设定一个事件
给NPC设定事件 char.setFunctionPointer(对像索引,事件标志,函数名,路径)
npcindex已知是NPC的编号
上图的 "1" 对应的是一个常量(事件标签) -- 常量,即是不会改变的量,事件标签的常量分别有 初始化事件 循环事件 对话事件 窗口事件 重叠事件 战后事件 等
"2"对应 函数名 --既然是函数,函数名称也就允许自拟
"3"对应的是该函数的路径 --如果 function WndowTalked 这个函数不是写在该文件 需要把路径写上 否则默认为该文件
之后,只要有玩家与npc对话,就会触动函数Talked()
为了更好理解脚本的自拟性 这里把函数Talked名改为 "shuohua" npcindex 改为npc
在函数shuohua()里有4个参数 --参数名字可自拟
meindex = npc (npc编号) --整数型
talkerindex = "说话的人"(即为玩家编号) --整数型
SzMes = 说话内容 -- 字符型
color = 说话颜色 --整数型
这里的用到了npc库里的isFaceToFace --注意接口一定要按照大小写
这个接口意味着,必须面对面与NPC对话,得到的值才等于1
这个值得到的是1 则执行print ("测试") 服务器会打印出 测试
如果不是1 则直接结束
常量,为源码固定的量,比如 "攻击" "防御" "声望" "活力" 等
格式,接口所用到的参数,格式必须正确
如: npc.isFaceToFace(meindex,talkerindex)
如果接口错误,则服务器会提示读取错误
如果参数错误(参数名写错),参数未被定义
在接口处直接结束,源码检测 该接口必须以2个整数形式取值
封包发送与接收(五)
接着上一章 与NPC对话已成立只需修改对话框内容与发送封包到客户端即可
这里用到了lssproto库里的windows --向客户端发送一个窗口封包
lssproto.windows(talkerindex, "对话框", "确定|取消", 0, char.getWorkInt( meindex, "对象"), "内容");
上图的 0,12,0 代表 0--"对话框" 12-- "确定|取消" 0 -- 封包号(key)
这时无论是按下 确定 或者 取消, lssproto.windows都会发送参数到function WindowTalked ()
function WindowTalked ( meindex, talkerindex, seqno, select, data)
sqno = key select = 按钮常量值 data = 发送内容 -- "确定"常量值=4 "取消"常量值=8
对话后 第一次"确定",给予key0, 赋予了seqno
在seqno==0处再次按"确定",key1 赋予seqno
语言的工作过程必须按照格式
在seqno == 0 按下"确定"后 只选择了if 并没有选择elseif
所以if的过程让key=1 ,然后end,赋予seqno
再次从 funtion WindowTalked()开头运行 才回到 seqno == 1
再最后的对话框 key=-1 ,赋予seqno后 并没找到 seqno==-1的判断,所以关闭对话框
PS
如果按"取消"和"确定"一样会发送key,所以要用select的值进行判断
当按下按钮后,按钮常量值会赋予select, "取消"的常量值为8,只要判断当按下"取消"时返回即可