插件是一种遵循一定规范的应用程序接口编写出来的程序。
由于一个大型软件通常只由一家软件公司开发,在开发过程中,由于人手和时间的限制,这就决定了软件自身功能的局限性,而且软件的更新速度也是较为缓慢的,也不能满足
所有的用户需求。正是处于这样的考虑,通常一些大型的软件都提供了调用外部插件程序的接口。这样一来,通过别人的插件使得自己的软件在功能和更新速度上都大大得到改
善,同时使用者可以根据自己的需求来制作一些更适用于自己使用环境的插件程序。
游戏中的插件和外挂是两个不同的概念,游戏外挂通常是通过修改游戏运行时的数据,包括网络通信、本机内存等方式欺骗服务器,让外挂使用者达到不劳而获的目的。
而游戏插件是游戏开发者允许的,在一定限制下的改善游戏内容,比如界面显示、操作方式、或者为使用者提供方便功能,并不直接修改游戏数据的程序。游戏插件都只能运行
在客户端。
剑三中插件能做什么
前面已经提到过,游戏插件都是运行在客户端的,也就是说我们通过客户端可以做的事情,理论上通过插件都可以做到。为了不影响游戏的正常运行,通常开发者都会对游戏插
件做出一些限制、下面整理一下剑三中,插件所被允许做的事情。
1、
改善用户界面(UI)
例如常用的头顶增强、战斗提示、气条拖动、Buff、Debuff缩放、弧形血条等。
2、
改善游戏操作
例如拾取助手、自动Roll取绿装、自动贩卖灰色物品等。
3、提供游戏开发者允许,但又没有提供的功能。
例如仇恨插件、任务指引、焦点目标、技能CD提示等。
3、
其他不影响游戏数据的你能想到的任何东西。
例如小游戏插件。
插件的安装
在剑三的安装目录下的interface文件夹中放入你需要安装的插件,登录游戏,在人物选择界面右侧点击插件管理,勾选上你想加载的插件,这样在你进入游戏,游戏程序就会
去调用相应的插件程序了。
以我的电脑为例,安装从多玩论坛下载的 弧形血条插件 我的剑三安装在D:\ProgramFiles\Kingsoft\JX3\ 目录下面。
进入D:\Program Files\Kingsoft\JX3\ 目录,找到interface文件夹。如果没有这个文件夹,直接新建文件夹并命名为interface即可。
解压下载到的headEx.rar文件,得到一个HeadEx的文件夹,文件夹里包含了HeadEx.lua 、info.ini、LEOConst_HeadEx.ini等文件,将HeadEx文件夹放入到interface文件夹
中,进入游戏,在任务选择画面点击插件管理,勾选弧形血条插件,进入游戏后就可以看见插件了。
很多人在安装插件时发现将插件文件放入了interface文件夹下,但在游戏中的插件管理中看不到自己下载的插件,这样的问题通常是因为在解压插件文件的过程中,多产生了
一级目录。
例如弧形血条插件中包含info.ini文件,这个文件应该处于的位置是Interface\HeadEx\info.ini
而有的使用者在解压时直接将HeadEx下的文件解压到了interface中,或者在interface下的HeadEx文件夹中又创建的HeadEx文件夹,造成了如下的一些目录情况,这些都是不能
运行插件的。
Interface\info.ini
Interface\HeadEx\ HeadEx \info.ini
学习制作插件需要哪些基础和工具
简单Lua编程,包括lua基本语法,table的概念,函数的概念,面向对象的基础概念。
工具上剑三客户端当然是不能少啦,剩下就是lua语言的编辑环境,最简单的就是txt文档编辑器来,一般我们还是习惯使用一些特殊的编辑器,比如UEStidio,NotePad++,这
些支持语法高亮的编辑器。
另外为了方便检查脚本错误,还需要使用luaforwindows的可执行文件。可以到lua的官方网站去下载 (http://code.google.com/p/luaforwindows/)
剑三插件的组成
首先,剑三中的游戏插件是一个程序,那么我们肯定是需要一个文件来保存程序的代码。其次,插件程序是不可以脱离游戏独立运行的,它必须依赖于游戏程序,
那么我们需要一种方式来告诉游戏程序,这个插件是干什么的,应该从哪开始执行这个插件程序,这个文件在剑三中就是info.ini文件。
最后,由于在游戏中通常会运行很多个插件,那么这么多info.ini就会十分的混乱,为了方便管理,降低每个插件与其他插件的耦合度,剑三有这样一个规则,
插件必须放在一个文件夹中,文件夹中必须有一个info.ini文件。并且ini文件中必须有一个Section名为文件夹名字。(一个Section就是INI文件中用中括号分割的一段区域,
具体详见Windows INI文件格式)
综上,剑三插件的基本结构有以下5点:
1、需要一个文件夹、至少一个程序文件、一个info.ini文件。
2、info.ini文件必须在这个文件夹中。
3、info.ini文件中的Section名必须为这个文件夹的文字。
4、info.ini文件中必须指明需要运行的程序文件的路径与名称。
5、info.ini文件中所指明的程序文件不能直接放在interface目录下,必须在其子目录中
从上面这五点中可以得到这样一些隐含信息:
info文件所指明的程序文件不必要和info在同一级目录下。
Info中可以有多个Section,但由于Section名和文件夹名不相同,所以多余的Section并不起作用,且不影响正常的Section工作。
Info文件中指明的程序文件可以有多个,随其编号决定调用顺序,编号越小越先调用。
info指明的程序文件不需要是lua的扩展名,只要是lua程序文件,可以是任意扩展名。
Info文件只能在interface目录的直接子目录下,比如 interface\HeadEx,不能是interface\a\b\info.ini
Info.ini文件中的注释符号使用【#】,具体配置项如下所示:
- [Const_GettingStarted]
- #插件名,和文件夹名相同
- name=准备开始
- #在插件管理栏显示的插件名
- desc=描述怎样开始制作剑三插件。 --By 奶舟
- #在插件管理栏名称后面跟随的插件描述
- default=1
- #是否默认加载插件
- version=0.3
- #插件对应的系统版本号
- #=================下面是入口程序文件路径====================
- lua_0=Interface\Const_GettingStarted\Main.lua
- lua_1=Interface\Const_GettingStarted\Data.dat
Info中的配置对应游戏中的显示界面:
当我们指定的系统插件版本号低于右上角显示的系统版本号时,插件将变成灰色,这表示官方对插件的一些设置、开放的接口作出了调整,可能你所编写的插件在该版本下不能正常使用,我们可以通过勾选下面的允许加载过期插件来强制运行它,但是不一定可以正常工作哦。
通常我们为了编写和管理插件的方便,有这样一些约定俗成的规矩。
1、为你的插件新建一个文件夹,文件夹的名字尽量做到见即知意。
2、 为了避免和别的插件冲突,在你的文件夹前加一个自己的前缀,比如Const_HeadEx。
3、将你的插件入口程序和info.ini文件放到同一目录下。
4、在你的程序文件第一行首先定义一个table,这个table的名字是你插件的名字,用于存储所有与你插件相关的信息。
5、所有的函数、属性、都写在自己定义的table中。
6、在程序文件的最后一行调用你的入口函数。
7、将界面配置文件和对应的程序文件取相同的文件名。
剑三插件的HelloWorld
下面开始我们进入剑三插件的Hello World程序,哈哈哈哈。
1、首先在剑三目录下的interface中建立一个My_InterFaceTest文件夹
2、在Interface文件夹中建立一个info.ini文件和Main.lua文件。
3、在info.ini文件中输入以下内容:
- [My_InterFaceTest]
- name=我的HelloWorld
- desc=第一个插件
- version=0.4
- lua_0=Interface\My_InterFaceTest\Main.lua
- Output("Hello World")
5、进入游戏,在插件管理界面勾选我的
6、进入游戏就可以看到聊天框里出现了这些文字。
到这里我们的HelloWorld就完成了,下面将进一步介绍插件的制作,从这里开始就需要程序基础了。
剑三插件用到的部分对象简介
Player对象
Player对象是玩家自己,是玩家所有属性的一个集合,这里有我们常用的一些属性。我们可以通过全局函数GetClientPlayer()来获得它。
szName | 名字 | 字符串 | 属性 |
nGender | 性别 | 整型 | 属性 |
nLevel | 等级 | 整型 | 属性 |
nFaceDirection | 朝向 | 整型 | 属性 |
nX | X坐标 | 整型 | 属性 |
nZ | Z坐标 | 整型 | 属性 |
nCurrentMana | 当前内力值 | 整型 | 属性 |
nCurrentLife | 当前生命值 | 整型 | 属性 |
nCamp | 阵营 | 整型 | 属性 |
HideHat() | 隐藏帽子 | 无返回 | 参数1:【b】是否隐藏 |
GetTarget() | 获取当前目标 | 返回1:目标类型 返回2:目标ID | 无参数 |
NPC对象 表示一个指定的NPC。可以使用全局函数GetNpc(dwID)来获得它。 [table] | |||
dwTemplateID | NPC模板ID | 双字 | 属性 |
nLevel | 等级 | 整型 | 属性 |
player相同。 |
剑三插件的基本接口介绍
GetClientPlayer()
获取本机的player对象。
GetNpc(dw)
获取npc对象,参数为NPCID。
GetPlayer(dw)
获取一个player对象,参数为playerID。
GetDoodad(dw)
获取一个Doodad对象,参数为doodad的ID
RegisterEvent(sz,function)
注册一个客户端事件,可以在Event()函数中响应它。参数为事件名,响应时间的函数。当它作为一个全局函数使用的时候,由于脚本程序是由上至下逐行解释的,所以一定要把响应事件的函数定义在它的前面。
RegisterCustomData(sz)
注册一个用户数据,参数是数据名。
剑三插件的基本事件介绍
通常事件在响应时,会向相应的函数传递一些事件相关的信息,这些信息存在叫arg0~arg9的变量里,我们可以直接在事件响应函数中访问到它们。
1、插件本身的事件:
OnFrameCreate()
OnFrameBreathe()
上面这两个事件实际上是两个函数,当遇到插件创建事件时会调用OnFrameCreate()。一般在没有特殊设置的情况下,当界面窗口可见时,会每秒调用16次OnFrameBreathe()函数。
2、客户端相关事件:
UI_SCALED
当UI进行缩放的时候会激发这个事件。
CUSTOM_DATA_LOADED
当用户数据读取完毕的时候会激发这个事件。
3、游戏角色相关事件:
BUFF_UPDATE
玩家角色Buff更新的时候会激发这个事件。
MONEY_UPDATE
玩家角色金钱变化时会激发这个事件。
SYNC_ROLE_DATA_END
玩家角色数据同步完成会激发这个事件。
BAG_ITEM_UPDATE
玩家角色背包里的物品变化会激发这个事件。
EQUIP_ITEM_UPDATE
玩家角色装备变化会激发这个事件。
PLAYER_STATE_UPDATE
玩家角色状态变化会激发这个事件。
PLAYER_LEVEL_UPDATE
玩家角色等级变化会激发这个事件。
PARTY_SYNC_MEMBER_DATA
玩家角色数据同步时会激发这个事件。
FIGHT_HINT
角色受到攻击时会激发这个事件。
PLAYER_ENTER_SCENE
玩家角色进入可视范围内会激发这个事件。
PLAYER_DEATH
玩家角色死亡会激发这个事件。
PLAYER_LEAVE_SCENE
玩家角色离开可视范围会激发这个事件。
PLAYER_REVIVE
玩家角色复活会激发这个事件。
SYNC_LOOT_LIST
玩家角色同步拾取列表后会激发这个事件。
4、NPC相关事件
NPC_STATE_UPDATE
NPC状态变化会激发这个事件。
NPC_LEAVE_SCENE
NPC离开可视范围会激发这个事件。
5、任务相关事件
QUEST_ACCEPTED
玩家角色接受任务会激发这个事件。
QUEST_FAILED
玩家角色任务失败会激发这个事件。
QUEST_CANCELED
玩家角色放弃任务会激发这个事件。
QUEST_FINISHED
玩家角色完成任务会激发这个事件。
QUEST_SHARED
玩家角色共享任务会激发这个事件。
QUEST_DATA_UPDATE
玩家角色任务数据变化会激发这个事件。
剑三插件的简单小实例
现在我需要这样一个辅助功能,我想在每次我接到任务的时候,在我近聊频道说这样一句话“我接到一个任务,这个任务是[XXXXX]”,点击这个任务名就可以调出相关的任务信息。
分析这个需求我们发现,这个插件需要在接受任务时调用,那么我们就需要QUEST_ACCEPTED这个事件,当这个事件被激发,我们要让玩家角色说一句话,那么就需要用到player对象的Talk方法。获取player对象就是使用GetClientPlayer()函数。
通过对arg0~arg9这些参数的输出观察,发现当响应QUEST_ACCEPTED事件时参数arg1的值是任务ID,这样就得到了所有需要的内容。
还是使用上面My_InterFaceTest的例子,按照约定的规范来编写这个插件,在Main.lua文件中输入以下内容:
- My_InterFaceTest = {}
- function My_InterFaceTest.OnAcceptedQuest()
- local player = GetClientPlayer()
- local tSay = {
- {type = "text", text = "我接到一个任务,这个任务是"},
- {type = "quest", questid = arg1},
- }
- player.Talk(1,"",tSay)
- end
- RegisterEvent("QUEST_ACCEPTED", My_InterFaceTest.OnAcceptedQuest)
加载这个插件后进入游戏,我们就可以看到这样的结果了: