为什么要写开发手册?
随着版本的推进和代码的迭代,如今代码里屎山遍布,弃用的API数不胜数,只看源码的上手难度很大。 而越来越多的老脚本出现BUG,但开发者们又往往躺平,所以对于想要修复功能或者新增功能的使用者来说,不妨先看看这篇攻略,可能能达到事半功倍的效果
main_new太麻烦,有没有办法直接跑某个功能/调试某个功能/调用某个API?
省流:直接看第三章
- 项目结构说明
- 脚本运行流程
- 使用AutomatorDebuger辅助编程
- Automator中的常用辅助功能
- 4.1 movevar
- 4.2 AutomatorRecorder
- 4.3 sidecheck
- 4.4 precheck
- 4.5 PCRretry
仅对目前使用中的代码进行介绍,对于已经弃用或者尚未启用的代码目前暂不提及。
项目结构(点击展开)
如果第一次接触该项目,不妨先跳过该部分,从第二章开始看哦。
-
adb 项目携带的指定版本的adb文件,默认设置下会使用该版本的abd防止出现连接问题。
-
api 涉及到app.py,目前仅用于全局的OCR服务,一般不修改。
-
automator_mixins 任务的主要实现模块
- _async.py 异步模块,目前主要用来全局异步检测网络错误等,一般不构成完整任务。
- _base.py Automator基类,包含最底层的控制函数,一般不构成完整任务。
- _captcha.py 验证码识别模块,仅用于登录时的过验证码。
- _dxc.py 地下城相关任务模块
- _dxc_base.py 地下城相关任务的子函数,在2.6版本Scene模块出现后逐渐弃用。
- _enhance.py 角色升级相关任务模块
- _fight_base.py 战斗相关任务的子函数,在2.6版本Scene模块出现后逐渐弃用。
- _hanghui.py 行会相关任务模块
- _haoyou.py 好友相关任务的模块
- _jjc.py 竞技场相关任务的模块
- _juqing.py 自动过剧情相关任务的模块
- _login.py 登录模块,一般不构成任务。
- _routine.py 日常任务相关模块
- _shop.py 购买指定碎片的任务的相关模块
- _shuatu.py 刷图推图相关的任务模块
- _shuatu_base.py 刷图推图任务所用子函数,在2.6版本Scene模块出现后逐渐弃用。
- _tools.py 对_base.py进行一部分封装获得的常用函数,也包含一些工具相关的任务。
-
core 项目的核心代码部分
- Automator.py 核心控制器,全部任务的大集合,也是任务列表执行的入口函数。
- bot.py bot模块代码部分
- constant.py 资源、坐标信息汇总,包含图地址、图坐标等。
- cv.py 对cv2库的一些封装,构成底层的图像识别函数,但基本都在automator_mixins._base.py中得到封装。
- emulator_port.py 自适应模拟器端口号代码。
- get_screen.py 快速截图核心代码
- initializer.py 流程控制器,包含Devices, PCRInitializer, Schedule三大模块。
- launcher.py 模拟器自启动相关代码
- log_handler.py log记录相关模块
- MoveRecord.py 用于任务的中断恢复,无需修改。
- pcr_checker.py 2.6版本后用于合并指令于某一指令集中统一管理。
- richutils.py 对rich库的封装,用于输出好看的控制台信息。
- safe_u2.py 对uiautomator2库的继承,包含了掉线重连的处理。
- tkutils.py 对tk库的封装,用于显示提示框。
- usercentre.py 包含了user,group,task,batch,switch,schedule六大模块的读写与分析。
- utils.py 工具类函数
- valid_task.py 包含了全部任务的信息,及任务参数正确性的判断。
-
img 项目图片资源存放目录
-
pcrdata 干炸里脊数据库以及数据交互分析、装备计算相关模块
-
pcrocr 使用pytorch训练的PCR特化ocr以及相关训练代码
-
scenes 2.6版本后的核心组件:场景
- errors.py 自带保存错误信息的exception,目前基本弃用
- scene_base.py 场景基类
- 其它的文件夹的名字都对应相关场景,包含相关场景的特化函数,具体氪参考
Scene框架的使用.md
-
app.py 目前仅作为全局OCR的后端。
-
CreateUser.py 对应main_new->edit,编辑器主界面
-
DataCenter.py 对应main_new->data, 数据中心主界面
-
img_helper.py 对应main_new->img, 图坐标编辑小助手主界面
-
main_new.py 主界面
-
screencut.py 对应main_new->screencut,截图小助手主界面,包含调试类AutomatorDebuger。
文件太多了,应该从哪里开始看呢
- 首先去
automator_mixins
中随便找几个任务看看,模仿学习下就明白个大概了。 - 再细看
automator_mixis/_base.py
,了解基本的控制器API。 - 稍微浏览下
constant.py
,对照看看img文件夹,了解坐标和资源存放的一些习惯。 - 结合Scene框架的使用.md,试着理解
scenes/scene_base.py
,之后再去随便看几个写好的场景就基本明白场景的用法了。 - 关注一下
core/valid_task.py
,模仿学习任务列表的编写方式。 - 研究一下
core/usercentre.py
,基本就明白数据存储的结构与方式了。 - 此时基本上你已经精通任务编写了,可以对照
sample_customtask/sample_task.py
,掌握一些任务编写的其它小细节。 - 最后如果还想更深入地了解脚本的流程,只需要研究好
core/initializer.py
就行了。
本节主要讲述该脚本的整体执行逻辑,与具体某个任务的编写无关。 如果你不感兴趣,或者只想急着改bug/写新脚本,也可以直接看第三节。
如果你已经看完了Schedule使用教程,你应该已经对该脚本的六大数据模块(user, task, group, batch, schedule, switch)有了基本的印象,此处不再赘述。 对于每类数据的具体存储格式,在core/usercentre.py的文件头处有详细的注释说明(比schedule教程的更完整),建议详细查看。
首先,在脚本开启前,往往会要求启动app.py。app.py是一个和main_new.py并行的外部进程。app.py本意是作为图形化界面的后端的,但目前更主要的任务是用来运行OCR框架。 即app.py上事先初始化好各种OCR的模块,然后在脚本进程需要使用OCR的时候,通过网络通讯向app.py发送一条请求,app.py会返回OCR的结果。
main_new.py便是脚本的主进程了。由于python的多线程只能占用1个CPU,因此该脚本基于多进程进行编写,以便于多开时提升处理效率,main_new.py便起到
进程的调度与控制的作用。当脚本开启后,main_new便会分析当前绑定的schedule,按照一定的计划将任务添加到任务队列中。随后,main_new启动一系列子进程,
并且根据子进程的空闲状态将任务队列中的任务分配给各个子进程。这一系列的控制流程均在core/initializer.py
中,被细分为Device
, PCRInitializer
,
Schedule
三大控制类。下面对这三个类各自的作用进行简单的介绍。
Device
设备类,主要用于显示当前连接的模拟器的一些状态,以及和adb、模拟器自启动、模拟器健康检测相关,也包含了控制器类Device.a:Automator
。 在主进程中,Device.a
被设置为None,因此它不具备执行任务的功能。多个Device组成AllDevices类,该类包含添加、删除、搜索设备的相关接口。
在多进程体系中,主进程与子进程中的Device承担着不同的角色。当脚本启动时,主进程会调用AllDevices来进行模拟器的搜索和连接, 随后根据当前连接的状态分配具体的任务。主进程创建子进程时,也会传入对应的Device,并且在子进程中初始化Device.a,此时Device才具有了脚本控制的功能。 子进程在执行任务中如果需要对Device的状态进行修改(比如显示”正在执行……“,或者检测到模拟器崩溃需要跳过该模拟器等等),需要通过进程间通讯的方法将信息 传递给主进程中的指定Device,实现模拟器状态的同步。
简而言之,主进程Device仅仅负责状态的显示,而子进程Device还可以进行脚本的控制。子进程Device需要和主进程中Device通过进程间通信进行状态的同步,这需要 通过后文介绍的PCRInitializer类实现。
PCRInitializer
PCR启动器类,包含有任务调度的优先级队列,且负责子进程的创建与进程间的通信。以下简称PCR
包含有AllDevices类:PCR.devices
,用来指示当前全部模拟器的状态,PCR会根据该类显示的信息对每一个空闲的设备都初始化一个子进程。
PCR.tasks
是一个优先级队列,以task的priority参数的负数作为排序标准,因此priority高的任务会排在任务列表的前面。
PCR.tasks
中的一条任务为一个6元组,(priority, account, taskname, rec_addr, task, continue_)
。其中,priority为优先级,
account表示该任务对应的用户,taskname表示该任务的名称(仅用于显示和记录),rec_addr为该任务的存档地址(用于中断恢复),task为任务字典, continue_
为bool值,表示是否需要运行前将rec_addr中的对应存档给清除。
使用PCR.add_task
或者PCR.add_tasks
来添加一系列任务,这些任务会被存放到PCR.tasks
中。
为了实现主进程与子进程之间的通信,PCRInitializer包含了两类消息队列。其中,PCR.in_queue[device]
为代表设备device的子进程接收主进程消息的队列,
每个模拟器都有一个代表自己设备的in_queue。PCR.out_queue
为主进程接受子进程消息的队列,被所有子进程公用。
启动PCRInitializer的方法是PCR.start()
。这首先会开启一个独立的监听线程PCR._listener
,用于监听PCR.out_queue
发来的信息并做出对应的处理。 随后,根据PCR.devices
中显示的可用设备的数量,为每一个空闲的模拟器单独启动一个进程PCR._do_process
,并对其共享任务队列PCR.tasks
和两个消息队列
PCR.in_queue[device]
和PCR.out_queue
。子进程自己会时刻关注PCR.in_queue[device]
中传入的进程控制信息,并在自己空闲时检测PCR.tasks
是否
有待执行的任务,如果有,便从中取出一项任务加以执行。使用PCR.send_message
可以向指定子进程(设备)的in_queue中发送一条控制信息。
子进程PCR._do_process
的参数仅有device:Device, task_queue, in_queue, out_queue,分别表示绑定的设备,任务队列、输入队列和输出队列。
device在主进程中,脚本控制器device.a
值为None,在子进程中会首先对其进行初始化,此时device就具有了脚本控制的功能。随后,子进程也会启动自己的 监听线程_listener()
,用来监听in_queue传来的控制指令。当自身处于空闲状态时,会检查task_queue是否为空,否则从中获取一条任务,并调用
PCR.run_task
来执行任务。同时,通过out_queue向外发送自己设备的状态,外部的_listener会根据发送的信息同步主进程的device的状态,以供随时调取查看。
PCR.run_task
是“设备执行任务”的整体实现,具体见代码注释,此处不再赘述。
任务的运行状态会实时与PCRInitializer进行更新。PCR.running_tasks
、PCR.finished_tasks
、PCR.paused_tasks
分别存放正在执行中的、已经
完成的、和被搁置的任务六元组。当子进程运行一条任务时,会把该任务告知主进程,主进程将该任务添加到PCR.running_tasks
中。当子进程将任务运行完毕后,
同样也会给主进程发送信息,主进程此时删除PCR.running_tasks
中的相关条目,并添加到PCR.finished_tasks
中。若任务执行出现异常,即执行失败, 该任务会被搁置,存放于PCR.paused_tasks
中。如果需要重新执行某一条任务,只需要再次调用PCR.add_task
即可,不过目前脚本中并没有给出相关 实现,有相关需求可以自行实现。
结束运行时,可以使用PCR.stop
来向全部子进程发送关闭的信息,具体详见注释。注意,PCR.stop
并不能用于关闭侦听线程,但该线程仅会开启一次,因此无需在意。
PCR.get_status
可以显示当前任务队列中的状态信息。
Schedule
计划控制器,根据编辑好的计划文件在条件满足的时机向PCRInitializer中新增新的任务。以下简称SCH
包含有PCRInitializer类:SCH.pcr
。
Schedule在初始化时,需要传入name参数和pcr参数。其中,pcr为待投入的PCRInitliazer。一个PCRInitializer只能绑定一个Schedule,否则可能发生不可名状的错误。 name为计划名称,若name为空字符串,则不启用任何计划(空计划);否则,name为计划文件的名称。在SCH的init函数中,会读取该计划文件,随后调用SCH.parse 对计划进行解析,最后调用SCH. init_status将所有计划初始化为未执行的状态。
一条子计划可以看作为一个五元组:(typ,nam,batch,cond,rec_addr)
。 其中,typ为计划类型(asap/wait),nam为计划的名称,batch为计划对应的批文件名称,cond为
计划执行的条件字典,rec_addr为计划执行进度的存储路径。这些子计划会被存放在SCH.SL
列表中。rec_addr路径与name和batch有关,即:
rec/{计划名称}/{子计划名称}/{批文件名}
。在SCH.SL
中每条计划的rec_addr应该是独一无二的,因此可以被用作查找计划的主键使用。
对于包含batchlist的计划,要求每个batch按照顺序依次执行。对于这种计划,SCH._parse
会拆分batchlist为多个batchfile,建立多条子计划,并且在第2条往后
的子计划中删掉已经存在的cond,但是新增一个隐藏条件_last_rec
。即:必须以_last_rec为存储路径的计划已经被执行完毕,该计划才能执行。
举例而言,对一个设置了batchlist和cond的子计划,当cond满足时,全部batch会依次执行,且即使执行到第二个batch时cond已经不满足,后续batch也会继续执行。
Schedule会为每个成功执行的计划,在其rec_addr目录下存放一个_fin文件,因此只需要检测该文件是否存在即可判断上一batch是否执行完毕。
每个子计划都有一个记录模式参数record
。对于持久运行的计划,其nam会被额外存放于SCH.not_restart_name
中,在执行restart操作时,会跳过该列表中包含的子计划;
而循环运行的计划,其nam和batch构成的二元组(nam,batch)则会被额外存储在SCH.always_restart_name
中, 当检测到SCH.SL
中的某一条计划已经完成,但是其nam和batch组成的二元组能在SCH.always_restart_name
中找到,
则会当场对名称为nam的子计划进行restart操作。特别的,对于batchlist的子计划,其nam和batchlist中最后一个batch组成的二元组会被存放,这意味着
需要将batchlist中的一套循环全部完成后,才会重置这一计划,重新进行batch循环。
SCH.run_status
为一个{rec_addr:计划状态}的字典,存放了每一条计划的状态信息。调用SCH._init_status
初始化时,所有计划的状态都被初始化为未执行
状态,但可能此时有一些计划已经完成或者因为不符合条件被跳过,因此还需要后续进一步检测。SCH.checked_status
为一个{rec_addr:bool}的字典,用来
记录每一条计划是否在后续被检测过,在SCH._init_status
中这被全部初始化为False,表示所有计划的状态都需要进一步检测。
使用SCH.run
开启计划线程SCH._run
,用于不间断地扫描SCH.SL
中处于未执行状态的计划,并判断是否满足加入SCH.pcr
的条件。具体逻辑详见代码。
SCH.get_status
将返回当前计划的执行状态字典,具体详见注释。
Automator类是核心控制类,包含了脚本执行的全部底层、高层API。Automator类由多个Mixin类构成,分别负责不同模块的脚本任务,以下简称a
。 Automator在初始化时需要手动调用a.init_device
来连接到模拟器,并且使用a.init_account
来绑定用户与记录读取地址。随后,使用a.start
来启动 公主连结app。待app启动之后,仍然需要a.start_th
,a.start_async
来开启异步线程,最后使用a.start_shuatu
来重置是否有体力能刷图的flag。 所幸的是,这些麻烦的步骤都在PCRInitializer.run_task
中执行了,因此无需对此过多关注。
Automator的最上层调用函数为a.RunTasks
,用于执行一个任务dict。RunTasks
会使用MoveRecord
库来建立一串函数链表,使用该库创建的函数链表
会在其中一个函数执行结束后立即存储当前的执行位置,以供中断恢复使用,下次再次运行时会从上次中断的链表处开始运行。使用该库运行的函数会额外向其中传递 一个参数var,可以使用MoveRecord.movevar
工具来在函数执行过程中随时存取关键数据,MoveRecord工具会在第4节详细介绍。
a.RunTasks
获得一个tasks字典后,会根据core/valid_tasks.py
中的任务总表,将任务映射为Automator类中的具体函数。a.RunTasks
将向
MoveRecord
链表中依次添加这些函数,构成函数链。接着,a.RunTasks
会执行登录逻辑和a.init_home
函数,确保账号的登录和回到主界面。接着,
a.RunTasks
将使用MoveRecord
进行函数链的依次运行。函数链全部运行完毕后,a.RunTasks
即结束,返回一个成功执行的标志。 外部的PCRInitializer.run_task
检测到成功执行后,会进一步执行a.change_acc
,切换账号,回到标题界面,至此,一个完整的“在设备Device上 登录账号account并执行任务task”的循环就完成了。
Automator与MoveRecord都会对一些特殊的Exception进行处理。在MoveRecord的函数链中,额外特判两个异常:MoveRecord.MoveSkipException
与
MoveRecord.MoveRestartException
,分别表示跳过当前的函数和重新开始当前的函数。特别的,还可以指定MoveRecord.MoveSkipException
的
skipinfo
参数为某一整数,表示跳转到函数链中的指定位置,这就是在运行时控制台中输入skip -t [XXX]
可以跳转到指定任务的原理。位于
MoveRecord外部的Automator则包含了对更多自定义异常的处理,如快速截图异常、模拟器断连异常、登陆时账号异常、从PCRInitializer
发送来的强制终止异常
等等,对每种特殊异常都制定了对应的应对措施,包括重启公主连结(a.fix_reboot
)等。详细逻辑可以参考代码。
而对于其它的异常,如锁定超时等等,则会触发纠错机制。即:重启程序可以解决绝大多数问题。此时,错误信息和截图会被保存,a.RunTasks
会重启游戏, 并从登录开始重新执行。登录完成后,由于有MoveRecord
的帮助,已经执行过的函数不会重复执行。如果重启次数超过设定上限,则运行失败,返回相关的信息。 外部的PCRInitializer
会做出相应的处理。
可以忽略Debuger不是Debugger的问题,就像忽略is_exists不是is_existed一样。 开发者文化水平有限,敬请谅解。
在这里,引进一个非常方便的调试工具:screencut.AutomatorDebuger
,该工具是对Automator
的继承,因此包含了所有的执行脚本;同时,该工具
扩充了调试函数,增加了可视化的截图、选点工具,大大增加了开发速度。尽管screencut内置了一个命令行来调用AutomatorDebuger,但仅用于应急使用, 用起来极为难受。因此强烈建议使用pycharm的python
console或Jupyter这类可交互控制台来实时地调用AutomatorDebuger中的相关函数。
这里尤其推荐使用pycharm的python console。下面会给出一个作者自己使用的基于pycharm的调试方法,以供参考。
调试代码尽量在config中启动debug和trace_exception_for_debug,你可以选择设置write_debug_to_log为False来减少屏幕输出量。
首先编写一个test.py
:
# 这里尽可能多地涵盖你将要调试的代码所用到的相关模块
from core.safe_u2 import run_adb
from core.utils import *
from screencut import *
from core.initializer import *
from core.constant import *
from CreateUser import *
from core.cv import *
from core.MoveRecord import movevar
import datetime
if __name__ == "__main__":
# 首先,打开app.py,或者除非你调试的代码中不涉及到任何OCR部分。
self = AutomatorDebuger() # 打开调试器,极其建议使用self作为变量名
WindowMode() # 开启窗口模式,使得Matplotlib产生的图片以可交互的形式呈现。
# self.Init() # 可选,相当于main_new中执行init
self.Connect() # 连接到模拟器,可以指定具体模拟器series。若不指定,则连接到第一个。
self.Account("admin") # 随便起了个名字,你可以把这里换成你想要调试的账号。
# self.InitPCROCR() # 可选,可以让你的AutomatorDebuger直接使用PCR专属OCR的相关功能。
接下来,执行test.py
,但注意在pycharm的Run/Debug Configurations
中设置启动方式为Run with python console
。
然后,你就可以自由地使用self.Shot
,self.Show
命令爽快地截图啦!关于GUI界面的操作方式可以参考screencut.py中显示的相关帮助信息。
但这,并不是使用python console还特意把变量名设置为self的真正好处。
随时随地测试脚本
如果正常使用main_new来测试某个脚本的性能,这需要经历多进程启动、模拟器连接、登录验证等一大堆工序,而且你还得编写一个很繁琐的任务文件,调试极为不方便。 现在你使用了test.py
,你想调试某个脚本,直接在python
console中补充执行相关命令就行。如,想测试每日刷图脚本,直接追加运行以下代码:
var = {}
self.shuatu_daily_ocr(
tu_order=['VH20-1-3', 'VH20-2-3'], daily_tili=0, xianding=True,
not_three_star_action="do", zero_star_action="do", lose_action="exit", can_not_enter_action="exit",
win_without_threestar_is_lose=True, team_order="zhanli", zhiyuan_mode=0, var=var,
)
随时随地调用底层API
比如,公主连结版本更新后,脚本卡在地下城选图界面,无法进入地下城。从debug信息中可以判断出是地下城图标的匹配值过低。为了验证这一点, 只需要启动test.py
,将模拟器手动执行到出错界面,随后追加运行以下代码:
self.is_exists(DXC_ELEMENT["in_sytzcs"])
此时,我们就可以观察debug和相关返回值来定位错误原因了。比如如果是图标变了,就可以直接追加运行self.Shot()
,在原来的位置上重新截图并替换 原有资源,手动更新constant.py
后,重启test.py
,就能起到实时调试、改错的效果了。
特别的,如果发现资源没有出错,仅仅是位置出错了,那么还可以直接追加运行以下代码:
self.img_where_all_prob(DXC_ELEMENT["in_sytzcs"].img)
观察其返回值,即为原图片资源在截图中的位置就可。太方便了吧。
对于更多好用底层API,此处不做更多介绍,_base.py中都有详尽注释。
真·单步调试
众所周知,Automator为一个类,其中的脚本都为类的成员函数,那么他们对Automator,都有个共同的称呼:self
。
一旦你设置的AutomatorDebuger的变量名称也为self
,你就能做到真正的单步调试:首先运行test.py
,随后手动操作模拟器到你想要单步调试的 场景。接下来,去_
automator_mixins或scenes中找到想要调试的对应函数(也可以是customtasks中你刚写的脚本的函数),选中一行,按下快捷键
Alt+Shift+E执行选中行,即可完成单步调试!你可以慢慢见证每一条函数引发的模拟器上的变化,并且随时可以调用底层API来辅助自己的调试。
当然,你得实现把你要调试的函数所需要的模块全import了才行。
也许你已经注意到,绝大多数automator_mixins中的任务入口都含有var参数。如果你已经阅读了2.3节,你应该已经清楚var的作用是在MoveRecord的中断恢复 框架下,某一个任务在执行途中随时存取的字典。比如,在购买体力任务中,如果设置了需要购买3次体力,但是购买了两次之后游戏崩溃,重新开始该任务得重新 购买3次体力,这非常浪费石头。所以,在该任务中引入var,每购买一次体力,就随即在var里的体力计数上增加1;当游戏崩溃重新开始任务后,即检查var里 有没有上次保存的购买数,这样就可以实现任务中的中断恢复了。
一般来说,能不使用movevar的地方就不使用,多用OCR、图像识别等,这样稳定性更高。例如,与其用movevar记录当前地下城打了几次了,不如直接OCR检测 当前所在的层数。
movevar的使用方法很简单。首先,你需要从MoveRecord中引入该工具,并将任务入口函数的var字典传入其中,得到控制句柄,一般命名为mv:
from core.MoveRecord import movevar
mv = movevar(var)
你不用考虑var的读取问题,因为MoveRecord框架会自动从存档中读取var并传入,因此你永远看到的都是最新的var。不过,你得自己考虑存储的问题。 你可以在你的任务中对var肆意修改,然后调用mv.save()即可。
但是你需要注意的是,大多数情况下,除非你有特殊需求,你都必须在你写的任务函数结束之前手动将var中你新添加的变量给del掉。因为MoveRecord被设计成了 var作为内部环境全任务共享的机制,如果你不手动del并save,下一个任务接收到的var中就会残留你之前的记录。因此请务必做好善后工作。
movevar中集成了一些flag控制函数,你可以使用mv.regflag
将某个变量注册为flag,之后你就可以用mv.clearflags
一键清除全部你设置的flag了。 类似的方法还有mv.notflag
,mv.setflag
,一定程度上可能简化了编程的复杂度。
在sample_customtasks/sample_task.py
中有mv使用的示例代码,感兴趣可以查看。
AutomatorRecorder,以下简称AR,是一个存取静态信息的控制类。可以直接使用Automator.AR
来进行调用。
该类最简单的功能是存取6大数据,推荐直接去看一眼core/usercentre.py
中相关API的实现就能明白。一种常见的需求是在
customtask中与switch或者switch的相关flag联动,从而控制不同的任务逻辑,如根据N2,N3的设置来动态调整刷图次数和体力等。
不过,AR的更大作用是读取用户相关的静态信息。在Automator.init_account
中,会将AR与具体用户绑定,此后, 只需要使用AR.get(key,default)
就能读取绑定用户的名称为key的静态信息,并在信息缺失时返回default。
用户相关的静态信息存储位置在users目录下,即users/{key}/{account}.json
。目前存放的信息举例如下:
- daily_status 每日刷图相关,包含体力使用、刷图记录等。
- juese_info 角色识别读取的角色信息
- zhuangbei_kucun 库存识别读取的装备信息
- time_status 上次进行探索/捐赠/免费扭蛋……的时间戳
这些Key对应的default都存储在constant.py中的USER_DEFAULT_DICT中。使用时,直接从constant中import就行:
from core.constant import USER_DEFAULT_DICT as UDD
如果需要存储新的静态信息,对应的,调用AR.set(key, obj)
即可。
在sample_customtasks/sample_task.py
中有mv使用的示例代码,感兴趣可以查看。
【龟速更新中】