吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7962|回复: 21
收起左侧

[其他转载] 罗技Lua语言脚本,发一个"多线程"框架

  [复制链接]
雪辉 发表于 2020-9-27 14:36
本帖最后由 雪辉 于 2020-9-27 14:40 编辑

众所周知,罗技宏在业务逻辑上是单线程的,对于部分宏的开发,主要体现在以下两个问题上:
        1.宏开始后无法干预
                按下g键后,宏开始运行,按下第二次g键时,若宏没有停止,则第二次g按键会被挂起,直到前一次宏退出时,才会执行此次g按键。这就导致了,在宏运行的过程中,不能直接的使用g按键对其进行干涉,做不到宏的'随开随停';
        2.逻辑流错综复杂
                举个例子,对于奶僧来说,进本后需要一直保持真言和黑人的释放,而在定点后需要打定点的宏,此时的两宏并发,在逻辑上非常简单, 但在实现上就比较麻烦了,两段代码糅杂在一起,非常混乱。这就是两条逻辑流交错时,逻辑流(双线)与开发流(单线)不一致,导致代码变得复杂冗余、高耦合。
  那么有什么解决办法么?
  以上两点都是单线程的弊病,那么自然可以想到,把程序变成多线程不就行了嘛~
  可惜,罗技是不支持多线程的,多线程是基于cpu不断的切换上下文,而达到宏观上的线程并发,不是发生在代码层面的,所以无法通过代码去实现真正的多线程,这时候就需要曲线救国一下了
  先提两个知识点:
  1.轮询:
        什么是轮询呢,顾名思义就是循环着去询问消息队列,是否有事情做。前文提到过,在用户按下第二次g键后,需要等待前一次宏的运行完毕才能接着运行。轮询的处理则是将一次宏的时间分割成多段,每次进来只运行一个较短的轮询时间就退出,这样用户的命令就可以通过轮询的间隙发出来。
  2.协程:
        协程运作不同于多线程,他是发生在代码层面的(也就是说即使lua不支持协程运作,也可以通过代码去实现),协程中记录一条完整的逻辑流,协程之间的切换就行互调方法一样简单、高效,宏开发者只需要将不同的逻辑流写到不同的协程中去,则只需要关心‘在什么时候切换’,而不需要关心‘怎么切换’的问题了。

  说完两个知识点,下面就要说说所谓的‘多线程’实现了
  其实运用轮询和协程实现并发的宏框架目前是有的,不过暗黑的宏作者很少有人用,目前此框架拥有这以下两个问题,导致其只能实现简单的连 点器功能,并不普适。
  1.在协程中写Sleep函数
        在协程中写Sleep函数并不会让协程放弃系统资源,Sleep函数依旧会让整个程序停下来等他,这就使得在轮询的低时间高频率的背景下,不能做循环节较长的宏,多协程并发时,时间不精准。
  2.每次轮询都遍历一遍待办任务表
        这个是很消耗资源的事情,直接导致了轮询时间不能设置的太短,宏的灵敏性不够,其实并不需要去遍历整个消息队列,只需要找到时间最接近的任务去执行就行了。

  那么这两个问题又怎么去解决呢
  1.将Sleep函数完全抽离到主线程里来,所有的逻辑流交于协程去运作,协程运作到sleep函数时将其挂起,并向消息队列中插入一则(当前时间+需sleep时间)的任务,等待时间到时将其唤醒继续运行。
  2.目前消息队列的数据模型只是lua原生的表,我在框架中重新构建了一个插排队列的数据模型,任务插入时排序,每次轮询时从队列首端(时间最近)取值。


引入框架
1.下载压缩包解压到本地

2.打开罗技脚本编辑器,在第一行引入框架
dofile('刚刚下载的压缩包中lua文件的绝对路径')

注意此处的斜杠要使用正斜杠(/)
至此,框架已经引入完毕,接下来就可以正常使用了









如图,实现了按下鼠标左键运行v_run1宏,输出系统运行时间。抬起鼠标左键停止输出。
1.EnablePrimaryMouseButtonEvents(true)函数,开启鼠标左键的编程,部分系统不能使用。
2.main函数多了两个参数
第一个参数控制抬起或按下(MOUSE_BUTTON_PRESSED/MOUSE_BUTTON_RELEASED),默认值为按下,可直接填写nil。
第二个参数控制开启或停止(start/end)默认值为start_end(若开即关,若关即开)



如图,实现了单击g4键位,循环输出1-10。
因为并非循环运行的宏,则不适用于queue_ctrl控制器,这里使用了run控制器
main函数的第一个参数直接传递run,第2、3个参数依旧是绑定键位、按下/抬起
第四个参数因为此宏不涉及停止,则直接传递需要运行函数名即可。
再举一例:

如图,添加了一个终止所有正在运行的宏的方法。
list:empty()清空任务队列里等待执行的所有任务。
则实现点击g5键,强制终止所有正在运行的宏。

目前list:empty方法无法弹起使用press方法按下的键位,框架中集成了all_stop方法,可以删除队列的同时弹起press方法按下的键位.
all_stop方法允许传入一个参数,为线程对象,可定向关闭对应线程的序列

另外,在宏里也可以使用run函数直接执行其他宏

如图,在v_run1中用run函数调用v_run2方法。
那么这样和直接调用v_run2有什么区别呢?
直接调用,宏会先去执行v_run2结束后再回来执行v_run1
而使用run函数调用,v_run1和v_run2是同步进行的(如图,同时输出1-5)




下面介绍一个框架中比较基础也比较核心的控制器——自旋器。
自旋器,顾名思义指反复的去做一件相同的事。宏本身就是为了替代人进行一些机械性的操作而存在的,而自旋器则是执行这些简单而机械的反复操作的控制器
1.此控制器是一个单独线程,所以无需担心和正常的宏出现逻辑上的冲突。
2.可以实时的获知此控制器的核心参数,此核心参数可以自定义 (比如一个计时用的自旋器,可以实时获得所记时间)
首先是自旋器所要运行的函数
如图,执行函数实现的是按一下q键,此函数和以往的执行函数不同在于有参数和返回值。
此返回值由玩家定义,返回一个控制器的核心参数。我这里要记录一共执行了几次q按键,故返回次数。
而函数的参数则是上一次运行的返回值,这样就完成了一个每次进入后次数+1的实现。
参数和返回值可以不填

spin函数有四个参数(要重复执行的函数,重复执行的时间间隔,传入的参数初始值,自旋中止时执行的函数)
会返回一个控制器

将控制器的开启和中止分别绑定到g4和g5上。
如此,则用自旋控制器实现了一个简单的连点 器的作用。
注意,自旋函数中尽量不要使用sleep函数。
因为每一次执行的自旋函数是一个单独的不可分割的元 操作,即每一次进入函数后必须执行完才能被终止,里面加入了sleep函数后,可能会导致宏无法立即停止。

自旋器由于其独立线程,可以在后台静默开启执行一些插入式的操作。
例如:


在刚刚的基础上,添加了一个监听器,监听刚刚的test_spin自旋控制器,若其执行到5次,则中断。
这种保持原函数独立性的同时,用外界的新函数去干预其原本逻辑的行为称为插入式。就像一个插件,需要时插上去,不需要可以关掉,不影响原本的逻辑流。
如图按下了5次q之后被监听器中断。
1.test_spin('status')返回该自旋器的运行状态(true/false)
2.test_spin('get')获取该自旋器的核心参数,图中为次数。
3.A and B or C  格式为lua中的三目运算符,指若A为真,则返回B否则返回C(有一些小瑕疵)
注意,test_spin('end')仅仅是中断自旋器,再重新调用后次数会从6开始继续计数。
那么,如果想每次点击g4后自旋器重新计数怎么办呢?

写一个重置的函数绑定到g4即可。
如图,输出5次q被终止后,再次开启,重新计数到5次后被终止。

最后再给一个实例,是我经常用到的自旋器实现


此自旋器实现了一个后台静默执行的元素戒轮转。
开启自旋后,无论在宏的任何地方调用 ys_spin("get") 方法都可以直接获取到元素戒信息,无需再花费过多的逻辑去根据运行时间计算。




下面所介绍的控制器是这个框架中最重要的两个控制器之一,多线程连 点器。这个控制器运用了我比较喜欢的数组式编程,让逻辑代码完全抽离,代码本身十分干净,可以说很多不懂编程的小白都能看懂,甚至模仿写出自己的宏。
所谓连 点器是指以固定的频率去重复点击某些按键。市面上大多数罗技宏因为本身单线程,会导致宏的不精准,而为了保证宏的精准性,常常会将延迟进行最小公倍数计算,比如某些跑马天谴宏,点一下跑马要录十几个天谴等等。而本框架的特色就是多线程,让每个键位之间保持独立,互不干扰,多条逻辑流并发,保证了连 点器的精准。

如图,实现了分别1,2,3,4秒连点q,w,e,r。
写法为模仿图中写一个二维数组,第一个参数为要按的键位,第二个参数为间隔
将数组放入clicks方法,生成一个控制器。
然后将控制器绑到按键上,即可完成。

如果想要控制键位按下和抬起的时间,可以在数组的第三个参数中写
如图,我想执行宏时按住强制站立键(shift)就将shift键位的间隔调到一个比较大的值即可。



之前介绍了一下多线程连 点器的基本使用功能,在此对于此控制器进行功能补充,如果各位所写的宏有基本方法无法完成的需求,可以来这一层看一看。
1.拦截器
比如我们要实行组合键的需求,例如ctrl+q

拦截器函数写在数组的第四格(前三格为‘所按键位’,‘按键间隔’,‘按下与抬起之间的间隔’)
拦截器函数会在这个键位被按下前触发,如图则在按键前插入一个ctrl按键
拦截器函数如果写返回值且为true,会触发拦截按键,并循环访问拦截器,直到返回false为止。

如图是一个法师黑人(r)与一技能(q)的例子
逻辑为:48s点一次黑人,黑人持续时间内隔0.6s打次一技能。
这个拦截器函数判断黑人上次点击时间,若不在20s内则拦截10ms(函数的第二个返回值为拦截器轮询间隔,不填则默认为按键间隔 即默认数组第二格,请勿填0及以下,会死循环
拦截器函数可写一个参数,此参数为连 点器本身(图中get),get(2)表示数组中第二个按键上一次运行的时间点。
下面给个例子。

这个例子是上面那个黑人与一技能的扩充版,加入了元素戒校验。
宏的上半部分为之前写的元素戒自旋器,下半部分为刚刚的黑人宏。
多加了一个位于29行的拦截器,保证黑人的开启时间在电0s-2s
这个例子也是一个比较古老的bd——维尔冰封球的宏的一部分。

2.非按键函数
此连 点器的第一个参数并非绑定按键,也可以使用函数。下面举个小例子


这个例子把一个自旋器装进了连 点器中去,数组中写了三个参数,都是这个自旋控制器,但意义不太一样。
第一个为执行函数,自旋器可以通过直接传入‘start’运行,
第二个为终止函数,自旋器可以通过直接传入‘end’终止,
第三个为get函数,即用于拦截器函数中的get()所返回的状态,自旋器也是通过传入‘get’获取核心参数。
所以自旋器可以三个都直接传入本身来保持正常运行。
因为连 点器本身的特性,即使是加入非按键函数一般也是自旋器,故在这里只介绍自旋器的方法。
注意:如果加入的是非按键函数,则没有第四个参数,即这个函数无法通过拦截器拦截

workspace.7z

6.31 KB, 下载次数: 117, 下载积分: 吾爱币 -1 CB

框架

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
wingking + 1 + 1 谢谢@Thanks!
大山洞 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

头像被屏蔽
CSGO01 发表于 2020-9-27 16:38
提示: 作者被禁止或删除 内容自动屏蔽
mjx 发表于 2021-4-29 14:19
mjx 发表于 2021-4-29 09:51
罗技 2021.3.5164版本的G HUB报错     spring.lua:134: attempt to index a nil value (global 'coroutine' ...

解决了  换了罗技游戏软件就可以了
美汁源 发表于 2020-9-27 15:34
bachelor66 发表于 2020-9-27 15:46
mark,留着慢慢看                                 
 楼主| 雪辉 发表于 2020-9-27 16:26
美汁源 发表于 2020-9-27 15:34
玩穿越火线可以用不

可以用宏的,CF的弹道貌似是固定方位的
peroperotina 发表于 2020-11-12 02:34
看了一半, 有点懵懂, 感谢分享.

不过一个zip文件怎么会被chrome警告有风险了呢...
coolloog 发表于 2021-4-27 17:22
留着慢慢看   
mjx 发表于 2021-4-29 09:51
罗技 2021.3.5164版本的G HUB报错     spring.lua:134: attempt to index a nil value (global 'coroutine')
有没有什么办法解决呢?
www445599 发表于 2021-7-8 00:26
CSGO01 发表于 2020-9-27 16:38
你是凯恩那个人??

大佬求求你给个csgo宏G102 LUA文件
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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