Skip to content

Latest commit

 

History

History
383 lines (267 loc) · 27.8 KB

比较好上手的项目开发手册.md

File metadata and controls

383 lines (267 loc) · 27.8 KB

[For Developer] 比较好上手的项目开发手册

为什么要写开发手册?

随着版本的推进和代码的迭代,如今代码里屎山遍布,弃用的API数不胜数,只看源码的上手难度很大。 而越来越多的老脚本出现BUG,但开发者们又往往躺平,所以对于想要修复功能或者新增功能的使用者来说,不妨先看看这篇攻略,可能能达到事半功倍的效果

main_new太麻烦,有没有办法直接跑某个功能/调试某个功能/调用某个API?

省流:直接看第三章

目录

  1. 项目结构说明
  2. 脚本运行流程
  3. 使用AutomatorDebuger辅助编程
  4. Automator中的常用辅助功能
    • 4.1 movevar
    • 4.2 AutomatorRecorder
    • 4.3 sidecheck
    • 4.4 precheck
    • 4.5 PCRretry

1. 项目结构说明

仅对目前使用中的代码进行介绍,对于已经弃用或者尚未启用的代码目前暂不提及。

项目结构(点击展开)

如果第一次接触该项目,不妨先跳过该部分,从第二章开始看哦。

  • 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。

文件太多了,应该从哪里开始看呢

  1. 首先去automator_mixins中随便找几个任务看看,模仿学习下就明白个大概了。
  2. 再细看automator_mixis/_base.py,了解基本的控制器API。
  3. 稍微浏览下constant.py,对照看看img文件夹,了解坐标和资源存放的一些习惯。
  4. 结合Scene框架的使用.md,试着理解scenes/scene_base.py,之后再去随便看几个写好的场景就基本明白场景的用法了。
  5. 关注一下core/valid_task.py,模仿学习任务列表的编写方式。
  6. 研究一下core/usercentre.py,基本就明白数据存储的结构与方式了。
  7. 此时基本上你已经精通任务编写了,可以对照sample_customtask/sample_task.py,掌握一些任务编写的其它小细节。
  8. 最后如果还想更深入地了解脚本的流程,只需要研究好core/initializer.py就行了。

2. 脚本运行流程

本节主要讲述该脚本的整体执行逻辑,与具体某个任务的编写无关。 如果你不感兴趣,或者只想急着改bug/写新脚本,也可以直接看第三节。

如果你已经看完了Schedule使用教程,你应该已经对该脚本的六大数据模块(user, task, group, batch, schedule, switch)有了基本的印象,此处不再赘述。 对于每类数据的具体存储格式,在core/usercentre.py的文件头处有详细的注释说明(比schedule教程的更完整),建议详细查看。

2.1 app.py

首先,在脚本开启前,往往会要求启动app.py。app.py是一个和main_new.py并行的外部进程。app.py本意是作为图形化界面的后端的,但目前更主要的任务是用来运行OCR框架。 即app.py上事先初始化好各种OCR的模块,然后在脚本进程需要使用OCR的时候,通过网络通讯向app.py发送一条请求,app.py会返回OCR的结果。

2.2 core/initializer.py

main_new.py便是脚本的主进程了。由于python的多线程只能占用1个CPU,因此该脚本基于多进程进行编写,以便于多开时提升处理效率,main_new.py便起到 进程的调度与控制的作用。当脚本开启后,main_new便会分析当前绑定的schedule,按照一定的计划将任务添加到任务队列中。随后,main_new启动一系列子进程, 并且根据子进程的空闲状态将任务队列中的任务分配给各个子进程。这一系列的控制流程均在core/initializer.py中,被细分为Device, PCRInitializerSchedule 三大控制类。下面对这三个类各自的作用进行简单的介绍。

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_tasksPCR.finished_tasksPCR.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将返回当前计划的执行状态字典,具体详见注释。

2.3 Automator

Automator类是核心控制类,包含了脚本执行的全部底层、高层API。Automator类由多个Mixin类构成,分别负责不同模块的脚本任务,以下简称a。 Automator在初始化时需要手动调用a.init_device 来连接到模拟器,并且使用a.init_account来绑定用户与记录读取地址。随后,使用a.start来启动 公主连结app。待app启动之后,仍然需要a.start_tha.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.MoveSkipExceptionMoveRecord.MoveRestartException,分别表示跳过当前的函数和重新开始当前的函数。特别的,还可以指定MoveRecord.MoveSkipExceptionskipinfo参数为某一整数,表示跳转到函数链中的指定位置,这就是在运行时控制台中输入skip -t [XXX]可以跳转到指定任务的原理。位于 MoveRecord外部的Automator则包含了对更多自定义异常的处理,如快速截图异常、模拟器断连异常、登陆时账号异常、从PCRInitializer发送来的强制终止异常 等等,对每种特殊异常都制定了对应的应对措施,包括重启公主连结(a.fix_reboot)等。详细逻辑可以参考代码。

而对于其它的异常,如锁定超时等等,则会触发纠错机制。即:重启程序可以解决绝大多数问题。此时,错误信息和截图会被保存,a.RunTasks会重启游戏, 并从登录开始重新执行。登录完成后,由于有MoveRecord 的帮助,已经执行过的函数不会重复执行。如果重启次数超过设定上限,则运行失败,返回相关的信息。 外部的PCRInitializer会做出相应的处理。

3. 使用AutomatorDebuger辅助编程

可以忽略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了才行。

4. Automator中的常用辅助功能

4.1 movevar

也许你已经注意到,绝大多数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使用的示例代码,感兴趣可以查看。

4.2 AutomatorRecorder

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使用的示例代码,感兴趣可以查看。

4.3 sidecheck

【龟速更新中】