1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2026-06-09 20:04:52 +00:00

Upload code

This commit is contained in:
2023-11-01 15:33:35 +08:00
commit 6860f2eb72
415 changed files with 50990 additions and 0 deletions
+385
View File
@@ -0,0 +1,385 @@
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 ```
ACCOUNT_INFO_CHECK = ButtonWrapper(
name='ACCOUNT_INFO_CHECK',
jp=Button(
file='./assets/jp/base/page/ACCOUNT_INFO_CHECK.png',
area=(108, 11, 235, 36),
search=(88, 0, 255, 56),
color=(193, 201, 210),
button=(108, 11, 235, 36),
),
)
BACK = ButtonWrapper(
name='BACK',
jp=Button(
file='./assets/jp/base/page/BACK.png',
area=(34, 19, 81, 56),
search=(14, 0, 101, 76),
color=(93, 118, 164),
button=(34, 19, 81, 56),
),
)
BOUNTY_CHECK = ButtonWrapper(
name='BOUNTY_CHECK',
jp=Button(
file='./assets/jp/base/page/BOUNTY_CHECK.png',
area=(107, 10, 158, 37),
search=(87, 0, 178, 57),
color=(150, 164, 177),
button=(107, 10, 158, 37),
),
)
CAFE_CHECK = ButtonWrapper(
name='CAFE_CHECK',
jp=Button(
file='./assets/jp/base/page/CAFE_CHECK.png',
area=(264, 11, 337, 35),
search=(244, 0, 357, 55),
color=(188, 197, 205),
button=(264, 11, 337, 35),
),
)
CIRCLE_CHECK = ButtonWrapper(
name='CIRCLE_CHECK',
jp=Button(
file='./assets/jp/base/page/CIRCLE_CHECK.png',
area=(107, 11, 211, 36),
search=(87, 0, 231, 56),
color=(195, 203, 211),
button=(107, 11, 211, 36),
),
)
COMMISSIONS_CHECK = ButtonWrapper(
name='COMMISSIONS_CHECK',
jp=Button(
file='./assets/jp/base/page/COMMISSIONS_CHECK.png',
area=(107, 10, 158, 37),
search=(87, 0, 178, 57),
color=(146, 160, 174),
button=(107, 10, 158, 37),
),
)
CRAFTING_CHECK = ButtonWrapper(
name='CRAFTING_CHECK',
jp=Button(
file='./assets/jp/base/page/CRAFTING_CHECK.png',
area=(108, 10, 214, 37),
search=(88, 0, 234, 57),
color=(200, 208, 215),
button=(108, 10, 214, 37),
),
)
GACHA_CHECK = ButtonWrapper(
name='GACHA_CHECK',
jp=Button(
file='./assets/jp/base/page/GACHA_CHECK.png',
area=(159, 10, 210, 37),
search=(139, 0, 230, 57),
color=(135, 148, 164),
button=(159, 10, 210, 37),
),
)
HOME = ButtonWrapper(
name='HOME',
jp=Button(
file='./assets/jp/base/page/HOME.png',
area=(1218, 8, 1253, 41),
search=(1198, 0, 1273, 61),
color=(168, 182, 205),
button=(1218, 8, 1253, 41),
),
)
LOADING_CHECK = ButtonWrapper(
name='LOADING_CHECK',
jp=Button(
file='./assets/jp/base/page/LOADING_CHECK.png',
area=(1084, 659, 1120, 674),
search=(1064, 639, 1140, 694),
color=(173, 196, 219),
button=(1084, 659, 1120, 674),
),
)
MAIL_CHECK = ButtonWrapper(
name='MAIL_CHECK',
jp=Button(
file='./assets/jp/base/page/MAIL_CHECK.png',
area=(108, 9, 186, 37),
search=(88, 0, 206, 57),
color=(205, 212, 219),
button=(108, 9, 186, 37),
),
)
MAIN_GO_TO_CAFE = ButtonWrapper(
name='MAIN_GO_TO_CAFE',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_CAFE.png',
area=(81, 638, 102, 668),
search=(61, 618, 122, 688),
color=(156, 209, 233),
button=(81, 638, 102, 668),
),
)
MAIN_GO_TO_CIRCLE = ButtonWrapper(
name='MAIN_GO_TO_CIRCLE',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_CIRCLE.png',
area=(540, 631, 583, 660),
search=(520, 611, 603, 680),
color=(131, 204, 234),
button=(540, 631, 583, 660),
),
)
MAIN_GO_TO_CRAFTING = ButtonWrapper(
name='MAIN_GO_TO_CRAFTING',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_CRAFTING.png',
area=(665, 622, 693, 664),
search=(645, 602, 713, 684),
color=(192, 229, 241),
button=(665, 622, 693, 664),
),
)
MAIN_GO_TO_GACHA = ButtonWrapper(
name='MAIN_GO_TO_GACHA',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_GACHA.png',
area=(900, 623, 924, 670),
search=(880, 603, 944, 690),
color=(157, 219, 241),
button=(900, 623, 924, 670),
),
)
MAIN_GO_TO_MAIL = ButtonWrapper(
name='MAIN_GO_TO_MAIL',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_MAIL.png',
area=(1130, 29, 1156, 49),
search=(1110, 9, 1176, 69),
color=(94, 121, 166),
button=(1130, 29, 1156, 49),
),
)
MAIN_GO_TO_MOMOTALK = ButtonWrapper(
name='MAIN_GO_TO_MOMOTALK',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_MOMOTALK.png',
area=(154, 134, 177, 158),
search=(134, 114, 197, 178),
color=(255, 219, 227),
button=(154, 134, 177, 158),
),
)
MAIN_GO_TO_PURCHASE = ButtonWrapper(
name='MAIN_GO_TO_PURCHASE',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_PURCHASE.png',
area=(148, 204, 183, 253),
search=(128, 184, 203, 273),
color=(172, 214, 239),
button=(148, 204, 183, 253),
),
)
MAIN_GO_TO_SCHEDULE = ButtonWrapper(
name='MAIN_GO_TO_SCHEDULE',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_SCHEDULE.png',
area=(194, 638, 216, 672),
search=(174, 618, 236, 692),
color=(149, 194, 222),
button=(194, 638, 216, 672),
),
)
MAIN_GO_TO_SHOP = ButtonWrapper(
name='MAIN_GO_TO_SHOP',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_SHOP.png',
area=(773, 630, 816, 667),
search=(753, 610, 836, 687),
color=(146, 208, 235),
button=(773, 630, 816, 667),
),
)
MAIN_GO_TO_TASK = ButtonWrapper(
name='MAIN_GO_TO_TASK',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_TASK.png',
area=(52, 220, 78, 248),
search=(32, 200, 98, 268),
color=(226, 207, 203),
button=(52, 220, 78, 248),
),
)
MAIN_GO_TO_WORK = ButtonWrapper(
name='MAIN_GO_TO_WORK',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_WORK.png',
area=(1167, 605, 1241, 632),
search=(1147, 585, 1261, 652),
color=(135, 149, 169),
button=(1167, 605, 1241, 632),
),
)
MISSION_CHECK = ButtonWrapper(
name='MISSION_CHECK',
jp=Button(
file='./assets/jp/base/page/MISSION_CHECK.png',
area=(108, 12, 183, 36),
search=(88, 0, 203, 56),
color=(188, 197, 206),
button=(108, 12, 183, 36),
),
)
MOMOTALK_CHECK = ButtonWrapper(
name='MOMOTALK_CHECK',
jp=Button(
file='./assets/jp/base/page/MOMOTALK_CHECK.png',
area=(144, 107, 169, 130),
search=(124, 87, 189, 150),
color=(253, 211, 219),
button=(144, 107, 169, 130),
),
)
MOMOTALK_GO_TO_MAIN = ButtonWrapper(
name='MOMOTALK_GO_TO_MAIN',
jp=Button(
file='./assets/jp/base/page/MOMOTALK_GO_TO_MAIN.png',
area=(1108, 105, 1134, 131),
search=(1088, 85, 1154, 151),
color=(252, 182, 194),
button=(1108, 105, 1134, 131),
),
)
SCHEDULE_CHECK = ButtonWrapper(
name='SCHEDULE_CHECK',
jp=Button(
file='./assets/jp/base/page/SCHEDULE_CHECK.png',
area=(108, 12, 159, 36),
search=(88, 0, 179, 56),
color=(188, 197, 206),
button=(108, 12, 159, 36),
),
)
SCHOOL_EXCHANGE_CHECK = ButtonWrapper(
name='SCHOOL_EXCHANGE_CHECK',
jp=Button(
file='./assets/jp/base/page/SCHOOL_EXCHANGE_CHECK.png',
area=(107, 11, 158, 36),
search=(87, 0, 178, 56),
color=(134, 149, 164),
button=(107, 11, 158, 36),
),
)
SHOP_CHECK = ButtonWrapper(
name='SHOP_CHECK',
jp=Button(
file='./assets/jp/base/page/SHOP_CHECK.png',
area=(108, 10, 212, 36),
search=(88, 0, 232, 56),
color=(200, 208, 215),
button=(108, 10, 212, 36),
),
)
STORY_CHECK = ButtonWrapper(
name='STORY_CHECK',
jp=Button(
file='./assets/jp/base/page/STORY_CHECK.png',
area=(108, 11, 157, 36),
search=(88, 0, 177, 56),
color=(194, 203, 211),
button=(108, 11, 157, 36),
),
)
TACTICAL_CHALLENGE_CHECK = ButtonWrapper(
name='TACTICAL_CHALLENGE_CHECK',
jp=Button(
file='./assets/jp/base/page/TACTICAL_CHALLENGE_CHECK.png',
area=(107, 11, 133, 37),
search=(87, 0, 153, 57),
color=(129, 145, 161),
button=(107, 11, 133, 37),
),
)
TASK_CHECK = ButtonWrapper(
name='TASK_CHECK',
jp=Button(
file='./assets/jp/base/page/TASK_CHECK.png',
area=(109, 12, 155, 36),
search=(89, 0, 175, 56),
color=(189, 198, 207),
button=(109, 12, 155, 36),
),
)
WORK_CHECK = ButtonWrapper(
name='WORK_CHECK',
jp=Button(
file='./assets/jp/base/page/WORK_CHECK.png',
area=(107, 10, 185, 38),
search=(87, 0, 205, 58),
color=(164, 175, 187),
button=(107, 10, 185, 38),
),
)
WORK_GO_TO_BOUNTY = ButtonWrapper(
name='WORK_GO_TO_BOUNTY',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_BOUNTY.png',
area=(669, 412, 765, 436),
search=(649, 392, 785, 456),
color=(165, 181, 208),
button=(669, 412, 765, 436),
),
)
WORK_GO_TO_COMMISSIONS = ButtonWrapper(
name='WORK_GO_TO_COMMISSIONS',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_COMMISSIONS.png',
area=(655, 494, 751, 518),
search=(635, 474, 771, 538),
color=(165, 179, 204),
button=(655, 494, 751, 518),
),
)
WORK_GO_TO_MISSION = ButtonWrapper(
name='WORK_GO_TO_MISSION',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_MISSION.png',
area=(720, 160, 803, 199),
search=(700, 140, 823, 219),
color=(165, 178, 204),
button=(720, 160, 803, 199),
),
)
WORK_GO_TO_SCHOOL_EXCHANGE = ButtonWrapper(
name='WORK_GO_TO_SCHOOL_EXCHANGE',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_SCHOOL_EXCHANGE.png',
area=(641, 575, 758, 599),
search=(621, 555, 778, 619),
color=(165, 179, 204),
button=(641, 575, 758, 599),
),
)
WORK_GO_TO_STORY = ButtonWrapper(
name='WORK_GO_TO_STORY',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_STORY.png',
area=(995, 163, 1032, 197),
search=(975, 143, 1052, 217),
color=(191, 201, 219),
button=(995, 163, 1032, 197),
),
)
WORK_GO_TO_TACTICAL_CHALLENGE = ButtonWrapper(
name='WORK_GO_TO_TACTICAL_CHALLENGE',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_TACTICAL_CHALLENGE.png',
area=(1012, 535, 1151, 562),
search=(992, 515, 1171, 582),
color=(159, 174, 200),
button=(1012, 535, 1151, 562),
),
)
+75
View File
@@ -0,0 +1,75 @@
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 ```
AFFECTION_LEVEL_UP = ButtonWrapper(
name='AFFECTION_LEVEL_UP',
jp=Button(
file='./assets/jp/base/popup/AFFECTION_LEVEL_UP.png',
area=(643, 599, 773, 641),
search=(623, 579, 793, 661),
color=(208, 223, 243),
button=(882, 244, 1176, 476),
),
)
DAILY_NEWS = ButtonWrapper(
name='DAILY_NEWS',
jp=Button(
file='./assets/jp/base/popup/DAILY_NEWS.png',
area=(120, 89, 326, 113),
search=(100, 69, 346, 133),
color=(150, 204, 253),
button=(1128, 89, 1156, 117),
),
)
DAILY_REWARD = ButtonWrapper(
name='DAILY_REWARD',
jp=Button(
file='./assets/jp/base/popup/DAILY_REWARD.png',
area=(854, 117, 1008, 165),
search=(834, 97, 1028, 185),
color=(178, 167, 112),
button=(920, 632, 1140, 712),
),
)
GET_NEW_STUDENT = ButtonWrapper(
name='GET_NEW_STUDENT',
jp=Button(
file='./assets/jp/base/popup/GET_NEW_STUDENT.png',
area=(32, 93, 158, 114),
search=(12, 73, 178, 134),
color=(125, 132, 92),
button=(934, 643, 1263, 714),
),
)
GET_REWARD = ButtonWrapper(
name='GET_REWARD',
jp=Button(
file='./assets/jp/base/popup/GET_REWARD.png',
area=(657, 145, 693, 170),
search=(637, 125, 713, 190),
color=(230, 222, 93),
button=(675, 623, 870, 695),
),
)
GET_REWARD_SKIP = ButtonWrapper(
name='GET_REWARD_SKIP',
jp=Button(
file='./assets/jp/base/popup/GET_REWARD_SKIP.png',
area=(1137, 34, 1243, 65),
search=(1117, 14, 1263, 85),
color=(197, 200, 205),
button=(1137, 34, 1243, 65),
),
)
NETWORK_RECONNECT = ButtonWrapper(
name='NETWORK_RECONNECT',
jp=Button(
file='./assets/jp/base/popup/NETWORK_RECONNECT.png',
area=(725, 488, 810, 516),
search=(705, 468, 830, 536),
color=(78, 138, 169),
button=(663, 467, 870, 537),
),
)
+5
View File
@@ -0,0 +1,5 @@
from tasks.base.popup import PopupHandler
class MainPage(PopupHandler):
pass
+162
View File
@@ -0,0 +1,162 @@
import traceback
from tasks.base.assets.assets_base_page import *
class Page:
# Key: str, page name like "page_main"
# Value: Page, page instance
all_pages = {}
@classmethod
def clear_connection(cls):
for page in cls.all_pages.values():
page.parent = None
@classmethod
def init_connection(cls, destination):
"""
Initialize an A* path finding among pages.
Args:
destination (Page):
"""
cls.clear_connection()
visited = [destination]
visited = set(visited)
while 1:
new = visited.copy()
for page in visited:
for link in cls.iter_pages():
if link in visited:
continue
if page in link.links:
link.parent = page
new.add(link)
if len(new) == len(visited):
break
visited = new
@classmethod
def iter_pages(cls):
return cls.all_pages.values()
@classmethod
def iter_check_buttons(cls):
for page in cls.all_pages.values():
yield page.check_button
def __init__(self, check_button):
self.check_button = check_button
self.links = {}
(filename, line_number, function_name, text) = traceback.extract_stack()[-2]
self.name = text[:text.find('=')].strip()
self.parent = None
Page.all_pages[self.name] = self
def __eq__(self, other):
return self.name == other.name
def __hash__(self):
return hash(self.name)
def __str__(self):
return self.name
def link(self, button, destination):
self.links[destination] = button
# Main Page
page_main = Page(MAIN_GO_TO_PURCHASE)
# Cafe
page_cafe = Page(CAFE_CHECK)
page_cafe.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_CAFE, destination=page_cafe)
# Schedule
page_schedule = Page(SCHEDULE_CHECK)
page_schedule.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_SCHEDULE, destination=page_schedule)
# Circle
page_circle = Page(CIRCLE_CHECK)
page_circle.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_CIRCLE, destination=page_circle)
# Crafting Chamber
page_crafting = Page(CRAFTING_CHECK)
page_crafting.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_CRAFTING, destination=page_crafting)
# Shop
page_shop = Page(SHOP_CHECK)
page_shop.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_SHOP, destination=page_shop)
# Gacha
page_gacha = Page(GACHA_CHECK)
page_gacha.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_GACHA, destination=page_gacha)
# Account Info
page_account_info = Page(ACCOUNT_INFO_CHECK)
page_account_info.link(HOME, destination=page_main)
# Mail
page_mail = Page(MAIL_CHECK)
page_mail.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_MAIL, destination=page_mail)
# Task (Daily)
page_task = Page(TASK_CHECK)
page_task.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_TASK, destination=page_task)
# MomoTalk
page_momo_talk = Page(MOMOTALK_CHECK)
page_momo_talk.link(MOMOTALK_GO_TO_MAIN, destination=page_main)
page_main.link(MAIN_GO_TO_MOMOTALK, destination=page_momo_talk)
# Work
page_work = Page(WORK_CHECK)
page_work.link(HOME, destination=page_main)
page_main.link(MAIN_GO_TO_WORK, destination=page_work)
# Mission
page_mission = Page(MISSION_CHECK)
page_mission.link(HOME, destination=page_main)
page_mission.link(BACK, destination=page_work)
page_work.link(WORK_GO_TO_MISSION, destination=page_mission)
# Story
page_story = Page(STORY_CHECK)
page_story.link(HOME, destination=page_main)
page_story.link(BACK, destination=page_work)
page_work.link(WORK_GO_TO_STORY, destination=page_story)
# Bounty
page_bounty = Page(BOUNTY_CHECK)
page_bounty.link(HOME, destination=page_main)
page_bounty.link(BACK, destination=page_work)
page_work.link(WORK_GO_TO_BOUNTY, destination=page_bounty)
# Commissions
page_commissions = Page(COMMISSIONS_CHECK)
page_commissions.link(HOME, destination=page_main)
page_commissions.link(BACK, destination=page_work)
page_work.link(WORK_GO_TO_COMMISSIONS, destination=page_commissions)
# School Exchange
page_school_exchange = Page(SCHOOL_EXCHANGE_CHECK)
page_school_exchange.link(HOME, destination=page_main)
page_school_exchange.link(BACK, destination=page_work)
page_work.link(WORK_GO_TO_SCHOOL_EXCHANGE, destination=page_school_exchange)
# Tactical Challenge
page_tactical_challenge = Page(TACTICAL_CHALLENGE_CHECK)
page_tactical_challenge.link(HOME, destination=page_main)
page_tactical_challenge.link(BACK, destination=page_work)
page_work.link(WORK_GO_TO_TACTICAL_CHALLENGE, destination=page_tactical_challenge)
+91
View File
@@ -0,0 +1,91 @@
from module.base.base import ModuleBase
from module.base.timer import Timer
from tasks.base.assets.assets_base_popup import *
from tasks.base.assets.assets_base_page import LOADING_CHECK
class PopupHandler(ModuleBase):
def handle_loading(self, interval=5) -> bool:
"""
Args:
interval:
Returns:
If handled.
"""
if self.appear(LOADING_CHECK, interval=interval):
timer = Timer(0.5).start()
while 1:
if timer.reached_and_reset():
self.device.screenshot()
if self.appear(LOADING_CHECK):
self.device.stuck_record_clear()
continue
else:
break
return True
return False
def handle_reward(self, interval=5) -> bool:
"""
Args:
interval:
Returns:
If handled.
"""
if self.appear_then_click(GET_REWARD, interval=interval):
timer = Timer(0.2).start()
while 1:
if timer.reached_and_reset():
self.device.screenshot()
if self.appear(GET_REWARD):
self.device.click(GET_REWARD)
else:
break
return True
return False
def handle_reward_skip(self, interval=5) -> bool:
if self.appear_then_click(GET_REWARD_SKIP, interval=interval):
return True
def handle_daily_news(self, interval=5) -> bool:
if self.appear_then_click(DAILY_NEWS, interval=interval):
return True
return False
def handle_daily_reward(self, interval=5) -> bool:
if self.appear_then_click(DAILY_REWARD, interval=interval):
return True
return False
def handle_network_reconnect(self, interval=5) -> bool:
if self.appear_then_click(NETWORK_RECONNECT, interval=interval):
return True
return False
def handle_affection_level_up(self, interval=5) -> bool:
if self.appear_then_click(AFFECTION_LEVEL_UP, interval=interval):
timer = Timer(0.2).start()
while 1:
if timer.reached_and_reset():
self.device.screenshot()
if self.appear(AFFECTION_LEVEL_UP):
self.device.click(AFFECTION_LEVEL_UP)
else:
break
return True
return False
def handle_new_student(self, interval=5) -> bool:
if self.appear_then_click(GET_NEW_STUDENT, interval=interval):
return True
return False
+393
View File
@@ -0,0 +1,393 @@
from module.base.button import ButtonWrapper
from module.base.decorator import run_once
from module.base.timer import Timer
from module.exception import GameNotRunningError, GamePageUnknownError
from module.logger import logger
from module.ocr.ocr import Ocr
from tasks.base.main_page import MainPage
from tasks.base.page import Page, page_main
from tasks.base.assets.assets_base_page import BACK
class UI(MainPage):
ui_current: Page
ui_main_confirm_timer = Timer(0.2, count=2)
def ui_page_appear(self, page):
"""
Args:
page (Page):
"""
return self.appear(page.check_button)
def ui_get_current_page(self, skip_first_screenshot=True):
"""
Args:
skip_first_screenshot:
Returns:
Page:
Raises:
GameNotRunningError:
GamePageUnknownError:
"""
logger.info("UI get current page")
@run_once
def app_check():
if not self.device.app_is_running():
raise GameNotRunningError("Game not running")
@run_once
def minicap_check():
if self.config.Emulator_ControlMethod == "uiautomator2":
self.device.uninstall_minicap()
@run_once
def rotation_check():
self.device.get_orientation()
timeout = Timer(10, count=20).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
if not hasattr(self.device, "image") or self.device.image is None:
self.device.screenshot()
else:
self.device.screenshot()
# End
if timeout.reached():
break
# Known pages
for page in Page.iter_pages():
if page.check_button is None:
continue
if self.ui_page_appear(page=page):
logger.attr("UI", page.name)
self.ui_current = page
return page
# Unknown page but able to handle
logger.info("Unknown ui page")
if self.ui_additional():
logger.info("Additional ui page handled")
timeout.reset()
continue
logger.info("May be in standby main page")
self.device.click(BACK)
app_check()
minicap_check()
rotation_check()
# Unknown page, need manual switching
logger.warning("Unknown ui page")
logger.attr("EMULATOR__SCREENSHOT_METHOD", self.config.Emulator_ScreenshotMethod)
logger.attr("EMULATOR__CONTROL_METHOD", self.config.Emulator_ControlMethod)
logger.attr("Lang", self.config.LANG)
logger.warning("Starting from current page is not supported")
logger.warning(f"Supported page: {[str(page) for page in Page.iter_pages()]}")
logger.warning('Supported page: Any page with a "HOME" button on the upper-right')
logger.critical("Please switch to a supported page before starting AAS")
raise GamePageUnknownError
def ui_goto(self, destination, skip_first_screenshot=True):
"""
Args:
destination (Page):
skip_first_screenshot:
"""
# Create connection
Page.init_connection(destination)
self.interval_clear(list(Page.iter_check_buttons()))
# loading_timer = Timer(0.5)
logger.hr(f"UI goto {destination}")
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# # Loading
# if self.appear(LOADING_CHECK):
# loading_timer.reset()
# continue
#
# if not loading_timer.reached():
# continue
# Destination page
if self.ui_page_appear(destination):
logger.info(f'Page arrive: {destination}')
if self.ui_page_confirm(destination):
logger.info(f'Page arrive confirm {destination}')
break
# Other pages
clicked = False
for page in Page.iter_pages():
if page.parent is None or page.check_button is None:
continue
if self.appear(page.check_button, interval=5):
logger.info(f'Page switch: {page} -> {page.parent}')
# self.handle_lang_check(page)
if self.ui_page_confirm(page):
logger.info(f'Page arrive confirm {page}')
button = page.links[page.parent]
self.device.click(button)
self.ui_button_interval_reset(button)
clicked = True
break
if clicked:
continue
# Additional
if self.ui_additional():
continue
# Reset connection
Page.clear_connection()
def ui_ensure(self, destination, acquire_lang_checked=True, skip_first_screenshot=True):
"""
Args:
destination (Page):
acquire_lang_checked:
skip_first_screenshot:
Returns:
bool: If UI switched.
"""
logger.hr("UI ensure")
self.ui_get_current_page(skip_first_screenshot=skip_first_screenshot)
# self.ui_leave_special()
# if acquire_lang_checked:
# if self.acquire_lang_checked():
# self.ui_get_current_page(skip_first_screenshot=skip_first_screenshot)
if self.ui_current == destination:
logger.info("Already at %s" % destination)
return False
else:
logger.info("Goto %s" % destination)
self.ui_goto(destination, skip_first_screenshot=True)
return True
def ui_ensure_index(
self,
index,
letter,
next_button,
prev_button,
skip_first_screenshot=False,
fast=True,
interval=(0.2, 0.3),
):
"""
Args:
index (int):
letter (Ocr, callable): OCR button.
next_button (Button):
prev_button (Button):
skip_first_screenshot (bool):
fast (bool): Default true. False when index is not continuous.
interval (tuple, int, float): Seconds between two click.
"""
logger.hr("UI ensure index")
retry = Timer(1, count=2)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if isinstance(letter, Ocr):
current = letter.ocr_single_line(self.device.image)
else:
current = letter(self.device.image)
logger.attr("Index", current)
diff = index - current
if diff == 0:
break
if current == 0:
logger.warning(f'ui_ensure_index got an empty current value: {current}')
continue
if retry.reached():
button = next_button if diff > 0 else prev_button
if fast:
self.device.multi_click(button, n=abs(diff), interval=interval)
else:
self.device.click(button)
retry.reset()
def ui_click(
self,
click_button,
check_button,
appear_button=None,
additional=None,
retry_wait=5,
skip_first_screenshot=True,
):
"""
Args:
click_button (ButtonWrapper):
check_button (ButtonWrapper, callable, list[ButtonWrapper], tuple[ButtonWrapper]):
appear_button (ButtonWrapper, callable, list[ButtonWrapper], tuple[ButtonWrapper]):
additional (callable):
retry_wait (int, float):
skip_first_screenshot (bool):
"""
if appear_button is None:
appear_button = click_button
logger.info(f'UI click: {appear_button} -> {check_button}')
def process_appear(button):
if isinstance(button, ButtonWrapper):
return self.appear(button)
elif callable(button):
return button()
elif isinstance(button, (list, tuple)):
for b in button:
if self.appear(b):
return True
return False
else:
return self.appear(button)
click_timer = Timer(retry_wait, count=retry_wait // 0.5)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if process_appear(check_button):
break
# Click
if click_timer.reached():
if process_appear(appear_button):
self.device.click(click_button)
click_timer.reset()
continue
if additional is not None:
if additional():
continue
def is_in_main(self):
if self.appear(page_main.check_button):
if self.image_color_count(page_main.check_button, color=(235, 235, 235), threshold=221, count=400):
return True
# if self.appear(MAP_EXIT):
# if self.image_color_count(MAP_EXIT, color=(235, 235, 235), threshold=221, count=50):
# return True
return False
def ui_goto_main(self):
return self.ui_ensure(destination=page_main)
# def ui_additional(self) -> bool:
# """
# Handle all possible popups during UI switching.
#
# Returns:
# If handled any popup.
# """
# if self.handle_reward():
# return True
# if self.handle_battle_pass_notification():
# return True
# if self.handle_monthly_card_reward():
# return True
# if self.appear(COMBAT_PREPARE, interval=5):
# logger.info(f'UI additional: {COMBAT_PREPARE} -> {CLOSE}')
# self.device.click(CLOSE)
# if self.appear_then_click(COMBAT_EXIT, interval=5):
# return True
# if self.appear_then_click(INFO_CLOSE, interval=5):
# return True
#
# return False
def ui_additional(self) -> bool:
"""
Handle all possible popups during UI switching.
Returns:
If handled any popup.
"""
if self.handle_loading():
return True
if self.handle_reward_skip():
return True
if self.handle_reward():
return True
if self.handle_daily_news():
return True
if self.handle_network_reconnect():
return True
if self.handle_affection_level_up():
return True
if self.handle_new_student():
return True
return False
def _ui_button_confirm(
self,
button,
confirm=Timer(0.1, count=0),
timeout=Timer(2, count=6),
skip_first_screenshot=True
):
confirm.reset()
timeout.reset()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if timeout.reached():
logger.warning(f'_ui_button_confirm({button}) timeout')
break
if self.appear(button):
if confirm.reached():
break
else:
confirm.reset()
def ui_page_confirm(self, page):
"""
Args:
page (Page):
Returns:
bool: If handled
"""
if page == page_main:
self._ui_button_confirm(page.check_button)
return True
return False
def ui_button_interval_reset(self, button):
"""
Reset interval of some button to avoid mistaken clicks
Args:
button (Button):
"""
pass