From 4cd2e06849342275bff1da1dc43070a1c4493643 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 2 Jan 2024 00:43:34 +0800 Subject: [PATCH] Add: Record progress of battle pass quests --- config/template.json | 9 ++- module/config/argument/args.json | 42 ++++++++++ module/config/argument/argument.yaml | 15 ++++ module/config/argument/stored.json | 91 ++++++++++++++++++++++ module/config/config_generated.py | 7 ++ module/config/i18n/en-US.json | 28 +++++++ module/config/i18n/es-ES.json | 28 +++++++ module/config/i18n/ja-JP.json | 28 +++++++ module/config/i18n/zh-CN.json | 28 +++++++ module/config/i18n/zh-TW.json | 28 +++++++ module/config/stored/classes.py | 34 ++++++++ module/config/stored/stored_generated.py | 14 ++++ module/ocr/keyword.py | 14 ++++ module/ocr/ocr.py | 4 +- module/ocr/utils.py | 4 +- tasks/battle_pass/battle_pass.py | 98 ++++++++++++++++++++---- tasks/battle_pass/keywords/classes.py | 3 + 17 files changed, 455 insertions(+), 20 deletions(-) diff --git a/config/template.json b/config/template.json index b328c0f90..a01d447e1 100644 --- a/config/template.json +++ b/config/template.json @@ -113,7 +113,14 @@ }, "BattlePassStorage": { "BattlePassLevel": {}, - "BattlePassWeeklyQuest": {} + "BattlePassWeeklyQuest": {}, + "BattlePassSimulatedUniverse": {}, + "BattlePassQuestCalyx": {}, + "BattlePassQuestEchoOfWar": {}, + "BattlePassQuestCredits": {}, + "BattlePassQuestSynthesizeConsumables": {}, + "BattlePassQuestCavernOfCorrosion": {}, + "BattlePassQuestTrailblazePower": {} } }, "Assignment": { diff --git a/module/config/argument/args.json b/module/config/argument/args.json index a04a8c746..519fa77b2 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -910,6 +910,48 @@ "value": {}, "display": "hide", "stored": "StoredBattlePassWeeklyQuest" + }, + "BattlePassSimulatedUniverse": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassSimulatedUniverse" + }, + "BattlePassQuestCalyx": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassQuestCalyx" + }, + "BattlePassQuestEchoOfWar": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassQuestEchoOfWar" + }, + "BattlePassQuestCredits": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassQuestCredits" + }, + "BattlePassQuestSynthesizeConsumables": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassQuestSynthesizeConsumables" + }, + "BattlePassQuestCavernOfCorrosion": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassQuestCavernOfCorrosion" + }, + "BattlePassQuestTrailblazePower": { + "type": "stored", + "value": {}, + "display": "hide", + "stored": "StoredBattlePassQuestTrailblazePower" } } }, diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index fd96e4320..6ff223a33 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -162,6 +162,21 @@ BattlePassStorage: color: "#cbe45b" BattlePassWeeklyQuest: stored: StoredBattlePassWeeklyQuest + # Quests progress + BattlePassSimulatedUniverse: + stored: StoredBattlePassSimulatedUniverse + BattlePassQuestCalyx: + stored: StoredBattlePassQuestCalyx + BattlePassQuestEchoOfWar: + stored: StoredBattlePassQuestEchoOfWar + BattlePassQuestCredits: + stored: StoredBattlePassQuestCredits + BattlePassQuestSynthesizeConsumables: + stored: StoredBattlePassQuestSynthesizeConsumables + BattlePassQuestCavernOfCorrosion: + stored: StoredBattlePassQuestCavernOfCorrosion + BattlePassQuestTrailblazePower: + stored: StoredBattlePassQuestTrailblazePower Assignment: # Options in Name_x will be injected in config updater diff --git a/module/config/argument/stored.json b/module/config/argument/stored.json index 30d344a0d..c676428a1 100644 --- a/module/config/argument/stored.json +++ b/module/config/argument/stored.json @@ -165,5 +165,96 @@ }, "order": 0, "color": "#777777" + }, + "BattlePassSimulatedUniverse": { + "name": "BattlePassSimulatedUniverse", + "path": "BattlePass.BattlePassStorage.BattlePassSimulatedUniverse", + "i18n": "BattlePassStorage.BattlePassSimulatedUniverse.name", + "stored": "StoredBattlePassSimulatedUniverse", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 1, + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "BattlePassQuestCalyx": { + "name": "BattlePassQuestCalyx", + "path": "BattlePass.BattlePassStorage.BattlePassQuestCalyx", + "i18n": "BattlePassStorage.BattlePassQuestCalyx.name", + "stored": "StoredBattlePassQuestCalyx", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 20, + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "BattlePassQuestEchoOfWar": { + "name": "BattlePassQuestEchoOfWar", + "path": "BattlePass.BattlePassStorage.BattlePassQuestEchoOfWar", + "i18n": "BattlePassStorage.BattlePassQuestEchoOfWar.name", + "stored": "StoredBattlePassQuestEchoOfWar", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 2, + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "BattlePassQuestCredits": { + "name": "BattlePassQuestCredits", + "path": "BattlePass.BattlePassStorage.BattlePassQuestCredits", + "i18n": "BattlePassStorage.BattlePassQuestCredits.name", + "stored": "StoredBattlePassQuestCredits", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 300000, + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "BattlePassQuestSynthesizeConsumables": { + "name": "BattlePassQuestSynthesizeConsumables", + "path": "BattlePass.BattlePassStorage.BattlePassQuestSynthesizeConsumables", + "i18n": "BattlePassStorage.BattlePassQuestSynthesizeConsumables.name", + "stored": "StoredBattlePassQuestSynthesizeConsumables", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 10, + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "BattlePassQuestCavernOfCorrosion": { + "name": "BattlePassQuestCavernOfCorrosion", + "path": "BattlePass.BattlePassStorage.BattlePassQuestCavernOfCorrosion", + "i18n": "BattlePassStorage.BattlePassQuestCavernOfCorrosion.name", + "stored": "StoredBattlePassQuestCavernOfCorrosion", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 8, + "value": 0 + }, + "order": 0, + "color": "#777777" + }, + "BattlePassQuestTrailblazePower": { + "name": "BattlePassQuestTrailblazePower", + "path": "BattlePass.BattlePassStorage.BattlePassQuestTrailblazePower", + "i18n": "BattlePassStorage.BattlePassQuestTrailblazePower.name", + "stored": "StoredBattlePassQuestTrailblazePower", + "attrs": { + "time": "2020-01-01 00:00:00", + "total": 0, + "value": 0 + }, + "order": 0, + "color": "#777777" } } \ No newline at end of file diff --git a/module/config/config_generated.py b/module/config/config_generated.py index feb883afb..756d7fdab 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -104,6 +104,13 @@ class GeneratedConfig: # Group `BattlePassStorage` BattlePassStorage_BattlePassLevel = {} BattlePassStorage_BattlePassWeeklyQuest = {} + BattlePassStorage_BattlePassSimulatedUniverse = {} + BattlePassStorage_BattlePassQuestCalyx = {} + BattlePassStorage_BattlePassQuestEchoOfWar = {} + BattlePassStorage_BattlePassQuestCredits = {} + BattlePassStorage_BattlePassQuestSynthesizeConsumables = {} + BattlePassStorage_BattlePassQuestCavernOfCorrosion = {} + BattlePassStorage_BattlePassQuestTrailblazePower = {} # Group `Assignment` Assignment_Name_1 = 'Nameless_Land_Nameless_People' # Nine_Billion_Names, Destruction_of_the_Destroyer, Winter_Soldiers, Born_to_Obey, Root_Out_the_Turpitude, Fire_Lord_Inflames_Blades_of_War, Nameless_Land_Nameless_People, Akashic_Records, The_Invisible_Hand, Abandoned_and_Insulted, Spring_of_Life, The_Land_of_Gold, The_Blossom_in_the_Storm, Legend_of_the_Puppet_Master, The_Wages_of_Humanity diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 8af2f0400..41674fd17 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -692,6 +692,34 @@ "BattlePassWeeklyQuest": { "name": "Honor Mission", "help": "" + }, + "BattlePassSimulatedUniverse": { + "name": "Complete Simulated Universe 1 time(s)", + "help": "" + }, + "BattlePassQuestCalyx": { + "name": "Clear Calyx 20 time(s)", + "help": "" + }, + "BattlePassQuestEchoOfWar": { + "name": "Complete Echo of War 2 time(s)", + "help": "" + }, + "BattlePassQuestCredits": { + "name": "Use 300,000 credits", + "help": "" + }, + "BattlePassQuestSynthesizeConsumables": { + "name": "Synthesize Consumables 10 time(s)", + "help": "" + }, + "BattlePassQuestCavernOfCorrosion": { + "name": "Clear Cavern of Corrosion 8 time(s)", + "help": "" + }, + "BattlePassQuestTrailblazePower": { + "name": "Consume a total of 100 Trailblaze Power (1400 Trailblazer Power max)", + "help": "" } }, "Assignment": { diff --git a/module/config/i18n/es-ES.json b/module/config/i18n/es-ES.json index da2ec281b..c27f438f7 100644 --- a/module/config/i18n/es-ES.json +++ b/module/config/i18n/es-ES.json @@ -692,6 +692,34 @@ "BattlePassWeeklyQuest": { "name": "Misión de Honor", "help": "" + }, + "BattlePassSimulatedUniverse": { + "name": "Completa el Universo Simulado 1 vez", + "help": "" + }, + "BattlePassQuestCalyx": { + "name": "Completa Cáliz 20 vez", + "help": "" + }, + "BattlePassQuestEchoOfWar": { + "name": "Completa Ecos de la guerra 2 vez", + "help": "" + }, + "BattlePassQuestCredits": { + "name": "Consume 300 000 créditos", + "help": "" + }, + "BattlePassQuestSynthesizeConsumables": { + "name": "Sintetiza consumibles 10 veces", + "help": "" + }, + "BattlePassQuestCavernOfCorrosion": { + "name": "Completa Caverna de la corrosión 8 veces", + "help": "" + }, + "BattlePassQuestTrailblazePower": { + "name": "Consume un total de 100 pts. de Poder trazacaminos (máx. 1400 pts.)", + "help": "" } }, "Assignment": { diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 47afd4ce3..61565b7ed 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -692,6 +692,34 @@ "BattlePassWeeklyQuest": { "name": "BattlePassStorage.BattlePassWeeklyQuest.name", "help": "BattlePassStorage.BattlePassWeeklyQuest.help" + }, + "BattlePassSimulatedUniverse": { + "name": "BattlePassStorage.BattlePassSimulatedUniverse.name", + "help": "BattlePassStorage.BattlePassSimulatedUniverse.help" + }, + "BattlePassQuestCalyx": { + "name": "BattlePassStorage.BattlePassQuestCalyx.name", + "help": "BattlePassStorage.BattlePassQuestCalyx.help" + }, + "BattlePassQuestEchoOfWar": { + "name": "BattlePassStorage.BattlePassQuestEchoOfWar.name", + "help": "BattlePassStorage.BattlePassQuestEchoOfWar.help" + }, + "BattlePassQuestCredits": { + "name": "BattlePassStorage.BattlePassQuestCredits.name", + "help": "BattlePassStorage.BattlePassQuestCredits.help" + }, + "BattlePassQuestSynthesizeConsumables": { + "name": "BattlePassStorage.BattlePassQuestSynthesizeConsumables.name", + "help": "BattlePassStorage.BattlePassQuestSynthesizeConsumables.help" + }, + "BattlePassQuestCavernOfCorrosion": { + "name": "BattlePassStorage.BattlePassQuestCavernOfCorrosion.name", + "help": "BattlePassStorage.BattlePassQuestCavernOfCorrosion.help" + }, + "BattlePassQuestTrailblazePower": { + "name": "BattlePassStorage.BattlePassQuestTrailblazePower.name", + "help": "BattlePassStorage.BattlePassQuestTrailblazePower.help" } }, "Assignment": { diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index 964a15f11..ebcafd67b 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -692,6 +692,34 @@ "BattlePassWeeklyQuest": { "name": "无名勋礼任务", "help": "" + }, + "BattlePassSimulatedUniverse": { + "name": "完成1次「模拟宇宙」", + "help": "" + }, + "BattlePassQuestCalyx": { + "name": "完成20次「拟造花萼」", + "help": "" + }, + "BattlePassQuestEchoOfWar": { + "name": "完成2次「历战余响」", + "help": "" + }, + "BattlePassQuestCredits": { + "name": "累计消耗30万信用点", + "help": "" + }, + "BattlePassQuestSynthesizeConsumables": { + "name": "累计合成消耗品10次", + "help": "" + }, + "BattlePassQuestCavernOfCorrosion": { + "name": "完成8次「侵蚀隧洞」", + "help": "" + }, + "BattlePassQuestTrailblazePower": { + "name": "累计消耗100点开拓力(上限1400点开拓力)", + "help": "" } }, "Assignment": { diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 025d1cf1e..11ef61804 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -692,6 +692,34 @@ "BattlePassWeeklyQuest": { "name": "無名勳禮任務", "help": "" + }, + "BattlePassSimulatedUniverse": { + "name": "完成1次「模擬宇宙」", + "help": "" + }, + "BattlePassQuestCalyx": { + "name": "完成20次「擬造花萼」", + "help": "" + }, + "BattlePassQuestEchoOfWar": { + "name": "完成2次「歷戰餘響」", + "help": "" + }, + "BattlePassQuestCredits": { + "name": "累计消耗30万信用点", + "help": "" + }, + "BattlePassQuestSynthesizeConsumables": { + "name": "累计合成消耗品10次", + "help": "" + }, + "BattlePassQuestCavernOfCorrosion": { + "name": "完成8次「侵蚀隧洞」", + "help": "" + }, + "BattlePassQuestTrailblazePower": { + "name": "累積消耗100點開拓力(上限1400點開拓力)", + "help": "" } }, "Assignment": { diff --git a/module/config/stored/classes.py b/module/config/stored/classes.py index 42f0f4e5c..c7fad20ba 100644 --- a/module/config/stored/classes.py +++ b/module/config/stored/classes.py @@ -351,3 +351,37 @@ class StoredBattlePassWeeklyQuest(StoredCounter, StoredExpiredAt0400): self.quest7 = quests[6] except IndexError: self.quest7 = '' + + +class StoredBattlePassSimulatedUniverse(StoredCounter): + FIXED_TOTAL = 1 + + +class StoredBattlePassQuestCalyx(StoredCounter): + FIXED_TOTAL = 20 + + +class StoredBattlePassQuestEchoOfWar(StoredCounter): + FIXED_TOTAL = 2 + + +class StoredBattlePassQuestCredits(StoredCounter): + FIXED_TOTAL = 300000 + + +class StoredBattlePassQuestSynthesizeConsumables(StoredCounter): + FIXED_TOTAL = 10 + + +# Not exists on client side +# class StoredBattlePassQuestStagnantShadow(StoredCounter): +# FIXED_TOTAL = 8 + + +class StoredBattlePassQuestCavernOfCorrosion(StoredCounter): + FIXED_TOTAL = 8 + + +class StoredBattlePassQuestTrailblazePower(StoredCounter): + # Dynamic total from 100 to 1400 + LIST_TOTAL = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400] diff --git a/module/config/stored/stored_generated.py b/module/config/stored/stored_generated.py index 2ff299140..1280f1e19 100644 --- a/module/config/stored/stored_generated.py +++ b/module/config/stored/stored_generated.py @@ -2,6 +2,13 @@ from module.config.stored.classes import ( StoredAssignment, StoredBase, StoredBattlePassLevel, + StoredBattlePassQuestCalyx, + StoredBattlePassQuestCavernOfCorrosion, + StoredBattlePassQuestCredits, + StoredBattlePassQuestEchoOfWar, + StoredBattlePassQuestSynthesizeConsumables, + StoredBattlePassQuestTrailblazePower, + StoredBattlePassSimulatedUniverse, StoredBattlePassWeeklyQuest, StoredCounter, StoredDaily, @@ -30,6 +37,13 @@ class StoredGenerated: DailyQuest = StoredDaily("DailyQuest.DailyStorage.DailyQuest") BattlePassLevel = StoredBattlePassLevel("BattlePass.BattlePassStorage.BattlePassLevel") BattlePassWeeklyQuest = StoredBattlePassWeeklyQuest("BattlePass.BattlePassStorage.BattlePassWeeklyQuest") + BattlePassSimulatedUniverse = StoredBattlePassSimulatedUniverse("BattlePass.BattlePassStorage.BattlePassSimulatedUniverse") + BattlePassQuestCalyx = StoredBattlePassQuestCalyx("BattlePass.BattlePassStorage.BattlePassQuestCalyx") + BattlePassQuestEchoOfWar = StoredBattlePassQuestEchoOfWar("BattlePass.BattlePassStorage.BattlePassQuestEchoOfWar") + BattlePassQuestCredits = StoredBattlePassQuestCredits("BattlePass.BattlePassStorage.BattlePassQuestCredits") + BattlePassQuestSynthesizeConsumables = StoredBattlePassQuestSynthesizeConsumables("BattlePass.BattlePassStorage.BattlePassQuestSynthesizeConsumables") + BattlePassQuestCavernOfCorrosion = StoredBattlePassQuestCavernOfCorrosion("BattlePass.BattlePassStorage.BattlePassQuestCavernOfCorrosion") + BattlePassQuestTrailblazePower = StoredBattlePassQuestTrailblazePower("BattlePass.BattlePassStorage.BattlePassQuestTrailblazePower") Assignment = StoredAssignment("Assignment.Assignment.Assignment") Credit = StoredInt("DataUpdate.ItemStorage.Credit") StallerJade = StoredInt("DataUpdate.ItemStorage.StallerJade") diff --git a/module/ocr/keyword.py b/module/ocr/keyword.py index 987b79acc..a5b8141dc 100644 --- a/module/ocr/keyword.py +++ b/module/ocr/keyword.py @@ -201,3 +201,17 @@ class Keyword: # Not found raise ScriptError(f'Cannot find a {cls.__name__} instance that matches "{name}"') + + +class KeywordDigitCounter(Keyword): + """ + A fake Keyword class to filter digit counters in ocr results + OcrResultButton.match_keyword will be a str + """ + @classmethod + def find(cls, name, lang: str = None, ignore_punctuation=True): + from module.ocr.ocr import DigitCounter + if DigitCounter.is_format_matched(name): + return name + else: + raise ScriptError diff --git a/module/ocr/ocr.py b/module/ocr/ocr.py index a099d2691..82fb32d39 100644 --- a/module/ocr/ocr.py +++ b/module/ocr/ocr.py @@ -1,7 +1,6 @@ import re import time from datetime import timedelta -from typing import Optional import cv2 import numpy as np @@ -13,13 +12,12 @@ from module.base.decorator import cached_property from module.base.utils import area_pad, corner2area, crop, extract_white_letters, float2str from module.exception import ScriptError from module.logger import logger -from module.ocr.keyword import Keyword from module.ocr.models import OCR_MODEL, TextSystem from module.ocr.utils import merge_buttons class OcrResultButton: - def __init__(self, boxed_result: BoxedResult, matched_keyword: Optional[Keyword]): + def __init__(self, boxed_result: BoxedResult, matched_keyword): """ Args: boxed_result: BoxedResult from ppocr-onnx diff --git a/module/ocr/utils.py b/module/ocr/utils.py index 357836ff9..d7a1584d5 100644 --- a/module/ocr/utils.py +++ b/module/ocr/utils.py @@ -74,8 +74,8 @@ def pair_buttons(group1, group2, relative_area): Pair buttons in group1 with those in group2 in the relative_area. Args: - group1 (list[OcrResultButton]): - group2 (list[OcrResultButton]): + group1 (list[OcrResultButton], Iterable[OcrResultButton]): + group2 (list[OcrResultButton], Iterable[OcrResultButton]): relative_area (tuple[int, int, int, int]): Yields: diff --git a/tasks/battle_pass/battle_pass.py b/tasks/battle_pass/battle_pass.py index 486170fd5..9992845e0 100644 --- a/tasks/battle_pass/battle_pass.py +++ b/tasks/battle_pass/battle_pass.py @@ -1,14 +1,17 @@ import datetime import re +from dataclasses import dataclass import numpy as np from module.base.timer import Timer from module.base.utils import get_color +from module.config.stored.classes import StoredCounter from module.config.utils import get_server_next_update from module.logger.logger import logger -from module.ocr.ocr import Digit, Duration, Ocr -from module.ocr.utils import split_and_pair_buttons +from module.ocr.keyword import KeywordDigitCounter +from module.ocr.ocr import Digit, DigitCounter, Duration, Ocr, OcrResultButton +from module.ocr.utils import pair_buttons from module.ui.scroll import Scroll from module.ui.switch import Switch from tasks.base.assets.assets_base_page import BATTLE_PASS_CHECK, MAIN_GOTO_BATTLE_PASS @@ -67,6 +70,20 @@ class BattlePassQuestOcr(Ocr): return result +@dataclass +class DataBattlePassQuest: + quest: BattlePassQuest + state: BattlePassQuestState = None + digit: KeywordDigitCounter = '' + + def __eq__(self, other): + return self.quest == other.quest + + @property + def is_incomplete(self) -> bool: + return self.state == KEYWORD_BATTLE_PASS_QUEST_STATE.Navigate + + class BattlePassUI(UI): MAX_LEVEL = 70 @@ -239,8 +256,7 @@ class BattlePassUI(UI): # Update quests self.battle_pass_mission_tab_goto( KEYWORD_BATTLE_PASS_MISSION_TAB.This_Week_Missions) - quests = self.battle_pass_quests_recognition() - self.config.stored.BattlePassWeeklyQuest.write_quests(quests) + self.battle_pass_quests_recognition() if previous_level == self.MAX_LEVEL: return previous_level @@ -253,20 +269,32 @@ class BattlePassUI(UI): self._claim_rewards() return current_level - def ocr_single_page(self): + def ocr_single_page(self) -> list[DataBattlePassQuest]: """ Returns incomplete quests only """ + logger.hr('Battle pass ocr single page') ocr = BattlePassQuestOcr(OCR_BATTLE_PASS_QUEST) - results = ocr.matched_ocr(self.device.image, [BattlePassQuest, BattlePassQuestState]) + results = ocr.matched_ocr( + self.device.image, keyword_classes=[BattlePassQuest, BattlePassQuestState, KeywordDigitCounter]) - def completed_state(state): - return state != KEYWORD_BATTLE_PASS_QUEST_STATE.Navigate + # Product DataBattlePassQuest objects + data_quest: dict[OcrResultButton, DataBattlePassQuest] = { + result: DataBattlePassQuest(result.matched_keyword) + for result in results if isinstance(result.matched_keyword, BattlePassQuest) + } + # Update quest state + list_attr = [result for result in results if isinstance(result.matched_keyword, BattlePassQuestState)] + for quest, state in pair_buttons(data_quest, list_attr, relative_area=(0, 0, 800, 100)): + data_quest[quest].state = state.matched_keyword + # Update quest progress + list_attr = [result for result in results if isinstance(result.matched_keyword, str)] + for quest, digit in pair_buttons(data_quest, list_attr, relative_area=(-50, 0, 200, 70)): + data_quest[quest].digit = digit.matched_keyword - return [incomplete_quest for incomplete_quest, _ in - split_and_pair_buttons(results, split_func=completed_state, relative_area=(0, 0, 800, 100))] + return list(data_quest.values()) - def battle_pass_quests_recognition(self) -> list[BattlePassQuest]: + def battle_pass_quests_recognition(self): """ Pages: in: page_battle_pass, KEYWORD_BATTLE_PASS_TAB.Missions, weekly or period @@ -275,7 +303,7 @@ class BattlePassUI(UI): scroll = Scroll(MISSION_PAGE_SCROLL, color=(198, 198, 198)) scroll.set_top(main=self) - results = [] + results: list[DataBattlePassQuest] = [] while 1: results += [result for result in self.ocr_single_page() if result not in results] if scroll.at_bottom(main=self): @@ -284,8 +312,50 @@ class BattlePassUI(UI): else: scroll.next_page(main=self) - results = [result.matched_keyword for result in results] - return results + # Convert quest keyword to stored object + dic_quest_to_stored = { + KEYWORD_BATTLE_PASS_QUEST.Complete_Simulated_Universe_1_times: + self.config.stored.BattlePassSimulatedUniverse, + KEYWORD_BATTLE_PASS_QUEST.Clear_Calyx_1_times: + self.config.stored.BattlePassQuestCalyx, + KEYWORD_BATTLE_PASS_QUEST.Complete_Echo_of_War_1_times: + self.config.stored.BattlePassQuestEchoOfWar, + KEYWORD_BATTLE_PASS_QUEST.Use_300000_credits: + self.config.stored.BattlePassQuestCredits, + KEYWORD_BATTLE_PASS_QUEST.Synthesize_Consumables_1_times: + self.config.stored.BattlePassQuestSynthesizeConsumables, + KEYWORD_BATTLE_PASS_QUEST.Clear_Cavern_of_Corrosion_1_times: + self.config.stored.BattlePassQuestCavernOfCorrosion, + KEYWORD_BATTLE_PASS_QUEST.Consume_a_total_of_1_Trailblaze_Power_1400_Trailblazer_Power_max: + self.config.stored.BattlePassQuestTrailblazePower, + } + with self.config.multi_set(): + # Write incomplete quests + quests = [result.quest for result in results if result.is_incomplete] + self.config.stored.BattlePassWeeklyQuest.write_quests(quests) + # Create an OCR object just for calling format_result() + ocr = DigitCounter(OCR_BATTLE_PASS_QUEST) + # Write quest progresses + for result in results: + ocr.name = result.quest.name + current, _, total = ocr.format_result(result.digit) + if total == 0: + logger.error(f'Battle pass quests {result.quest} progress invalid: {result.digit}') + continue + stored: StoredCounter = dic_quest_to_stored.get(result.quest, None) + # Check if exist + if stored is None: + logger.error(f'Battle pass quest {result.quest} has not corresponding stored object') + continue + # Check total + if stored.FIXED_TOTAL and total != stored.FIXED_TOTAL: + logger.error(f'Battle pass quest progress {current}/{total} does not match its stored object') + continue + if hasattr(stored, 'LIST_TOTAL') and total not in stored.LIST_TOTAL: + logger.error(f'Battle pass quest progress {current}/{total} is not in LIST_TOTAL') + continue + # Set + stored.set(current, total=total) def has_battle_pass_entrance(self, skip_first_screenshot=True): """ diff --git a/tasks/battle_pass/keywords/classes.py b/tasks/battle_pass/keywords/classes.py index 7bac877e3..f92067820 100644 --- a/tasks/battle_pass/keywords/classes.py +++ b/tasks/battle_pass/keywords/classes.py @@ -26,6 +26,9 @@ class BattlePassQuest(Keyword): return remove_digit(name) == remove_digit(keyword) + def __hash__(self) -> int: + return super().__hash__() + @dataclass(repr=False) class BattlePassQuestState(Keyword):