ff14高级触发器不正经教程-想让你的角色被注视时摇摇尾巴吗?

“最终幻想XIV”,“ACT高级触发器/Triggernometry”有不感兴趣或抵触的朋友们可以先退出了,愿你们看B站其他内容看的开心❤
本篇不涉及修改游戏资源,mod的使用等;战斗用触发器我大概也能做,但是非本篇主要介绍内容;摇尾巴指的是ff14游戏内置em宏命令,而非动作模组:
本篇是高级触发器教程(而非触发器高级教程),本教程以制作一个“被玩家注视时执行特定宏命令的触发器”为目标介绍ACT高级触发器,可能包含的内容有(目录):
高级触发器(Triggernometry)的简单介绍
分组、触发器(触发器条件、触发器动作、计划任务)的简单介绍
ACT日志的简单介绍
正则表达式知识(并不完整,只讲我喜欢的部分)的简单介绍
变量的简单介绍(只介绍部分,比如标量变量,列表变量,特殊变量)
触发器调用简单介绍(顺便介绍下我称之为迭代器和定时器的写法)
放点链接

1.高级触发器的简单介绍
Q:什么是触发器?
A:ACT会解析游戏并打印日志,触发器可以处理日志并做一些事情,比如播放声音语音合成或者发出蜂鸣声
Q:高级触发器与普通触发器的区别?
A:引入了变量,包括自己创建变量或是读取在场角色的变量;能做更多的事情,比如模拟键盘按键、执行鼠标操作、发送post请求、触发其他触发器、执行C#脚本等。


如插件中心介绍说的那样,没特殊需求的话用cactbot就好了,但摇尾巴偏就属于特殊需求~
第二张图中,本地触发器通常指.xml配置文件放在本地的触发器,自己创建或者导入的触发器就放在这里;远程触发器则是可以从远程代码仓库进行更新的.xml配置文件,比如ff14AuraCan的多数版本上传到过GitHub上,它们也可以作为远程触发器被安装及更新。

为了能看到更多的东西(主要指日志和变量),我们来修改一些配置:
点击高级触发器主界面右上角的【选项】-【编辑配置】-【其他】标签,勾选【设置使用实时值为默认测试方法】以及【开发者模式】
再来到【选项】-【编辑配置】-【通用】标签,勾选【通用】窗口下的【记录通常日志】
如果本文中还有其他东西我这显示了而你那没有,可以来找我贴贴,也可以自己想想办法,专栏末尾附上的链接也可能对你有帮助~

(修改配置后)点击高级触发器的选项按钮,里面有几个比较重要与常用的功能,我挑点喜欢的介绍下:

测试输入:选择日志行(Normal log line)并且输入日志可以很方便的测试你的触发器是否有效,不需要真的让你的同伴反复放一个三分钟CD的技能
禁用所有的Aura:Aura有敖龙族的意思,英语翻译是气质、气氛、氛围等。这里我感觉用“图片区域”和“文本区域”更合适,当你使用高级触发器显示图片或者文本区出了问题需要紧急停止时请使用这个功能
尝试中断执行的动作:冒险者你也不想你的尾巴一直摇吧(这例子其实不太恰当)。遇到不可控情况时先去掉触发器前的对号,还不能停止的话使用该功能
清除所有变量:好东西
清除动作队列:好东西
触发器性能基准测试:通常来说触发器的执行还是蛮快的,但并不代表它一直很快。当你的列表变量中储存着海都900位玩家时(当然不代表海都真的有这么多人)你可以明显的观察到处理这个变量的时间占比高的离谱
查看变量:你可以通过这个来创建、删除、编辑、查看高级触发器中已经储存的变量
查看日志:最主要的功能之一了,似乎通常只会显示战斗日志,需要做一点修改(勾选记录通常日志)才会显示非战斗日志
2.分组、触发器的简单介绍
分组:文件夹
触发器:文件夹里除了文件夹以外的东西,有时也指代一整组触发器
如果你用的也是中文版,那么你几乎不可能搞错他们的概念,它几乎在每一个显眼的地方告诉你它是个什么东西。
分组或者触发器左侧都有一个勾选框,默认是钩上的,也就是工作状态。你可以点一下,让那个✔消失,这样的话无论日志打印了什么都和该分组、该触发器无关了

好的我们来创建一个分组:
右键点击【本地触发器】-点击【添加】-点击【分组】,给分组随便起个英文名中文名日文名法文名都可以,只供展示用,触发器互相调用时识别的是它的id(因此需要被调用的触发器请不要轻易复制,很容易由于id相同而出问题)。我们就叫它Hello WorldTouch my tail好了,同时我将我旧触发器(这里指负责某个功能的整组触发器)前的✔去掉,以免他们互相干扰(本地触发器的✔别去掉,不然下面的都不工作了)
创建分组时有一些其他的功能可以点点看,万一哪天就用上了呢~

再在分组下创建一个触发器,右键新创建的分组,也就是Touch my tail那行字,点击【添加】-点击【触发】,起个名字,因为计划等下第一个要做的触发器功能是入场提醒,因此我简单的叫它in。同样地,这个触发器可以随便起什么名字,只要你自己分得清就好。如果你不想别人看得懂它,也可以起一些诸如e981a■e38184e■a898e■■■b6的名字。
其他的部分我们暂时空着,我们可以随时右键触发器或分组,点击编辑来修改任何部分。点击减号可以折叠,右键分组点击折叠全部也可以折叠。

现在我们来看一点触发器的细节部分,包括触发器条件、触发器动作、计划任务。双击我们的in,开始编辑我们的触发器
触发器动作:这个触发器被触发后会执行的动作,可以添加多个
触发器条件:满足条件后才能让这个触发器(以及其下触发器动作)执行,如果其他触发器调用该触发器且勾选忽略条件则无视触发器条件。类比编程语言的if else
计划任务:前面几个选择框也留意一下,会有用的到的时候。我们先看一下顺序执行这个可选框,触发器动作内的多个动作默认是并发执行的,可以粗略理解为谁先谁后不一定。但如果你勾选这个,那么该触发器内的动作一定会从上到下执行,执行完一个才执行另一个(触发器的互相调用另算)
3.ACT日志的简单介绍
说实话,我说不准这是原生的、应该叫ACT日志还是被处理过、应该叫高级触发器日志,以前看过一个架构图,后来忘了,也找不到了。
现在去玩会游戏,打个本或者去某个地图挂机亦或者看看风景,总之你认为会打印日志的活动都可以(写到这里时我去打了个月读讨伐战。小队,通讯贝,跨服贝,部队都有人说话,还有猫娘甩朝阳巴掌,有肥肥在啊呜啊呜,算是比较全面的日志采集了)。点击查看日志,里面应该有很多东西
我们右键其中一条-【复制】-【复制选择到剪贴板】(你可以输入AddCombatant然后点击搜索,从这里面选),这是我们待会要用的日志(龙尾轻轻摇是假名,希望没有叫这个名字的玩家)
现在把前面的部分以及结尾的括号去掉,中间的才是日志本体
日志的格式并不是一成不变的,至少在开6.0大版本时经历过一次改变
我来列举一些关键词,可供搜索日志时使用:
如果你也像我一样需要处理通讯贝跨服贝部队小队团队默语呼喊喊话情感动作一类的话可以多关注一下ChatLog,我来举几个例子:
4.正则表达式知识的简单介绍
先胃疼五秒
让我写是没什么问题的,让我讲我会胃疼。写不出想要的正则可以找我帮忙,我不会的话也会先去学然后试着写
先声明一下,不同编程语言的正则表达式是不完全相同的,但它们有相似的概念。学会一个后其他的查查文档也就会的差不多了,nga那个教程(后面有链接)正则讲的就十分详细。甚至都快变成正则教程了
我们再回顾一下入场打印的日志,并试图解析一下它的组成
日期,包含一对方括号、两个冒号、一个点、时、分、秒、毫秒
一个分隔用的空格
关键词AddCombatant
又一个分隔用的空格
03
可能是玩家唯一id(为了让日志尽量准确这里没有做修改,请大家不要找这些id的无辜玩家的麻烦)
玩家角色名字(这里是假名字)
后面那些我不太关注(因为可以通过特殊变量获取),有服务器名,坐标,血量血量上限,蓝量蓝量上限,怪物还有怪物id。也许wiki上有怪物id列表,我暂时没兴趣去查
接下来我试图讲清楚这个正则,如果看不懂一定不是你们的问题。我把日志(上)与对应的正则表达式(下)放在一起方便大家对照
先来看看前置知识点:
这行日志能通过(上文的正则)^.{14} AddCombatant 03:[^:]*?:(?<visiter>[^:]*?)(:[^:]*?){5}:0:
这行日志能通过(日志行中的一部分)AddCombatant
这行日志能通过(这有个点↘).
这行日志能通过(啥也没有,包括空格也没有)
好的~前置部分讲完了~上面的四段橘色都可以称为正则表达式(包括那个点和那个啥也没有)。这里是想提醒大家正则写的不要太随意,否则触发器可能会不受控制
下面正式开始:
^行首的这个我也不知道读什么玩意的符号表示日志行的开头。
.(↙这有个英文句号,和小数点长得一样的那个)代表一个任意字符。
{14}表示前面的元素有14份,(这有个英文句号↘).{14}表示14个任意字符;嗷{5}表示嗷嗷嗷嗷嗷。
(←这有个空格)代表空格。是的,空格没什么特殊的,它和嗷没太大的区别。
AddCombatant 03:(←这有个英文冒号)代表的就是你看到的东西。冒号也没什么特殊的。
[^:]方括号代表的是一组规则,表示这里有一个或一组符合方括号内规则的字符。这里的冒号依然只是冒号;^表示非;[^:]表示任意英文冒号以外的字符;[^嗷]表示任意嗷以外的字符。
*表示0个或任意多个前面的字符(顺便+表示1个或多个);嗷*表示任意多个嗷;(英文句号↘).*表示任意多个任意字符;[^:]*表示任意多个不是冒号的字符。
?单独使用的话表示0或1个,与*或+连用表示懒惰匹配(懒惰匹配可以理解为想尽办法让日志通过该正则的情况下匹配尽量少的字符。如嗷+会匹配喵嗷嗷嗷嗷嗷中的所有嗷,嗷+?只会匹配其中的第一个嗷,嗷*?更是懒到一个嗷都不会匹配。懒惰匹配在写正则时还是比较实用的,建议理解清楚)
[^:]*?(前面的三个东西组合在一起)表示匹配尽量少的冒号以外的字符
:(←这有个冒号)表示匹配一个冒号
(?<visiter>[^:]*?)这个结构不是所有能使用正则的地方都支持的用法,我的启蒙教程称其为捕获组,而且是命名捕获组。它的功能可以粗略理解为从日志行中截取一段,并且作为一个仅在该触发器中可以使用的变量(即便是同分组的其他触发器也不能使用)。捕获组的另一种被称为普通捕获组,由于我更喜欢命名捕获组,所以我不讲普通捕获组。虽然不讲,但是我不否认普通捕获组比较省事,而且打印更少的触发器日志。
回过头来看这个捕获组(?<visiter>[^:]*?),橙色部分(即括号、第一个问号、尖括号)是命名捕获组的固定写法,灰色则是可以自由发挥的部分。这个捕获组按顺序从日志行中还未匹配的部分捕获尽量少的非冒号字符,将其命名为visiter,并且供该触发器使用。使用方法为${visiter}
(:[^:]*?){5}这个就不是捕获组了,和捕获组没什么关系。它匹配5个括号里的东西,括号里则是一个冒号和尽量少的非冒号字符。它和:[^:]*?:[^:]*?:[^:]*?:[^:]*?:[^:]*?的效果是一致的
:0:(←两个冒号夹着一个数字0)它匹配你看到的东西——两个冒号夹着一个数字0。玩家这里是0,怪物这里则是怪物的id,我用这种方式筛选进入视野范围的是玩家还是小怪。毕竟谁都不想在下副本期间触发器叫个不停
上面的这些并不都是正则的基础部分,也不是基础的全部部分,能懂多少都没关系。拜读下我的启蒙教程、在B站找一些视频、去网络上学习一下、直接抡起高级触发器开搞都是十分可行的方法,最后我来把日志行与正则匹配的东西用不同的颜色标记出来:

[23:15:19.017] AddCombatant 03:10410CE8:龙尾轻轻摇:15:5A:0000:496:萌芽池:0:0:65728:80366:10000:10000:::-657.40:-849.27:12.04:2.53
^.{14} AddCombatant 03:[^:]*?:(?<visiter>[^:]*?)(:[^:]*?){5}:0:

日志行后面有一段黑色的字体没有对应的正则去匹配。没关系,我们并不关心它,前面的部分已经能达到我们的目的了——识别玩家(而不是怪物)进入我们监控范围的日志行,并且允许触发器肆意摆弄玩家的角色名~无论你想用语音合成播放、用对话框显示、创建变量供其他触发器使用、发送到你的远端服务器还是配合高级触发器的特殊变量做其他的操作都可以,随你喜欢~
现在我们来实践一下,双击之前创建的触发器in,来编辑这个触发器:
把上方的正则表达式复制进触发器页面的输入框
在触发器动作页签下点击Add action按钮,使用默认的动作类型系统音效就可以,我们直接点击添加,然后点击保存更改。如果操作没有问题的话现在每有一个人入场你的音频设备就会发出短促的滴声(如果没有音响也可以把蜂鸣修改为显示消息框,但可能会消息框太多关不过来)

提醒大家两点:角色的模型会在角色入场后一段时间才加载出来,对于过图很慢的玩家尤其明显
5.变量的简单介绍
变量是高级触发器与普通触发器的区别之一,GitHub上的文档足够详细的介绍了变量的用法
我们可以一起打开GitHub看一下…哦Thal’s Balls,又打不开了,算了我简单说说吧
变量分为标量变量,变量列表(一维数组),表格变量(二维数组)和特殊变量(可以理解为游戏数据)。前三者都有专门的触发器动作进行操作;特殊变量要从小队列表对象或者世界实体对象读取
变量能以文本或数字的方式处理:数字有包括运算和比较在内的一系列方法,文本则是有包括正则和字符串截取的一系列方法。方法太多这里不介绍了,可以去GitHub或者我nga的启蒙教程看看
测试没问题后把蜂鸣前的对号去掉(不去掉或直接删除也是没问题的),点击Add action按钮。动作类型选择变量列表操作,操作类型选择将值推送到列表变量的末尾(其他几个没差太多),原变量名称我叫它player_list,表达写${visiter}
现在我们去一个人数不太离谱的地方(旧萨雷安就不错),然后一路保存更改

等待片刻,然后去插件主页面右上角的选项中点击查看变量,然后切换到列表变量页签,可以双击变量以较为详细的方式查看,也可以进行添加编辑删除等操作(列表中都是假名)

现在去只有两三个人的地方,比如住宅区。清空一下player_list列表变量(在Triggernometry状态那个窗口选中player_list然后点摧毁变量),然后换一下职业(比如占星换成贤者)。点一下刷新按钮,你会发现你也在player_list里了。再换几次职业,你会发现里面有好几个你的角色名(换职业视作又一个你来了)。
这河狸吗?这不河狸。接下来我来介绍一点列表变量的用法,让触发器不重复记录;再介绍一点特殊变量的用法,让触发器不记录我们。

先搞清一件事:
捕获组只能在某触发器内使用,使用方法为${捕获组名}或$捕获组角标数字(前文没细讲的普通捕获组用法)
变量能在不同的触发器中使用,使用方法为:
${var:标量变量名}
${lvar:变量列表名[序号]}
${tvar:表格变量名[列序号][行序号]}
还有个叫持久变量的东西,前面三个东西加个字母p就行,如${evar:持久变量名},类似长期存储的变量。似乎是在创建变量时点一下右侧的软盘图标就会设定为持久变量,我目前还没用过
特殊变量与捕获组类似,${特殊变量表达式},可用的特殊变量可以去GitHub上查看,稍后也会举几个栗子
详细的请阅读GitHub文档~请小心,最初写触发器以及困迷糊的时候很容易因为忽略了捕获组和变量的使用差异而一个问题排查半小时不知道哪写错了。

让触发器不重复记录:
思路很简单,执行触发器in前查一下变量列表,这个名字已经插入过就不插入了:
点击触发器条件页签,勾选最上级条件组,右键并选择添加,然后选择条件。左侧表达式与右侧表达式用默认的字符串就好。左侧表达式和右侧表达式如下:
条件选择:左侧必须与右侧的正则表达式匹配。可能是还处于版本初期的原因,其他的条件有些存在bug(也可能是我用错了或其他什么原因)。大家可以把表达式的类型由字符串修改为数字,并使用大于小于符号进行尝试

我稍微拉大了窗口,方便大家查看我做了哪些修改。左侧表达式的意思是返回visiter这个捕获组代表的玩家名在变量列表player_list中的索引(索引,也就是位置,从“1”开始。这点与多数编程语言不同),如果变量列表里没有这个visiter存储的字符串则返回0。换言之,我们看看返回值是否为0就知道是不是已经存过了。
现在可以试下是否正常动作了~清空player_list变量或者直接删掉,然后换职业换职业换职业换职业,看看列表里只有一个自己,ok~很成功

让触发器不记录我们:

思路同样很简单,看看那个人是不是玩家自己就行惹~
_ffxivplayer是特殊变量,返回的是当前玩家(你)的角色名称
这个触发器做好后发现有个不完善的地方,这样写的话万一你的角色名比较短,而来者的名字恰巧能把你的名字包含在里面(比如你叫龙尾,来的人叫龙尾轻轻摇),那这个触发器就不会触发了
可以把右侧表达式修改为^${_ffxivplayer}$,这样的话就不存在上述问题了($表示一行的结尾)
现在可以试下是否正常动作了~清空player_list变量或者直接删掉,然后换职业换职业换职业换职业,看看列表里没有一个自己,ok~很成功(拿前面那段话改了一个字,懒)

人要是走出我们的视野了怎么办?我们的列表里还存着这个人呢,这似乎不合适吧?
如果你想到了这个问题,给你加十分~如果你甚至想出了解决办法,那给你加二十分(来自漂亮龙娘的肯定)
人员离场时同样也会打印日志。由于我们不用担心重复删除的问题,并且既然我们根本不会进入列表变量那么自然就不需要删除列表变量,因此名为out的触发器不用设置触发器条件

比较简单,因此我只把两行比较长的部分放上来,其他部分参考图片就好:
现在可以试试了,一切正常的话该变量列表会记录在座各位的角色名(不过海都很容易缺少离场日志,也就是out那个,所以你会发现在海都挂了一下午会有上千角色名)
6.触发器调用简单介绍
本篇到这里是一万字左右,领悟了上面这些勉强可以算入门了
那被注视时摇尾巴的日志呢?被注视没有日志(乖巧
……但是我们有特殊变量可以显示某个人选中目标的id!我们判断这个id是不是我们角色的id就知道那个人有没有在看我们了。如果之前没在看我们,现在看我们了,那么我们就摇摇尾巴
我来阐述下实现的思路:
使用in和out维护一个人员列表
定时遍历这个人员列表,如果列表中的某个人在看你的角色,且之前不在注视列表(记录正在看着我们的角色名单)我们就把ta的名字添加进注释列表中,否则无作为;定时遍历注视列表,如果那个人没看你,就把ta的名字从注视列表中拿出去
更换地图时把人员列表和注视列表清了
再做个可以用游戏内的宏关闭摇尾巴功能的小开关,你也不想你的尾巴像猫猫(非猫魅族)的一样不受控制吧
第一步已经实现了,我们接下来做第二步~我们把第二部拆分为如下数个触发器:
gazeat:传入一个角色名,若人员列表中这个人在看你,且之前没看你,就把ta的名字放入注视列表,同时摇摇尾巴
remove:传入一个数字,若注视列表中这个人没在看你,就把ta的名字从注视列表中移除
member_iterator:人员列表遍历器,如果传入的数字不大于人员列表长度,把人员列表中索引为该数字的角色名传给gazeat进行调用,并且调用自身,调用自身时传的数字加一
gazeat_iterator:注视列表遍历器,如果传入的数字不大于注视列表长度,把注视列表中索引为该数字的角色名传给remove进行调用,并且调用自身,调用自身时传的数字加一
trigger:定时器,一秒一次调用自身,不去人多地方的话甚至可以500ms调用一次。于此同时调用member_iterator和gazeat_iterator

1.gazeat的条件1是用来区分玩家和陆行鸟的,玩家和陆行鸟的日志行实在是太像了,我没找到仅凭日志行区分的方法。_ffxiventity是个特殊变量,表示当前区域的所有实体,job是职业,陆行鸟没有职业。如果没人帮你做实验你可以先不加这个条件,让陆行鸟看你…
条件2的targetid就是注视实体的id了,_ffxiventity[龙尾轻轻摇]这种写法似乎获取不到当前玩家id,于是稍稍麻烦了一点做了特殊处理。
动作2的系统消息方式即便你前台在使用其他软件,后台也会发送按键,注意安全。122对应的是F11,详细的你可以在输入122的地方看到下面有一个链接,点进去就是了:https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.keys?view=windowsdesktop-6.0
2.remove没什么要讲的,测试gazeat和remove时可以使用测试输入这个功能:
比如你想测试gazeat这个触发器,可以使用这一行:
gazeat龙尾轻轻摇

查看下实验结果,需要用到游戏内特殊变量的测试请确保游戏是开着的

3.member_iterator:这个开始是真正的触发器互相触发的操作了,触发器互相调用有些类似多线程编程开启新线程一样,所以触发器工作的先后顺序可能与预期不符,自己设计时请多做实验,必要时及时给电脑断电以免烧坏主板~(骗你的啦,一般最多死机,不太容易烧掉)
numeric的用法是把${index}+1算出来
触发器调用这里放个图:

4.gazeat_iterator:你可能注意到了,触发器的正则和前面一个东西的开头一样的,都是gazeat。嗯,不影响,能跑就行(/em 心虚地偏开了头。才不是因为懒所以没做修改呢…)因为这两个触发器匹配的都不是日志行,而是匹配其他触发器对其进行调用时的事件文本,因此不会互相干扰。
5.trigger:计划任务选项卡凭直觉写的,看起来工作的还不错
穿漂亮点去海都挂一会、找亲友帮忙测试、或者把判定职业的触发器条件关掉然后把你的好CP叫出来~
主体功能已经做完了,撒花~

接下来是第三步,换地图时把人员列表和注视列表清了:

放上Touch my tail整组触发器,复制下来点击导入然后粘贴就能使用了。你也许想使用通用Json操作来在触发器被触发时给你的内置装备发送post请求使其通过力反馈的方式来提醒你。我试图这样做但是没有找到合适的硬件,有的话希望能介绍给我
我去玩我的尾巴了,下次再见~
7.放点链接
我使用的是国服整合版的ACT(https://ffcafe.org/act/)。很方便,有汉化,且他们仍在对Triggernometry 高级触发器进行维护。其他版本的高级触发器版本存在差距但同样可以接受。
高级触发器GitHub更新日志:https://github.com/paissaheavyindustries/Triggernometry/wiki/Triggernometry-changelog
高级触发器GitHub功能列表与详细介绍:https://github.com/paissaheavyindustries/Triggernometry/wiki/Triggernometry-FAQ-and-examples
我入门的教程(不是我写的别误会了):https://nga.178.com/read.php?tid=20779526&rand=20
本篇文章的源码(版本更新导致不可用的话后续可能会更新):https://github.com/raine01/TouchMyTail