Upd: use combination instead of inheritance in RogueSelector

This commit is contained in:
Hengyu 2023-08-15 03:35:15 +08:00
parent 03caaa2855
commit 5a06402d43
9 changed files with 152 additions and 135 deletions

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,25 @@
from module.base.button import Button, ButtonWrapper
# This file was auto-generated, do not modify it manually. To generate:
# ``` python -m dev_tools.button_extract ```
BONUS_BOTTOM_WHITE_BAR = ButtonWrapper(
name='BONUS_BOTTOM_WHITE_BAR',
share=Button(
file='./assets/share/rogue/bonus/BONUS_BOTTOM_WHITE_BAR.png',
area=(182, 568, 1098, 590),
search=(162, 548, 1118, 610),
color=(221, 221, 222),
button=(182, 568, 1098, 590),
),
)
BONUS_CONFIRM = ButtonWrapper(
name='BONUS_CONFIRM',
share=Button(
file='./assets/share/rogue/bonus/BONUS_CONFIRM.png',
area=(504, 629, 620, 677),
search=(484, 609, 640, 697),
color=(222, 224, 224),
button=(504, 629, 620, 677),
),
)

View File

@ -3,26 +3,6 @@ from module.base.button import Button, ButtonWrapper
# This file was auto-generated, do not modify it manually. To generate: # This file was auto-generated, do not modify it manually. To generate:
# ``` python -m dev_tools.button_extract ``` # ``` python -m dev_tools.button_extract ```
BONUS_BOTTOM_WHITE_BAR = ButtonWrapper(
name='BONUS_BOTTOM_WHITE_BAR',
share=Button(
file='./assets/share/rogue/ui/BONUS_BOTTOM_WHITE_BAR.png',
area=(182, 568, 1098, 590),
search=(162, 548, 1118, 610),
color=(221, 221, 222),
button=(182, 568, 1098, 590),
),
)
BONUS_CONFIRM = ButtonWrapper(
name='BONUS_CONFIRM',
share=Button(
file='./assets/share/rogue/ui/BONUS_CONFIRM.png',
area=(504, 629, 620, 677),
search=(484, 609, 640, 697),
color=(222, 224, 224),
button=(504, 629, 620, 677),
),
)
CHECK_BLESSING = ButtonWrapper( CHECK_BLESSING = ButtonWrapper(
name='CHECK_BLESSING', name='CHECK_BLESSING',
share=Button( share=Button(

View File

@ -12,7 +12,6 @@ from tasks.rogue.assets.assets_rogue_ui import CONFIRM
from tasks.rogue.keywords import * from tasks.rogue.keywords import *
from tasks.rogue.preset import * from tasks.rogue.preset import *
from tasks.rogue.selector import RogueSelector from tasks.rogue.selector import RogueSelector
from tasks.rogue.ui import RogueUI
from tasks.rogue.utils import get_regex_from_keyword_name, parse_name, is_card_selected from tasks.rogue.utils import get_regex_from_keyword_name, parse_name, is_card_selected
# normal blessing # normal blessing
@ -78,7 +77,7 @@ class RogueBuffOcr(Ocr):
return result return result
class RogueBlessingSelector(RogueUI, RogueSelector): class RogueBlessingSelector(RogueSelector):
""" """
Usage: Usage:
self = RogueBlessingSelector('alas') self = RogueBlessingSelector('alas')
@ -90,9 +89,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
""" """
Returns: The number of blessing Returns: The number of blessing
""" """
if not self.image_color_count(BOTTOM_WHITE_BAR.area, color=(255, 255, 255), count=5000): if not self.main.image_color_count(BOTTOM_WHITE_BAR.area, color=(255, 255, 255), count=5000):
return 0 return 0
color = get_color(self.device.image, BOTTOM_WHITE_BAR.area) color = get_color(self.main.device.image, BOTTOM_WHITE_BAR.area)
mean = np.mean(color) mean = np.mean(color)
return int(mean // 60) # the magic number that maps blessing num with mean_color return int(mean // 60) # the magic number that maps blessing num with mean_color
@ -100,7 +99,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
self.ocr_results = [] self.ocr_results = []
self._wait_until_blessing_loaded() self._wait_until_blessing_loaded()
ocr = RogueBuffOcr(OCR_ROGUE_BUFF) ocr = RogueBuffOcr(OCR_ROGUE_BUFF)
results = ocr.matched_ocr(self.device.image, [RogueBlessing, RogueResonance]) results = ocr.matched_ocr(self.main.device.image, [RogueBlessing, RogueResonance])
blessing_count = self.get_blessing_count() blessing_count = self.get_blessing_count()
if blessing_count != len(results): if blessing_count != len(results):
logger.warning(f"The OCR result does not match the blessing count. " logger.warning(f"The OCR result does not match the blessing count. "
@ -121,8 +120,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
Case 2: choose curio Case 2: choose curio
Case 3: another choose blessings, but no blessing is selected when the new selection page loaded Case 3: another choose blessings, but no blessing is selected when the new selection page loaded
""" """
return (self.is_in_main() or self.is_page_choose_curio() return (self.main.is_in_main() or self.main.is_page_choose_curio()
or (self.is_page_choose_blessing() and not is_card_selected(self, target, confirm_button=CONFIRM))) or (self.main.is_page_choose_blessing() and
not is_card_selected(self.main, target, confirm_button=CONFIRM)))
interval = Timer(1) interval = Timer(1)
enforce = False enforce = False
@ -135,9 +135,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
if skip_first_screenshot: if skip_first_screenshot:
skip_first_screenshot = False skip_first_screenshot = False
else: else:
self.device.screenshot() self.main.device.screenshot()
if is_card_selected(self, target, confirm_button=CONFIRM): if is_card_selected(self.main, target, confirm_button=CONFIRM):
if enforce: if enforce:
logger.info("Buff selected (enforce)") logger.info("Buff selected (enforce)")
else: else:
@ -145,9 +145,9 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
break break
if interval.reached(): if interval.reached():
if enforce: if enforce:
self.device.click(BLESSING_ENFORCE) self.main.device.click(BLESSING_ENFORCE)
else: else:
self.device.click(target) self.main.device.click(target)
interval.reset() interval.reset()
skip_first_screenshot = True skip_first_screenshot = True
@ -156,16 +156,16 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
if skip_first_screenshot: if skip_first_screenshot:
skip_first_screenshot = False skip_first_screenshot = False
else: else:
self.device.screenshot() self.main.device.screenshot()
if is_select_blessing_complete(): if is_select_blessing_complete():
break break
if interval.reached(): if interval.reached():
self.device.click(CONFIRM) self.main.device.click(CONFIRM)
interval.reset() interval.reset()
def _get_reset_count(self): def _get_reset_count(self):
current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.device.image) current, _, _ = DigitCounter(OCR_RESET_COUNT).ocr_single_line(self.main.device.image)
return current return current
def _wait_until_blessing_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)): def _wait_until_blessing_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
@ -173,7 +173,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
timeout.reset() timeout.reset()
previous_count = self.get_blessing_count() previous_count = self.get_blessing_count()
while 1: while 1:
self.device.screenshot() self.main.device.screenshot()
blessing_count = self.get_blessing_count() blessing_count = self.get_blessing_count()
if timeout.reached(): if timeout.reached():
@ -189,7 +189,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
timer.reset() timer.reset()
def reset_blessing_list(self, skip_first_screenshot=True): def reset_blessing_list(self, skip_first_screenshot=True):
if not self.is_page_choose_blessing(): if not self.main.is_page_choose_blessing():
return False return False
reset_count = self._get_reset_count() reset_count = self._get_reset_count()
@ -197,8 +197,8 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
logger.info("Does not have enough reset count") logger.info("Does not have enough reset count")
return False return False
reset_cost = Digit(OCR_RESET_COST).ocr_single_line(self.device.image) reset_cost = Digit(OCR_RESET_COST).ocr_single_line(self.main.device.image)
if reset_cost > self.cosmic_fragment: if reset_cost > self.main.cosmic_fragment:
logger.info("Does not have enough cosmic fragment") logger.info("Does not have enough cosmic fragment")
return False return False
@ -207,7 +207,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
if skip_first_screenshot: if skip_first_screenshot:
skip_first_screenshot = False skip_first_screenshot = False
else: else:
self.device.screenshot() self.main.device.screenshot()
new_count = self._get_reset_count() new_count = self._get_reset_count()
@ -215,7 +215,7 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
logger.info("Reset once") logger.info("Reset once")
break break
if interval.reached(): if interval.reached():
self.device.click(BLESSING_RESET) self.main.device.click(BLESSING_RESET)
interval.reset() interval.reset()
return True return True
@ -224,16 +224,16 @@ class RogueBlessingSelector(RogueUI, RogueSelector):
keyword = self.ocr_results[0].matched_keyword keyword = self.ocr_results[0].matched_keyword
if isinstance(keyword, RogueBlessing): if isinstance(keyword, RogueBlessing):
filter_ = BLESSING_FILTER filter_ = BLESSING_FILTER
if self.config.Rogue_PresetBlessingFilter == 'preset-1': if self.main.config.Rogue_PresetBlessingFilter == 'preset-1':
filter_.load(parse_name(BLESSING_PRESET_1)) filter_.load(parse_name(BLESSING_PRESET_1))
if self.config.Rogue_PresetBlessingFilter == 'custom': if self.main.config.Rogue_PresetBlessingFilter == 'custom':
filter_.load(parse_name(self.config.Rogue_CustomBlessingFilter)) filter_.load(parse_name(self.main.config.Rogue_CustomBlessingFilter))
if isinstance(keyword, RogueResonance): if isinstance(keyword, RogueResonance):
filter_ = RESONANCE_FILTER filter_ = RESONANCE_FILTER
if self.config.Rogue_PresetResonanceFilter == 'preset-1': if self.main.config.Rogue_PresetResonanceFilter == 'preset-1':
RESONANCE_FILTER.load(parse_name(RESONANCE_PRESET_1)) RESONANCE_FILTER.load(parse_name(RESONANCE_PRESET_1))
if self.config.Rogue_PresetResonanceFilter == 'custom': if self.main.config.Rogue_PresetResonanceFilter == 'custom':
RESONANCE_FILTER.load(parse_name(self.config.Rogue_CustomResonanceFilter)) RESONANCE_FILTER.load(parse_name(self.main.config.Rogue_CustomResonanceFilter))
self.filter_ = filter_ self.filter_ = filter_
def try_select(self, option: OcrResultButton | str): def try_select(self, option: OcrResultButton | str):

83
tasks/rogue/bonus.py Normal file
View File

@ -0,0 +1,83 @@
import numpy as np
from module.base.timer import Timer
from module.logger import logger
from module.ocr.ocr import OcrResultButton
from tasks.rogue.assets.assets_rogue_blessing import OCR_ROGUE_BUFF
from tasks.rogue.assets.assets_rogue_bonus import BONUS_BOTTOM_WHITE_BAR, BONUS_CONFIRM
from tasks.rogue.keywords import RogueBonus
from tasks.rogue.selector import RogueSelector
from tasks.rogue.ui import RogueBonusOcr
from tasks.rogue.utils import is_card_selected
class RogueBonusSelector(RogueSelector):
def _wait_bonus_page_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
timer.reset()
timeout.reset()
while 1:
self.main.device.screenshot()
if timeout.reached():
logger.warning('Wait bonus page loaded timeout')
break
if self.main.appear(BONUS_BOTTOM_WHITE_BAR):
if timer.reached():
logger.info('Bonus page stabled')
break
else:
timer.reset()
def recognition(self):
self._wait_bonus_page_loaded()
ocr = RogueBonusOcr(OCR_ROGUE_BUFF)
results = ocr.matched_ocr(self.main.device.image, [RogueBonus])
expected_count = 3
if expected_count != len(results):
logger.warning(f"The OCR result does not match the bonus count. "
f"Expect {expected_count}, but recognized {len(results)} only.")
self.ocr_results = results
return results
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
interval = Timer(1)
# start -> select
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.main.device.screenshot()
if is_card_selected(self.main, target, confirm_button=BONUS_CONFIRM):
break
if interval.reached():
self.main.device.click(target)
interval.reset()
skip_first_screenshot = True
# select -> confirm
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.main.device.screenshot()
if self.main.is_in_main() or self.main.is_page_choose_curio() or self.main.is_page_choose_blessing():
break
if interval.reached():
self.main.device.click(BONUS_CONFIRM)
interval.reset()
def recognize_and_select(self):
self.recognition()
if not self.ocr_results:
self.ui_select(None)
options = {result.matched_keyword.en: result for result in self.ocr_results}
if self.main.config.Rogue_Bonus not in options.keys():
logger.warning(f"Can not find option: {self.main.config.Rogue_Bonus}, randomly choose one")
target = np.random.choice(options)
else:
target = options[self.main.config.Rogue_Bonus]
logger.info(f"Choose bonus: {target}")
self.ui_select(target)

View File

@ -12,7 +12,6 @@ from tasks.rogue.assets.assets_rogue_ui import CONFIRM
from tasks.rogue.keywords import RogueCurio from tasks.rogue.keywords import RogueCurio
from tasks.rogue.preset import CURIO_PRESET_1 from tasks.rogue.preset import CURIO_PRESET_1
from tasks.rogue.selector import RogueSelector from tasks.rogue.selector import RogueSelector
from tasks.rogue.ui import RogueUI
from tasks.rogue.utils import get_regex_from_keyword_name, parse_name from tasks.rogue.utils import get_regex_from_keyword_name, parse_name
CURIO_FILTER_ATTR = tuple() CURIO_FILTER_ATTR = tuple()
@ -36,11 +35,11 @@ class RogueCurioOcr(Ocr):
return result return result
class RogueCurioSelector(RogueUI, RogueSelector): class RogueCurioSelector(RogueSelector):
def recognition(self): def recognition(self):
self.ocr_results = [] self.ocr_results = []
ocr = RogueCurioOcr(OCR_ROGUE_CURIO) ocr = RogueCurioOcr(OCR_ROGUE_CURIO)
results = ocr.matched_ocr(self.device.image, RogueCurio) results = ocr.matched_ocr(self.main.device.image, RogueCurio)
expect_num = 3 expect_num = 3
if len(results) != expect_num: if len(results) != expect_num:
logger.warning(f"The OCR result does not match the curio count. " logger.warning(f"The OCR result does not match the curio count. "
@ -50,13 +49,13 @@ class RogueCurioSelector(RogueUI, RogueSelector):
def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True): def ui_select(self, target: OcrResultButton | None, skip_first_screenshot=True):
def is_curio_selected(): def is_curio_selected():
return np.mean(get_color(self.device.image, tuple(target.area))) > 70 # shiny background return np.mean(get_color(self.main.device.image, tuple(target.area))) > 70 # shiny background
def is_select_curio_complete(): def is_select_curio_complete():
""" """
Case 1: back to main page Case 1: back to main page
""" """
return self.is_in_main() return self.main.is_in_main()
enforce = False enforce = False
if not target: if not target:
@ -67,7 +66,7 @@ class RogueCurioSelector(RogueUI, RogueSelector):
if skip_first_screenshot: if skip_first_screenshot:
skip_first_screenshot = False skip_first_screenshot = False
else: else:
self.device.screenshot() self.main.device.screenshot()
if is_curio_selected(): if is_curio_selected():
if enforce: if enforce:
@ -77,9 +76,9 @@ class RogueCurioSelector(RogueUI, RogueSelector):
break break
if interval.reached(): if interval.reached():
if enforce: if enforce:
self.device.click(CURIO_ENFORCE) self.main.device.click(CURIO_ENFORCE)
else: else:
self.device.click(target) self.main.device.click(target)
interval.reset() interval.reset()
skip_first_screenshot = True skip_first_screenshot = True
@ -88,12 +87,12 @@ class RogueCurioSelector(RogueUI, RogueSelector):
if skip_first_screenshot: if skip_first_screenshot:
skip_first_screenshot = False skip_first_screenshot = False
else: else:
self.device.screenshot() self.main.device.screenshot()
if is_select_curio_complete(): if is_select_curio_complete():
break break
if interval.reached(): if interval.reached():
self.device.click(CONFIRM) self.main.device.click(CONFIRM)
interval.reset() interval.reset()
def try_select(self, option: OcrResultButton | str): def try_select(self, option: OcrResultButton | str):
@ -108,8 +107,8 @@ class RogueCurioSelector(RogueUI, RogueSelector):
def load_filter(self): def load_filter(self):
filter_ = CURIO_FILTER filter_ = CURIO_FILTER
if self.config.Rogue_PresetCurioFilter == 'preset-1': if self.main.config.Rogue_PresetCurioFilter == 'preset-1':
filter_.load(parse_name(CURIO_PRESET_1)) filter_.load(parse_name(CURIO_PRESET_1))
if self.config.Rogue_PresetCurioFilter == 'custom': if self.main.config.Rogue_PresetCurioFilter == 'custom':
filter_.load(parse_name(self.config.Rogue_CustomCurioFilter)) filter_.load(parse_name(self.main.config.Rogue_CustomCurioFilter))
self.filter_ = filter_ self.filter_ = filter_

View File

@ -4,12 +4,17 @@ from module.base.filter import MultiLangFilter
from module.logger import logger from module.logger import logger
from module.ocr.keyword import Keyword from module.ocr.keyword import Keyword
from module.ocr.ocr import OcrResultButton from module.ocr.ocr import OcrResultButton
from tasks.rogue.ui import RogueUI
class RogueSelector: class RogueSelector:
""" """
An Interface used in blessing, curio, and other ui selection in rogue An Interface used in blessing, curio, and other ui selection in rogue
""" """
def __init__(self, main: RogueUI):
self.main = main
ocr_results: list[OcrResultButton] ocr_results: list[OcrResultButton]
filter_: MultiLangFilter filter_: MultiLangFilter
preset_methods: dict[str, callable] preset_methods: dict[str, callable]

View File

@ -1,15 +1,9 @@
import re import re
import numpy as np from module.ocr.ocr import Digit, Ocr
from module.base.timer import Timer
from module.logger import logger
from module.ocr.ocr import Digit, Ocr, OcrResultButton
from tasks.base.ui import UI from tasks.base.ui import UI
from tasks.rogue.assets.assets_rogue_blessing import OCR_ROGUE_BUFF
from tasks.rogue.assets.assets_rogue_ui import * from tasks.rogue.assets.assets_rogue_ui import *
from tasks.rogue.keywords import * from tasks.rogue.keywords import *
from tasks.rogue.utils import is_card_selected
class RogueBonusOcr(Ocr): class RogueBonusOcr(Ocr):
@ -43,72 +37,3 @@ class RogueUI(UI):
def is_page_choose_bonus(self): def is_page_choose_bonus(self):
return self.appear(PAGE_CHOOSE_BONUS) return self.appear(PAGE_CHOOSE_BONUS)
def _wait_bonus_page_loaded(self, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
timer.reset()
timeout.reset()
while 1:
self.device.screenshot()
if timeout.reached():
logger.warning('Wait bonus page loaded timeout')
break
if self.appear(BONUS_BOTTOM_WHITE_BAR):
if timer.reached():
logger.info('Bonus page stabled')
break
else:
timer.reset()
def bonus_recognition(self):
self._wait_bonus_page_loaded()
ocr = RogueBonusOcr(OCR_ROGUE_BUFF)
results = ocr.matched_ocr(self.device.image, [RogueBonus])
expected_count = 3
if expected_count != len(results):
logger.warning(f"The OCR result does not match the bonus count. "
f"Expect {expected_count}, but recognized {len(results)} only.")
return results
def ui_choose_bonus(self, target: OcrResultButton | None, skip_first_screenshot=True):
interval = Timer(1)
# start -> select
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if is_card_selected(self, target, confirm_button=BONUS_CONFIRM):
break
if interval.reached():
self.device.click(target)
interval.reset()
skip_first_screenshot = True
# select -> confirm
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.is_in_main() or self.is_page_choose_curio() or self.is_page_choose_blessing():
break
if interval.reached():
self.device.click(BONUS_CONFIRM)
interval.reset()
def recognize_and_select_bonus(self):
results = self.bonus_recognition()
if not results:
self.ui_choose_bonus(None)
options = {result.matched_keyword.en: result for result in results}
if self.config.Rogue_Bonus not in options.keys():
logger.warning(f"Can not find option: {self.config.Rogue_Bonus}, randomly choose one")
target = np.random.choice(options)
else:
target = options[self.config.Rogue_Bonus]
logger.info(f"Choose bonus: {target}")
self.ui_choose_bonus(target)