mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-12-12 07:29:03 +00:00
5f4a2933b5
then click directly if unknown timer reached
218 lines
6.5 KiB
Python
218 lines
6.5 KiB
Python
from module.base.base import ModuleBase
|
|
from module.base.timer import Timer
|
|
from module.exception import ScriptError
|
|
from module.logger import logger
|
|
|
|
|
|
class Switch:
|
|
"""
|
|
A wrapper to handle switches in game, switch among states with retries.
|
|
|
|
Examples:
|
|
# Definitions
|
|
submarine_hunt = Switch('Submarine_hunt', offset=120)
|
|
submarine_hunt.add_state('on', check_button=SUBMARINE_HUNT_ON)
|
|
submarine_hunt.add_state('off', check_button=SUBMARINE_HUNT_OFF)
|
|
|
|
# Change state to ON
|
|
submarine_view.set('on', main=self)
|
|
"""
|
|
|
|
def __init__(self, name='Switch', is_selector=False):
|
|
"""
|
|
Args:
|
|
name (str):
|
|
is_selector (bool): True if this is a multi choice, click to choose one of the switches.
|
|
For example: | [Daily] | Urgent | -> click -> | Daily | [Urgent] |
|
|
False if this is a switch, click the switch itself, and it changed in the same position.
|
|
For example: | [ON] | -> click -> | [OFF] |
|
|
"""
|
|
self.name = name
|
|
self.is_selector = is_selector
|
|
self.state_list = []
|
|
|
|
def add_state(self, state, check_button, click_button=None):
|
|
"""
|
|
Args:
|
|
state (str): State name but cannot use 'unknown' as state name
|
|
check_button (ButtonWrapper):
|
|
click_button (ButtonWrapper):
|
|
"""
|
|
if state == 'unknown':
|
|
raise ScriptError(f'Cannot use "unknown" as state name')
|
|
self.state_list.append({
|
|
'state': state,
|
|
'check_button': check_button,
|
|
'click_button': click_button if click_button is not None else check_button,
|
|
})
|
|
|
|
def appear(self, main):
|
|
"""
|
|
Args:
|
|
main (ModuleBase):
|
|
|
|
Returns:
|
|
bool
|
|
"""
|
|
for data in self.state_list:
|
|
if main.appear(data['check_button']):
|
|
return True
|
|
|
|
return False
|
|
|
|
def get(self, main):
|
|
"""
|
|
Args:
|
|
main (ModuleBase):
|
|
|
|
Returns:
|
|
str: state name or 'unknown'.
|
|
"""
|
|
for data in self.state_list:
|
|
if main.appear(data['check_button']):
|
|
return data['state']
|
|
|
|
return 'unknown'
|
|
|
|
def click(self, state, main):
|
|
"""
|
|
Args:
|
|
state (str):
|
|
main (ModuleBase):
|
|
"""
|
|
button = self.get_data(state)['click_button']
|
|
main.device.click(button)
|
|
|
|
def get_data(self, state):
|
|
"""
|
|
Args:
|
|
state (str):
|
|
|
|
Returns:
|
|
dict: Dictionary in add_state
|
|
|
|
Raises:
|
|
ScriptError: If state invalid
|
|
"""
|
|
for row in self.state_list:
|
|
if row['state'] == state:
|
|
return row
|
|
|
|
raise ScriptError(f'Switch {self.name} received an invalid state: {state}')
|
|
|
|
def handle_additional(self, main):
|
|
"""
|
|
Args:
|
|
main (ModuleBase):
|
|
|
|
Returns:
|
|
bool: If handled
|
|
"""
|
|
return False
|
|
|
|
def set(self, state, main, skip_first_screenshot=True):
|
|
"""
|
|
Args:
|
|
state:
|
|
main (ModuleBase):
|
|
skip_first_screenshot (bool):
|
|
|
|
Returns:
|
|
bool: If clicked
|
|
"""
|
|
logger.info(f'{self.name} set to {state}')
|
|
self.get_data(state)
|
|
|
|
changed = False
|
|
has_unknown = False
|
|
unknown_timer = Timer(5, count=10).start()
|
|
click_timer = Timer(1, count=3)
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
main.device.screenshot()
|
|
|
|
# Detect
|
|
current = self.get(main=main)
|
|
logger.attr(self.name, current)
|
|
|
|
# End
|
|
if current == state:
|
|
return changed
|
|
|
|
# Handle additional popups
|
|
if self.handle_additional(main=main):
|
|
continue
|
|
|
|
# Warning
|
|
if current == 'unknown':
|
|
if unknown_timer.reached():
|
|
logger.warning(f'Switch {self.name} has states evaluated to unknown, '
|
|
f'asset should be re-verified')
|
|
has_unknown = True
|
|
unknown_timer.reset()
|
|
# If unknown_timer never reached, don't click when having an unknown state,
|
|
# the unknown state is probably the switching animation.
|
|
# If unknown_timer reached once, click target state ignoring whether state is unknown or not,
|
|
# the unknown state is probably a new state not yet added.
|
|
# By ignoring new states, Switch.set() can still switch among known states.
|
|
if not has_unknown:
|
|
continue
|
|
else:
|
|
# Known state, reset timer
|
|
unknown_timer.reset()
|
|
|
|
# Click
|
|
if click_timer.reached():
|
|
if self.is_selector:
|
|
# Click target state to switch
|
|
click_state = state
|
|
else:
|
|
# If this is a selector, click on current state to switch to another
|
|
# But 'unknown' is not clickable, if it is, click target state instead
|
|
# assuming all selector states share the same position.
|
|
if current == 'unknown':
|
|
click_state = state
|
|
else:
|
|
click_state = current
|
|
self.click(click_state, main=main)
|
|
changed = True
|
|
click_timer.reset()
|
|
unknown_timer.reset()
|
|
|
|
return changed
|
|
|
|
def wait(self, main, skip_first_screenshot=True):
|
|
"""
|
|
Wait until any state activated
|
|
|
|
Args:
|
|
main (ModuleBase):
|
|
skip_first_screenshot:
|
|
|
|
Returns:
|
|
bool: If success
|
|
"""
|
|
timeout = Timer(2, count=6).start()
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
main.device.screenshot()
|
|
|
|
# Detect
|
|
current = self.get(main=main)
|
|
logger.attr(self.name, current)
|
|
|
|
# End
|
|
if current != 'unknown':
|
|
return True
|
|
if timeout.reached():
|
|
logger.warning(f'{self.name} wait activated timeout')
|
|
return False
|
|
|
|
# Handle additional popups
|
|
if self.handle_additional(main=main):
|
|
continue
|