LUACN论坛

 找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
热搜: YJWOW MagicStone BoL
查看: 104|回复: 0

[教程] WOW插件知识普及,黄金二章论

[复制链接]
发表于 2023-9-30 14:04:17 | 显示全部楼层 |阅读模式
第一章:插件的一些基本常识和疑难杂症解析
今天实在太累了,明天还要加班…… 第一章明天补上。
首先,我们都知道插件是干什么的,就不多介绍了,本章主要是站在插件初学者的角度来分析并解决一些小问题。

任何插件都必须放在 \World of Warcraft\Interface\AddOns 目录内才能生效,(大家熟悉的Ai-Art是放在Interface文件夹内的,实际上Ai-Art不属于插件,只是一些材质而已,利用Interface目录的读取优先级实现替换游戏默认材质的目的)
如果没有AddOns目录的话,进入一次游戏,这个目录会自动生成,AddOns目录内会生成30个(4.1版本)以“Blizzard_”开头的文件夹,
这些是暴雪自带插件,一般情况下这些插件是不需要理会的,即使你误删了也不要紧,重新登录游戏时他们会自动生成;
补充一个WOW客户端结构:

一般情况下你在网络上下载的插件都是以压缩包的形式出现,把解压出来的文件夹丢进AddOns目录内登陆游戏即可,需要注意的是并不是每个插件只有一个单独的文件夹,比如Grid,

如图所示,除了一个名为“Grid”的文件夹之外,还有很多其他文件夹,这些都是Grid的模块,他们都在同级目录下。

插件搞定之后就可以进入游戏啦,在你的人物选择界面左下角有一个“插件”按钮,

点开就是插件列表了,右上角的加载过期插件强烈建议始终保持勾选!这个在下面会详细讲一下,
左上角的下拉列表打开会显示你账号内的所有角色,你可以为每一个角色配置需要加载或不需要加载的插件。

进入游戏之后按 ESC--界面--插件标签,一般的插件设置界面就在这里了,特殊的可能需要输入一段命令来开启设置界面,
插件设置好了之后一定要正常退出游戏,这样插件的配置才能正常保存,楼主曾经很多次因为游戏报错或者非正常退出游戏造成所有插件配置文件丢失的悲催事故了。

上面说到了插件的配置,它是保存在两个位置:
1、World of Warcraft\WTF\Account\你的游戏账号\服务器名\角色名\SavedVariables
2、World of Warcraft\WTF\Account\你的游戏账号\SavedVariables
(这里的游戏账号要说明一下,如果你是九城时期的老玩家,那么它就是你曾经登录游戏的用户名;如果你是网易时期注册的战网通行证,那么你的游戏账号会是一组随机的数字+字符组成的名字)
位置1里保存的是可按角色分别设置的插件配置文件,位置2里保存的是不分角色保存的插件配置文件,
所以如果你需要清空配置文件时这两个文件夹都需要看一下,插件的配置文件一般为 “插件名.lua”文件,和"插件名.lua.bak"后者为备份配置文件,
如果你误删了配置文件,比如 Grid.lua ,你可以将“Gris.lua.bak”文件重命名,删掉后面的“.bak”来恢复它。

下面来说说新手们经常遇到的一些小问题:
1、下载好插件进入游戏后发现不起作用,打设置命令也没反应
首先可能是插件的目录级别错误,比如GS插件路径为 World of Warcraft\Interface\AddOns\GearScoreLite\GearScoreLite 很明显多了一个文件夹,这样插件是不会被读取到的;
其次可能是插件版本错误,显示过期插件,上面提到的“加载过期插件”可以很好的解决这个问题,
再详细说一下关于插件的TOC问题,举个例子

如上图中第一行
## Interface: 40200
这个40200即这个插件所对应的游戏版本,只对应大版本,比如3.35版本是 30300;4.1版本是40100;4.3版本为40300,熊猫人的第一个版本是 50001
需要注意的是这样跨版本使用插件可能会报错,因为BLZ喜欢在大版本更新时更改API(API什么意思?详见楼下的讲座);
还有一点就是你在插件列表里根本没有勾选这个插件……

2、插件报错
很多人在问答区提问插件报错应该怎样处理,说实话连我自己都看不太明白那玩意,只能看出是哪个插件报错,错误的位置,然后就看不懂了,
一般来说一个很常用的插件报错的话应该是插件版本与游戏版本不对应,去下载对应自己游戏版本的插件吧,不是每个人都有能力修复插件报错的。

第二章:曾经有这样一个讲座

流星曾经发布过一个公告,说UI群里将会有一个讲座,嗯,我就是奔着讲座去的,结果莫名其妙的错过了……还好吃饭同学做了笔记,
下面有请流星同学为大家进行讲解:
排版绝对是体力活儿!我已经头昏眼花了,恳请大家仔细阅读一下,如有排版错误敬请指出。


Part.1
首先先感谢各位能在百忙之中花时间来听这个讲座 我就不自我介绍了 今天的讲座主要内容就是通过一些实例来讲解魔兽世界中的UI开发流程
PS 为了照顾一些没有任何编程基础的玩家 会在开始的时候稍微介绍一点很基础的内容
如果有基础的朋友也可以看看 LUA中的基本语法和其他一些编程语言的差别
首先第一个要介绍的就是魔兽世界中的插件的构成 UI = user interface
所有的UI都是存在于Interface\\AddOns下的文件夹 包含内容基本上是 *.lua *.toc *.xml
以及一些资源的文件 其他中lua和xml的文件一般是用来实现所有的功能的载体
toc则是让魔兽世界识别插件的标识目录 如果你想自行制作一个UI 并且想让游戏可以识别你的插件的话 toc和lua是必不可少的
toc的写法
Code lua:
## Interface: 30300
## Title: PowerBar
## Notes: PowerBar as Elv style
## Title-zhCN: Power监视器
## Notes-zhCN: 和ElvUI配套风格的Power监视器
## Author: 素雪_NGAcn@风暴之眼
## Author-zhCN: 素雪_NGAcn@风暴之眼
## Version: 1.1 PowerBar-WotLK.lua



(我补充一个 ## OptionalDeps: XXX 这个XX代表运行这个插件所需要的其他插件,如果不同时加载XXX的话这个插件是无法正常运行的)

类似这样

先是接口的版本号 一般是30300 WLK
然后是一个标题
再就是一个小型的说明
然后就是中文标题和中文说明
这些内容会出现在 角色选择画面中的 插件目录下
Version代表的是你的插件的版本号 可以自己定义
然后 最下面的 则是你的lua
在写整个toc之前 请各位注意一下的就是
先将整篇的文档转换成utf-8的编码格式 不然 你在角色画面 插件目录下的显示将是"?" 这样的
toc部分 还有一个注意点就是 如果你的插件是包含一些ace库(补充:ACE库在前) 或者本地化的locales的话
这些locales 要写在你要汉化的lua之后 类似
Code lua:
PowerBar-WotLK.lua
locales\zh-cn.lua




Part.2
首先 魔兽世界的插件是一种程序 既然是程序 那么就和其他的语言编写的程序一样 是根据作者自己定义的流程 执行代码的一个顺序
插件 就是对数据的呈现以及交互 WOW中的插件的数据交互形式 基本上可以分为文字交互以及可视化的界面元素交互
类似 密语 聊天框 print 屏幕中间弹文字之类的,这些都是交互形式
这些交互形式的底层机制是插件中的数据以怎么样的形式呈现给用户 包括呈现给用户的是 什么样的数据
举个例子:上马宏
Code lua:
1:
2:

/run SendChatMessage("上马不喊话....",yell)
/use 幽灵虎






这实际上是小型UI的一个表现形式 调用SendChatMessage()方法 并且按顺序传入参数 来达到交互的目的
接下来说的是四个常用的数据类型
这些在插件制作中 基本上能用到的就是这四种 字符串、整形、布尔、空(String、int、bool、nil)

字符串就是一串字符 也就是文字内容 用双引号包起来的 类似"Hello World"
整形就是数字 不需要任何包装 类似 365
布尔代表真或假的结果 true or false
空值 lua中的空值使用 nil 关键字来代表空值
nil 同时还是一个false

Part.3
接下来是定义变量
变量 是插件作者和插件之间约定的标识符
举个例子
"本次G团拍卖品 1号 2000+2000"
请问 1号卖出去了什么东西
OK 我们也看到了 如果不定义变量来标记的话 谁都不知道 这个2000和后面的2000代表的是什么
如果我们要通过插件来实现的话 就可以给他们定义两个有意义的变量
Code lua:
1:
2:

local weapon = 2000 --定义武器为2000
local ring  = 2000 --定义戒指为2000






这样的话 在我们接下来 如果要做一些其他处理的话 就可以很清楚的弄明白 这个2000到底是什么东西的2000
这样 团长就黑不到G了嗯嗯
local 是 lua 中的局部变量的定义的关键字
和其他语言不一样 lua不需要声明数据类型
学过java或者c之类的应该知道 如果在其他语言中
如果要声明变量的话 int i = 1; string str = "abc"; 需要在变量前声明数据类型
但是lua不需要 因为它会在执行的时候才决定这个变量的数据类型 并且做处理
Code lua:
1:
2:
3:

local a = 10
local b = 1
local c = "1"





Code lua:
1:
2:

print(a+b)  
print(a+c)





结果是
11

101

多重赋值的形式:local a,b = 10,"1"

提问:local addon ,ns = …
定义的什么类型的变量?
回答:按照java的语法
Code lua:
1:
2:

int a = 10 string b = "1"
string c = b + a.toString()






大致上是这样的
整形是无论如何都可以强转成字符串的
字符串不一定强转的成整形

Part.4
接下来是逻辑部分
逻辑判断的话 lua中常用的就是
if 判断结果 then
执行语句
end

开始于if 结束于end
举例:假设我们需要在登录游戏的时候 根据自己的职业对应的给自己打个招呼

Code lua:
1:
2:

local unitClass = UnitClass("player")
local str ="欢迎你"





Code lua:
1:
2:
3:
4:
5:
6:
7:

local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:SetScript("OnEvent",function(self,event,...)
if(event == "PLAYER_ENTERING_WORLD") then
print(str + unitClass)
end
end)






这段代码就可以实现我们的需求
首先是定义一个变量 接收自己的职业
Code lua:
1:

UnitClass("player")




这是暴雪提供的API 用来获取自己的职业
然后
Code lua:
1:

local f = CreateFrame("Frame")




这个是动态frame概念
在魔兽世界中 对象用动态frame来展现
包括事件挂载 以及代码实现
这是一个插件中最基本的一个表现形式
也是非常常用的
实现机制就是 创建动态frame 注册事件并且挂载 然后当注册事件触发时 执行对应的代码
动态frame如果要响应事件触发的话 就需要注册事件
Code lua:
1:

f:SetScript("OnEvent",function(self,event,...)




为这个动态frame挂载要执行的函数
OnEvent这个挂载的机制是 事件触发一次或者多次
如果是像血条这种的话 需要挂载的机制就是OnUpdate了
Code lua:
PLAYER_ENTERING_WORLD


这是暴雪官方提供的事件
当玩家登录游戏(进入游戏画面的时候)触发
第二个参数 function(...) 一个匿名方法
然后直接在这个匿名方法中写方法体
参数的意思
就是一个方法的多重表现形式
就好像
Code lua:
1:
2:

print(UnitClass("player"))  
print(UnitName("player"))





我传入的两个参数不同 print出来的内容也不同
...表示可变长度
可以接受任意个数的参数
只要你指定

常用的逻辑判断
Code lua:
1:
2:
3:

if xxx then  
xxx  
end





Code lua:
1:
2:
3:
4:
5:

if xxx then
xxx
else
if xxx then xxx
end





注意 if ....elseif....end 这样的话只需要一个end闭包
但是如果你是
Code lua:
1:
2:
3:
4:
5:

if xxx then
xxxx
else  if  xxx then
xxxx
end






这样是会报错的
因为缺了一个end闭包的标记
举例:
假设 开G团的团长说 如果我们卖掉超过10WG的东西 DPS第一的补贴500G 如果卖掉超过5WG的东西 DPS补贴250G
Code lua:
1:
2:
3:
4:
5:
6:
7:

local extra = 0
local total = 卖掉的东西的总金额(这里是举例)
if total > 10WG then
extra = 500
elseif total >5WG  and total <10WG then
extra =250
end





如果是这样
Code lua:
1:
2:
3:
4:
5:
6:
7:
8:
9:

local extra = 0
local total = 卖掉的东西的总金额(这里是举例)
if total > 10WG then
extra = 500
return
elseif total >5WG  and total <10WG then
extra =250
return
end





也就是说 逻辑判断的话
当条件表示为真 并且遇到return关键字
就跳出整个逻辑判断(补充:直接跳到end的位置)
否则的话 指针继续往下做判断 直到遇到属于这个逻辑的end结束
这个是非常容易犯错的地方 就是else if和elseif
所以说 尽量使用一些文档编辑器来做 (推荐:Notepad++)

查API:
http://wowprogramming.com/docs
http://wiki.cwowaddon.com/

包括 你可以从里面查到暴雪提供的事件列表

Part.5
讲个常用的数据结构
Table
Table是lua中最强大的一个数据结构
灵活快捷简便是它最大的特点
在lua中 如果要定义一张表
Code lua:
1:

local tbl = {}




这样就定义了一张空的表
表一般是用来存放数据的载体
好比我们常用的filger
Setting里面就是一张很大的表 里面嵌套一些小的表
假设我们要定义一张表 用来存放三个好友
Code lua:
1:

local friends = {"好友1","好友2","好友3"}




这样就可以 这张表同时等同于
Code lua:
1:
2:
3:
4:
5:

local friends = {
1="好友1",
2="好友2",
3="好友3"
}






你扔进去的每个成员 表会帮你隐式的定义一个数字索引
然后 如果我们要获取好友2
friends[2] 这样就可以
表还有另外一种键值对的形式 索引也使用字符串的
Code lua:
1:
2:
3:
4:
5:

local friendsClass  = {
["好友1"] = "人类",
["好友2"] = "暗夜精灵",
["好友3"] = "矮人"
}





我们也可以用friendsClass["好友1"] 来获取 "人类" 这样的一个值
lua中所有的表的数字索引都是从1开始的

现在出道题目吧
local marks = {"大饼","圆圈","月亮","三角","骷髅","大叉","菱形","方块"}
请用print()方法来标记出 大叉 三角 菱形 方块

回答:
Code lua:
1:

print(marks[6],marks[4],marks[7],marks[8])





嗯 再说个小细节
如果要获取表中的元素的个数
可以用 tbl.getn()
或者 #tbl 这样
返回值为表中的元素个数(整形)
非数字索引的表元素 按照两个元素算

提问:local i = tbl.getn(marks)?
回答:不,local i = marks.getn()或者local i = #marks,如果用#marks的话 一般不需要再用变量去接,这个是用在迭代器中的比较多一点

[Part.6
迭代器
有很多情况下 我们需要对表中的数据进行处理,就好像上面的marks表 如果有这样一个需求
要求你一行一行的输出所有的标记 你会怎么做
Code lua:
1:
2:
3:
4:
5:
6:
7:
8:

print(marks[1])
print(marks[2])
print(marks[3])
print(marks[4])
print(marks[5])
print(marks[6])
print(marks[7])
print(marks[8])





这样确实能解决办法 但是太不灵活了 而且 如果表中有成千上万条记录呢
所以要引用到迭代器 也就是循环
lua中用的是for和for iparis
就用上面的marks表来做循环输出
Code lua:
1:
2:
3:

for i =1,#marks do
print(marks)
end





这是一个最基本的迭代器的形态
i=1 代表将索引从1开始 一直到#marks (这里是8) 结束 循环执行8次 每次循环开始 i自增1
和function() xxx end 以及if xxx then xxx end一样 迭代器需要一个end来结束这个循环
跳出循环也可以通过在循环体中进行条件判断 然后return
假设我们要从第一个开始标记 如果标记数的怪大于4个就跳出循环 可以通过设置循环次数 或者 在循环体中判断当前循环次数是否大于4来解决
Code lua:
1:
2:
3:

for i =1 ,4 do
print(marks)
end






Code lua:
1:
2:
3:
4:
5:
6:

for i=1,#marks do
print(marks)
if i >4 then
return
end
end





都可以
视情况来决定你要怎么写

然后是for iparis的迭代器
这个是用来做数组遍历的 通常情况下会出现在表嵌套表的情况下
这个暂时没有现成的例子 等会儿我去找鹌鹑大叔的Malaimo中间来选一段看看
迭代器部分有人有什么问题么

再说一个 遍历的话
还有一个办法
比如说
我们要设定一个面板的颜色
通常情况下不是
Code lua:
frame:SetVertexColor(255/255,255/255,255/255)

这样嘛
但是如果要分离开 因为要把config写在其他的文件里面
Code lua:
1:
2:

local color = {255/255,255/255,255/255}
frame:SetVertexColor(unpack(color))





unpack会自动遍历color表中的每一个使用数字索引的元素
并且输出 unpack会把表里所有数据提取出来

Part.7
这部分算是一个比较重点的部分
API的使用

如果是要做文字交互形式的插件的话(说话 喊话 悄悄话 这个属于文字交互形式,
然后 有图标 有计时条 有乱七八糟的二次元画面的就是图形元素交互形式了)
API FunctionsGame Events就可以了
API是API 事件是事件
好吧这好像是废话...
Complete API listing 完整的API列表 按字母排序来排的
API listing by category 按分类来排列的

GameEvent是暴雪提供的触发事件列表
先看API listing by category

我们就用一个最简单的实例来实现一个简单的功能
假设 我们打/notice 命令的时候 通报一下自己的当前血量和当前魔法值
这个时候 我们先要确定是从哪个分类里面去查对应的API
ctrl+f 输入Health

8个结果,一个一个看
UnitHealth - Returns a unit's current amount of health
返回目标当前的生命值
点进去

=号之前的是返回值 之后是函数名和可以传入的参数
Code lua:
1:

UnitHealth("player")  or UnitHealth("素雪")




这样都可以 然后用一个变量来接

Code lua:
1:
2:
3:

this is mana
local hp = UnitHealth("player")
local mp = UnitPower("player")






这样就好了,挂个toc 这个插件就可以工作了
SLASH这个就是注册的一个输入指令函数 是暴雪提供的 按照这个格式去写就可以了
第一行 SLASH_要定义的指令名1 = "/指令" 然后判断 执行
多个命令

当然这是比较笨的写法.
实际上可以这样

文字交互形式的UI制作主要是看需求 然后再看有没有可以供使用的API

https://bbs.nga.cn/read.php?&tid=4617462&pid=77983274&to=1

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?加入我们

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

小黑屋|手机版|Archiver|LUACN论坛

GMT+8, 2024-4-29 08:39 AM , Processed in 0.039119 second(s), 14 queries , Gzip On, Redis On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表