首页 > 技术文章 > 插件开发入门

not2 2019-12-23 11:21 原文

一、准备工作

(1)查阅

WowWiki: 提供了大量有用的WOW API,其中最重要的有

(2)工具

WowLua: 游戏内Lua编辑器

SciTE: Lua编辑器


二、Lua语法

(1)数据类型

  • nil 空
  • boolean 布尔值, 0为true
  • number 数字
  • string 字符串
  • userdata 没看懂
  • function 函数
  • thread 线程,wow插件开发用不到
  • table lua最强大数据类型,lua无array和map之分,统一使用table,index从1开始,不是0开始

(2)运算符

  • +(加) 
  • -(减) 
  • *(乘) 
  • /(除) 
  • ^(幂) 
  • %(取模)
  • and(与)
  • or(或)
  • not(非)

(3)关系运算符

  • ==(等于)
  • ~=(不等于)
  • >(大于)
  • >=(大于等于)
  • <(小于)
  • <=(小于等于)

(4)局部变量和全局变量

do
    a=1 --全局变量
    local b=2 --local 代表局部变量,仅限在此do-end代码块内可见
end
print(a)-->1
print(b)-->nil,这里无法使用上面的"local b"

(5)控制语句

 if-else

if( a == 10 ) then
   print("a 的值为 10" )
elseif( a == 20 ) then  
   print("a 的值为 20" )
elseif( a == 30 ) then
   print("a 的值为 30" )
else
   print("没有匹配 a 的值" )
end

while

local i = 1
while a[i] do
    print(a[i])
    i = i + 1
end

for

for i = 1, 3 do
    print(i)
end

for k, v in pairs(t) do
    print(k, v)
end

repeat...until

a = 10
repeat
   print("a的值为:", a)
   a = a + 1
until( a > 15 )

goto

goto quit
print('come on')
::quit::
print('quit')

--这里只输出quit

(6)函数

定义函数

function GetPlayerPosition(unit)
    if unit=="player" then
        return 1,2,3
    end
end

local x,y,z = GetPlayerPosition("player") --lua可以有多个返回值

匿名函数

local x,y,z = function(unit) --不定义函数,直接使用函数体赋值
    if unit=="player" then
        return 1,2,3
    end
end

print(x,y,z)

可变参数函数

--使用...关键字
function variable(...)
    local a={...}--接收可变参数
    print(#a)--获取a的个数
end

variable(1,2)-->2
variable(4,3,2,4,5)-->5
variable()-->0 

(7)数据库

math

math.abs(x) --绝对值
math.ceil(x) -- 向上取整
math.max(x1,x2,...) --最大值
math.min(x1,x2,...) --最小值
math.random(x, y) --x y之间随机值
math.pi --3.1415926...

string

string.byte(str, start, end) --获取start到end 字节流
string.find(str, pattern, start, plain) --查找,plain表示是否识别为正则表达式
string.format(str, ...) --格式化
string.len(str) --获取长度
string.match(str, pattern, start) --正则查找

table

table.concat(tb1, sep, i, j)  --sep是元素分割符,默认"";i起始坐标,默认1;j结束坐标,默认#tb1
table.insert(tb1, position, value) --向tb1插入元素value到position
table.sort(tb1, func) --排序,且只作用于array部分,对hash table部分无效,func是比较函数,默认是<
table.remove(tb1, position) --删除position位置元素
table.maxn(tb1) --返回最大指针,同时作用于hash table部分(key 为number?)

debug

debug.traceback() --打印堆栈

os

os.date(format, time) --日期,默认格式mm/dd/yy hh:mm:ss 
os.difftime(time1, time2) --time2 - time1
os.time() --Unix 时间

 

(8)正则表达式

符号匹配
^ 行首
$ 行尾
. 所有字符
%a 字母
%c 控制字符(\t, \n ...)
%d 数字
%l 小写字母
%p 标点符号(, .)
%s 空格(空格,制表符)
%u 大写字母
%w 字母和数字(0,1,a,A...)
%x 十六进制(0,1,a,A,f,F...)

 

local str = "Hello, World! 123"
print(str:match("%w*")) --> Hello 

 


三、一个例子

(1)文件结构

一个Wow插件实际上就是一个包含若干文件的文件夹,只需要将文件夹拷贝到World of Warcraft/_classic_/Interface/AddOns目录下,游戏启动时就会自动加载该插件。

一个Wow插件至少包含一个toc文件和若干lua文件,其中

  • toc是配置文件,与文件夹同名
  • lua是插件代码文件,包含插件业务逻

以HelloWorld插件为例

 

HelloWorld.toc为配置文件,toc文件格式分两部分:以##开头的是配置项;其他是需要加载的程序文件

##Interface: 10200 (适用于Wow1.2.x版本)
##Title: Hello,World! (插件名)
##Title-zhCN: 一个插件 (插件中文名)
##Notes: a simple debug addon! (简介)
##X-Category: Pet (自定义配置项)
HelloWorld.lua (lua文件)

toc完整的配置项如下,也可以自定义配置项(如上,以"X-"开头)

## Interface: 适用的魔兽版本号
## Title: 显示的标题(默认语言)
## Notes: 显示的说明(默认语言)
## Title-zhCN: 特定语言的标题(简体中文)
## Notes-zhCN: 特定语言的说明(简体中文)
## Author: 作者
## Version: 版本
## eMail: 邮箱
## UIType: 插件类型
## Dependencies: 依赖的插件
## RequiredDeps: 必须依赖的其他插件
## OptionalDeps: 可选倚赖
## SavedVariables: 统一存放的变量,用于数据持久化
## SavedVariablesPerCharacter: 按角色存放的变量
## LoadOnDemand: 0 启动时加载;1 调用时加载
## LoadWith: 当指定插件加载时才加载,前提是调用时加载
## DefaultState:  默认是否可用
## Secure: Blizzard签名插件

Script.lua -- 脚本文件

Layout.xml -- 布局文件

(2)编写Lua代码

lua是代码文件,通过调用Wow API来完成我们想要的功能。

以HelloWorld插件为例,我们希望在适当的时候存入一些key-value数值对,并且随时可以通过key提取对应的value值:

HelloWorld_Text = {}  --定义一个table,用于存储数值对
local channel = "SAY"  --定义一个本地变量,代表数据将要发送的聊天频道

SLASH_HELLO_WORLD_ADD1 = "/hwadd"  --定义一个Slash命令
SLASH_HELLO_WORLD_ADD2 = "/helloworldadd"  --别名
SlashCmdList["HELLO_WORLD_ADD"] = function(msg)  --指定Slash命令处理器
    local id, text = msg:match("(%S+)%s+(.+)")  --提取key, value
    if id and text then  --key和value不为nil
        HelloWorld_Text[id:lower()] = text  --存入table
    end
end

SLASH_HELLO_WORLD_SHOW1 = "/hwshow"  --定义另一个Slash命令
SLASH_HELLO_WORLD_SHOW2 = "/helloworldshow"  --别名
SlashCmdList["HELLO_WORLD_SHOW"] = function(msg)  --指定Slash命令处理器
    local text = HelloWorld_Text[msg:lower()]  --按key提取value
    if text then  --value不为nil
        SendChatMessage(text, channel)  --将Value发送到指定聊天频道
    end
end

(3)调用插件

将HelloWorld文件夹放入Interface/AddOns目录,启动游戏就可以在插件列表看到我们的插件了。

通过/hwadd命令插入一些数据

/hwadd 1 猎人
/hwadd 2 德鲁伊
/hwadd 3 战士

通过/hwshow命令提取数据

/hwshow 3

(4)持久化

到目前为止,我们的数据只是存储在HelloWorld_Text变量中,并没有持久化到本地数据库,一旦游戏退出,数据也消失了。Wow插件的数据持久化非常简单,无需操作数据库,只需要在toc配置文件中配置即可

## SavedVariables: HelloWorld_Text

只需要这一行,系统会自动将HelloWorld_Text变量中的数据存储到数据库,并且在下次加载插件后将这些数据再次赋值到HelloWorld_Text。

至此,一个简单的插件完成!

 

推荐阅读