Add: UI switches and login
BIN
assets/share/base/page/BATTLE_PASS_CHECK.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
assets/share/base/page/CHARACTER_CHECK.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/share/base/page/CLOSE.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
assets/share/base/page/EVENT_CHECK.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/share/base/page/GACHA_CHECK.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/share/base/page/GUIDE_CHECK.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/share/base/page/GUIDE_CLOSE.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/share/base/page/ITEM_CHECK.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/share/base/page/MAIN_GOTO_BATTLE_PASS.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/share/base/page/MAIN_GOTO_CHARACTER.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/share/base/page/MAIN_GOTO_EVENT.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
assets/share/base/page/MAIN_GOTO_GACHA.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
assets/share/base/page/MAIN_GOTO_GUIDE.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/share/base/page/MAIN_GOTO_ITEM.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
assets/share/base/page/MAIN_GOTO_MENU.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
assets/share/base/page/MAIN_GOTO_MESSAGE.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/share/base/page/MAIN_GOTO_MISSION.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/share/base/page/MAIN_GOTO_TEAM.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/share/base/page/MAIN_GOTO_TUTORIAL.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
assets/share/base/page/MENU_CHECK.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
assets/share/base/page/MESSAGE_CLOSE.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/share/base/page/MISSION_CHECK.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
assets/share/base/page/TEAM_CHECK.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/share/base/page/TUTORIAL_CHECK.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
assets/share/base/popup/BATTLE_PASS_NOTIFICATION.BUTTON.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
assets/share/base/popup/BATTLE_PASS_NOTIFICATION.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
assets/share/base/popup/GET_REWARD.BUTTON.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
assets/share/base/popup/GET_REWARD.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/share/login/LOGIN_CONFIRM.BUTTON.png
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
assets/share/login/LOGIN_CONFIRM.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
@ -44,7 +44,7 @@ class ModuleBase:
|
|||||||
|
|
||||||
self.interval_timer = {}
|
self.interval_timer = {}
|
||||||
|
|
||||||
def match_template(self, button, interval=5, similarity=0.85):
|
def match_template(self, button, interval=0, similarity=0.85):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
button (ButtonWrapper):
|
button (ButtonWrapper):
|
||||||
@ -74,7 +74,7 @@ class ModuleBase:
|
|||||||
|
|
||||||
return appear
|
return appear
|
||||||
|
|
||||||
def match_color(self, button, interval=5, threshold=10):
|
def match_color(self, button, interval=0, threshold=10):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
button (ButtonWrapper):
|
button (ButtonWrapper):
|
||||||
@ -96,7 +96,7 @@ class ModuleBase:
|
|||||||
|
|
||||||
return appear
|
return appear
|
||||||
|
|
||||||
def match_template_color(self, button, interval=5, similarity=0.85, threshold=30):
|
def match_template_color(self, button, interval=0, similarity=0.85, threshold=30):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
button (ButtonWrapper):
|
button (ButtonWrapper):
|
||||||
|
245
tasks/base/assets/assets_base_page.py
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
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 ```
|
||||||
|
|
||||||
|
BATTLE_PASS_CHECK = ButtonWrapper(
|
||||||
|
name='BATTLE_PASS_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/BATTLE_PASS_CHECK.png',
|
||||||
|
area=(42, 22, 72, 55),
|
||||||
|
search=(22, 2, 92, 75),
|
||||||
|
color=(159, 142, 108),
|
||||||
|
button=(42, 22, 72, 55),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHARACTER_CHECK = ButtonWrapper(
|
||||||
|
name='CHARACTER_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/CHARACTER_CHECK.png',
|
||||||
|
area=(41, 18, 73, 47),
|
||||||
|
search=(21, 0, 93, 67),
|
||||||
|
color=(172, 153, 119),
|
||||||
|
button=(41, 18, 73, 47),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CLOSE = ButtonWrapper(
|
||||||
|
name='CLOSE',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/CLOSE.png',
|
||||||
|
area=(1222, 25, 1252, 55),
|
||||||
|
search=(1202, 5, 1272, 75),
|
||||||
|
color=(53, 54, 54),
|
||||||
|
button=(1222, 25, 1252, 55),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
EVENT_CHECK = ButtonWrapper(
|
||||||
|
name='EVENT_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/EVENT_CHECK.png',
|
||||||
|
area=(39, 19, 75, 56),
|
||||||
|
search=(19, 0, 95, 76),
|
||||||
|
color=(133, 125, 103),
|
||||||
|
button=(39, 19, 75, 56),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
GACHA_CHECK = ButtonWrapper(
|
||||||
|
name='GACHA_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/GACHA_CHECK.png',
|
||||||
|
area=(40, 20, 74, 54),
|
||||||
|
search=(20, 0, 94, 74),
|
||||||
|
color=(157, 139, 112),
|
||||||
|
button=(40, 20, 74, 54),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
GUIDE_CHECK = ButtonWrapper(
|
||||||
|
name='GUIDE_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/GUIDE_CHECK.png',
|
||||||
|
area=(44, 216, 63, 248),
|
||||||
|
search=(24, 196, 83, 268),
|
||||||
|
color=(196, 198, 200),
|
||||||
|
button=(44, 216, 63, 248),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
GUIDE_CLOSE = ButtonWrapper(
|
||||||
|
name='GUIDE_CLOSE',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/GUIDE_CLOSE.png',
|
||||||
|
area=(1153, 56, 1183, 87),
|
||||||
|
search=(1133, 36, 1203, 107),
|
||||||
|
color=(79, 79, 79),
|
||||||
|
button=(1153, 56, 1183, 87),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ITEM_CHECK = ButtonWrapper(
|
||||||
|
name='ITEM_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/ITEM_CHECK.png',
|
||||||
|
area=(43, 23, 72, 54),
|
||||||
|
search=(23, 3, 92, 74),
|
||||||
|
color=(188, 169, 129),
|
||||||
|
button=(43, 23, 72, 54),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_BATTLE_PASS = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_BATTLE_PASS',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_BATTLE_PASS.png',
|
||||||
|
area=(860, 36, 889, 56),
|
||||||
|
search=(840, 16, 909, 76),
|
||||||
|
color=(165, 164, 162),
|
||||||
|
button=(860, 36, 889, 56),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_CHARACTER = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_CHARACTER',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_CHARACTER.png',
|
||||||
|
area=(1204, 25, 1234, 51),
|
||||||
|
search=(1184, 5, 1254, 71),
|
||||||
|
color=(184, 185, 187),
|
||||||
|
button=(1204, 25, 1234, 51),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_EVENT = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_EVENT',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_EVENT.png',
|
||||||
|
area=(786, 33, 814, 56),
|
||||||
|
search=(766, 13, 834, 76),
|
||||||
|
color=(185, 184, 183),
|
||||||
|
button=(786, 33, 814, 56),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_GACHA = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_GACHA',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_GACHA.png',
|
||||||
|
area=(929, 38, 957, 59),
|
||||||
|
search=(909, 18, 977, 79),
|
||||||
|
color=(161, 162, 163),
|
||||||
|
button=(929, 38, 957, 59),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_GUIDE = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_GUIDE',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_GUIDE.png',
|
||||||
|
area=(997, 34, 1027, 59),
|
||||||
|
search=(977, 14, 1047, 79),
|
||||||
|
color=(170, 171, 173),
|
||||||
|
button=(997, 34, 1027, 59),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_ITEM = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_ITEM',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_ITEM.png',
|
||||||
|
area=(1064, 35, 1098, 59),
|
||||||
|
search=(1044, 15, 1118, 79),
|
||||||
|
color=(179, 180, 182),
|
||||||
|
button=(1064, 35, 1098, 59),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_MENU = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_MENU',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_MENU.png',
|
||||||
|
area=(22, 60, 51, 81),
|
||||||
|
search=(2, 40, 71, 101),
|
||||||
|
color=(176, 177, 179),
|
||||||
|
button=(22, 60, 51, 81),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_MESSAGE = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_MESSAGE',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_MESSAGE.png',
|
||||||
|
area=(184, 182, 203, 212),
|
||||||
|
search=(164, 162, 223, 232),
|
||||||
|
color=(230, 230, 230),
|
||||||
|
button=(184, 182, 203, 212),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_MISSION = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_MISSION',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_MISSION.png',
|
||||||
|
area=(21, 199, 51, 221),
|
||||||
|
search=(1, 179, 71, 241),
|
||||||
|
color=(168, 169, 172),
|
||||||
|
button=(21, 199, 51, 221),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_TEAM = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_TEAM',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_TEAM.png',
|
||||||
|
area=(1135, 41, 1166, 58),
|
||||||
|
search=(1115, 21, 1186, 78),
|
||||||
|
color=(160, 161, 164),
|
||||||
|
button=(1135, 41, 1166, 58),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MAIN_GOTO_TUTORIAL = ButtonWrapper(
|
||||||
|
name='MAIN_GOTO_TUTORIAL',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MAIN_GOTO_TUTORIAL.png',
|
||||||
|
area=(195, 58, 207, 82),
|
||||||
|
search=(175, 38, 227, 102),
|
||||||
|
color=(127, 131, 139),
|
||||||
|
button=(195, 58, 207, 82),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MENU_CHECK = ButtonWrapper(
|
||||||
|
name='MENU_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MENU_CHECK.png',
|
||||||
|
area=(1222, 638, 1252, 669),
|
||||||
|
search=(1202, 618, 1272, 689),
|
||||||
|
color=(57, 50, 39),
|
||||||
|
button=(1222, 638, 1252, 669),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MESSAGE_CLOSE = ButtonWrapper(
|
||||||
|
name='MESSAGE_CLOSE',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MESSAGE_CLOSE.png',
|
||||||
|
area=(863, 95, 895, 127),
|
||||||
|
search=(843, 75, 915, 147),
|
||||||
|
color=(175, 174, 175),
|
||||||
|
button=(863, 95, 895, 127),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MISSION_CHECK = ButtonWrapper(
|
||||||
|
name='MISSION_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/MISSION_CHECK.png',
|
||||||
|
area=(44, 33, 70, 55),
|
||||||
|
search=(24, 13, 90, 75),
|
||||||
|
color=(194, 177, 139),
|
||||||
|
button=(44, 33, 70, 55),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
TEAM_CHECK = ButtonWrapper(
|
||||||
|
name='TEAM_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/TEAM_CHECK.png',
|
||||||
|
area=(41, 34, 73, 54),
|
||||||
|
search=(21, 14, 93, 74),
|
||||||
|
color=(138, 123, 101),
|
||||||
|
button=(41, 34, 73, 54),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
TUTORIAL_CHECK = ButtonWrapper(
|
||||||
|
name='TUTORIAL_CHECK',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/page/TUTORIAL_CHECK.png',
|
||||||
|
area=(44, 30, 70, 56),
|
||||||
|
search=(24, 10, 90, 76),
|
||||||
|
color=(141, 126, 99),
|
||||||
|
button=(44, 30, 70, 56),
|
||||||
|
),
|
||||||
|
)
|
25
tasks/base/assets/assets_base_popup.py
Normal 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 ```
|
||||||
|
|
||||||
|
BATTLE_PASS_NOTIFICATION = ButtonWrapper(
|
||||||
|
name='BATTLE_PASS_NOTIFICATION',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/popup/BATTLE_PASS_NOTIFICATION.png',
|
||||||
|
area=(960, 601, 984, 625),
|
||||||
|
search=(940, 581, 1004, 645),
|
||||||
|
color=(137, 127, 109),
|
||||||
|
button=(895, 595, 1180, 630),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
GET_REWARD = ButtonWrapper(
|
||||||
|
name='GET_REWARD',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/base/popup/GET_REWARD.png',
|
||||||
|
area=(625, 118, 655, 147),
|
||||||
|
search=(605, 98, 675, 167),
|
||||||
|
color=(167, 151, 116),
|
||||||
|
button=(741, 495, 1071, 644),
|
||||||
|
),
|
||||||
|
)
|
122
tasks/base/page.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
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_GOTO_CHARACTER)
|
||||||
|
|
||||||
|
# Menu, entered from phone
|
||||||
|
page_menu = Page(MENU_CHECK)
|
||||||
|
page_menu.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_MENU, destination=page_menu)
|
||||||
|
|
||||||
|
# Team
|
||||||
|
page_team = Page(TEAM_CHECK)
|
||||||
|
page_team.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_TEAM, destination=page_team)
|
||||||
|
|
||||||
|
# Item, storage
|
||||||
|
page_item = Page(ITEM_CHECK)
|
||||||
|
page_item.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_ITEM, destination=page_item)
|
||||||
|
|
||||||
|
# Guide, which includes beginners' guide, daily missions and dungeons
|
||||||
|
page_guide = Page(GUIDE_CHECK)
|
||||||
|
page_guide.link(GUIDE_CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_GUIDE, destination=page_guide)
|
||||||
|
|
||||||
|
# Gacha
|
||||||
|
page_gacha = Page(GACHA_CHECK)
|
||||||
|
page_gacha.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_GACHA, destination=page_gacha)
|
||||||
|
|
||||||
|
# Battle Pass
|
||||||
|
page_battle_pass = Page(BATTLE_PASS_CHECK)
|
||||||
|
page_battle_pass.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_BATTLE_PASS, destination=page_battle_pass)
|
||||||
|
|
||||||
|
# Event
|
||||||
|
page_event = Page(EVENT_CHECK)
|
||||||
|
page_event.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_EVENT, destination=page_event)
|
||||||
|
|
||||||
|
# Tutorial
|
||||||
|
page_tutorial = Page(TUTORIAL_CHECK)
|
||||||
|
page_tutorial.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_TUTORIAL, destination=page_tutorial)
|
||||||
|
|
||||||
|
# Mission
|
||||||
|
page_mission = Page(MISSION_CHECK)
|
||||||
|
page_mission.link(CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_MISSION, destination=page_mission)
|
||||||
|
|
||||||
|
# Message
|
||||||
|
page_message = Page(MESSAGE_CLOSE)
|
||||||
|
page_message.link(MESSAGE_CLOSE, destination=page_main)
|
||||||
|
page_main.link(MAIN_GOTO_MESSAGE, destination=page_message)
|
32
tasks/base/popup.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from module.base.base import ModuleBase
|
||||||
|
from tasks.base.assets.assets_base_popup import *
|
||||||
|
|
||||||
|
|
||||||
|
class PopupHandler(ModuleBase):
|
||||||
|
def handle_reward(self, interval=5) -> bool:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
interval:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If handled.
|
||||||
|
"""
|
||||||
|
if self.appear_then_click(GET_REWARD, interval=interval):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_battle_pass_notification(self, interval=5) -> bool:
|
||||||
|
"""
|
||||||
|
Popup notification that you enter battle pass the first time.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
interval:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If handled.
|
||||||
|
"""
|
||||||
|
if self.appear_then_click(BATTLE_PASS_NOTIFICATION, interval=interval):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
175
tasks/base/ui.py
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
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 tasks.base.page import Page, page_main
|
||||||
|
from tasks.base.popup import PopupHandler
|
||||||
|
|
||||||
|
|
||||||
|
class UI(PopupHandler):
|
||||||
|
ui_current: Page
|
||||||
|
|
||||||
|
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():
|
||||||
|
timeout.reset()
|
||||||
|
continue
|
||||||
|
|
||||||
|
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("SERVER", self.config.SERVER)
|
||||||
|
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 SRC")
|
||||||
|
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()))
|
||||||
|
|
||||||
|
logger.hr(f"UI goto {destination}")
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
# Destination page
|
||||||
|
if self.ui_page_appear(destination):
|
||||||
|
logger.info(f'Page arrive: {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}')
|
||||||
|
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, skip_first_screenshot=True):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
destination (Page):
|
||||||
|
skip_first_screenshot:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If UI switched.
|
||||||
|
"""
|
||||||
|
logger.hr("UI ensure")
|
||||||
|
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_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
|
||||||
|
|
||||||
|
def ui_button_interval_reset(self, button):
|
||||||
|
"""
|
||||||
|
Reset interval of some button to avoid mistaken clicks
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Button):
|
||||||
|
"""
|
||||||
|
pass
|
15
tasks/login/assets/assets_login.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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 ```
|
||||||
|
|
||||||
|
LOGIN_CONFIRM = ButtonWrapper(
|
||||||
|
name='LOGIN_CONFIRM',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/login/LOGIN_CONFIRM.png',
|
||||||
|
area=(1188, 44, 1220, 74),
|
||||||
|
search=(1168, 24, 1240, 94),
|
||||||
|
color=(140, 124, 144),
|
||||||
|
button=(683, 327, 1143, 620),
|
||||||
|
),
|
||||||
|
)
|
65
tasks/login/login.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
from module.base.timer import Timer
|
||||||
|
from module.logger import logger
|
||||||
|
from tasks.base.page import page_main
|
||||||
|
from tasks.base.ui import UI
|
||||||
|
from tasks.login.assets.assets_login import LOGIN_CONFIRM
|
||||||
|
|
||||||
|
|
||||||
|
class Login(UI):
|
||||||
|
def _handle_app_login(self):
|
||||||
|
"""
|
||||||
|
Pages:
|
||||||
|
in: Any page
|
||||||
|
out: page_main
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GameStuckError:
|
||||||
|
GameTooManyClickError:
|
||||||
|
"""
|
||||||
|
logger.hr('App login')
|
||||||
|
|
||||||
|
orientation_timer = Timer(5)
|
||||||
|
login_success = False
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
# Watch device rotation
|
||||||
|
if not login_success and orientation_timer.reached():
|
||||||
|
# Screen may rotate after starting an app
|
||||||
|
self.device.get_orientation()
|
||||||
|
orientation_timer.reset()
|
||||||
|
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
# End
|
||||||
|
if self.ui_page_appear(page_main):
|
||||||
|
logger.info('Login to main confirm')
|
||||||
|
break
|
||||||
|
|
||||||
|
# Login
|
||||||
|
if self.appear_then_click(LOGIN_CONFIRM):
|
||||||
|
continue
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def handle_app_login(self):
|
||||||
|
self.device.screenshot_interval_set(1.0)
|
||||||
|
try:
|
||||||
|
self._handle_app_login()
|
||||||
|
finally:
|
||||||
|
self.device.screenshot_interval_set()
|
||||||
|
|
||||||
|
def app_stop(self):
|
||||||
|
logger.hr('App stop')
|
||||||
|
self.device.app_stop()
|
||||||
|
|
||||||
|
def app_start(self):
|
||||||
|
logger.hr('App start')
|
||||||
|
self.device.app_start()
|
||||||
|
self.handle_app_login()
|
||||||
|
|
||||||
|
def app_restart(self):
|
||||||
|
logger.hr('App restart')
|
||||||
|
self.device.app_stop()
|
||||||
|
self.device.app_start()
|
||||||
|
self.handle_app_login()
|
||||||
|
self.config.task_delay(server_update=True)
|