Fix: Stop scheduler if a task failed 3 or more times

- Add: Clear click record
- Opt: Check the type of user setting and display invalid settings
This commit is contained in:
LmeSzinc 2021-11-03 20:46:34 +08:00
parent 1fa344c2d3
commit 3098aa31aa
5 changed files with 79 additions and 7 deletions

34
alas.py
View File

@ -9,7 +9,7 @@ from cached_property import cached_property
import module.config.server as server
from module.config.config import AzurLaneConfig, TaskEnd
from module.config.config_updater import ConfigUpdater
from module.config.utils import deep_get
from module.config.utils import deep_get, deep_set
from module.exception import *
from module.logger import logger
@ -26,6 +26,9 @@ class AzurLaneAutoScript:
# Set server before loading any buttons.
server.server = deep_get(config.data, keys='Alas.Emulator.Server', default='cn')
return config
except RequestHumanTakeover:
logger.critical('Request human takeover')
exit(1)
except Exception as e:
logger.exception(e)
exit(1)
@ -250,24 +253,41 @@ class AzurLaneAutoScript:
def loop(self):
logger.set_file_logger(self.config_name)
logger.info(f'Start scheduler loop: {self.config_name}')
is_first = True
failure_record = {}
while 1:
# Skip first restart
if is_first and self.config.task == 'Restart':
logger.info('Skip task `Restart` at scheduler start')
self.config.task_delay(server_update=True)
del self.__dict__['config']
logger.info(f'Scheduler: Start task `{self.config.task}`')
# Run
task = self.config.task
logger.info(f'Scheduler: Start task `{task}`')
self.device.stuck_record_clear()
self.device.click_record_clear()
self.device.screenshot()
logger.hr(self.config.task, level=0)
success = self.run(inflection.underscore(self.config.task))
logger.info(f'Scheduler: End task `{self.config.task}`')
logger.hr(task, level=0)
success = self.run(inflection.underscore(task))
logger.info(f'Scheduler: End task `{task}`')
del self.__dict__['config']
is_first = False
# Check failures
failed = deep_get(failure_record, keys=task, default=0)
failed = 0 if success else failed + 1
deep_set(failure_record, keys=task, value=failed)
if failed >= 3:
logger.critical(f"Task `{task}` failed 3 or more times.")
logger.critical("Possible reason: You haven't used it correctly. "
"Please read the help text of the options.")
logger.critical("Possible reason: There is a problem with this task. "
"Please contact developers or try to fix it yourself.")
logger.critical('Request human takeover')
exit(1)
if success:
continue
elif self.config.Error_HandleError:

View File

@ -81,6 +81,7 @@ class AzurLaneConfig(ConfigUpdater, ManualConfig, GeneratedConfig):
def load(self):
self.data = self.read_file(self.config_name)
ConfigTypeChecker.check(self.data)
for path, value in self.modified.items():
deep_set(self.data, keys=path, value=value)
@ -489,3 +490,32 @@ class MultiSetWrapper:
def __exit__(self, exc_type, exc_val, exc_tb):
self.main.update()
self.main.auto_update = True
class ConfigTypeChecker:
checkers = [
(['Scheduler', 'NextRun'], datetime),
(['Emotion', 'Fleet1Record'], datetime),
(['Emotion', 'Fleet2Record'], datetime),
(['Exercise', 'OpponentRefreshRecord'], datetime),
]
@classmethod
def check(cls, data):
"""
Args:
data (dict): User config.
Raises:
RequestHumanTakeover: If there's invalid setting.
"""
for func, func_data in data.items():
for path, typ in cls.checkers:
value = deep_get(func_data, keys=path, default=None)
if value is None:
continue
if not isinstance(value, typ):
logger.critical(f'Task `{func}` has an invalid setting {".".join(path)}="{str(value)}". '
f'Current type: {type_to_str(value)}, expected type: {type_to_str(typ)}')
logger.critical('Please check your settings')
raise RequestHumanTakeover

View File

@ -439,3 +439,19 @@ def to_list(text, length=1):
return [int(text)] * length
out = [int(letter.strip()) for letter in text.split(',')]
return out
def type_to_str(typ):
"""
Convert any types or any objects to a string
Remove <> to prevent them from being parsed as HTML tags.
Args:
typ:
Returns:
str: Such as `int`, 'datetime.datetime'.
"""
if not isinstance(typ, type):
typ = type(typ)
return str(typ).strip("<class '>").replace('<', '_').replace('>', '_')

View File

@ -45,14 +45,19 @@ class Control(MiniTouch):
if count[0][1] >= 12:
logger.warning(f'Too many click for a button: {count[0][0]}')
logger.warning(f'History click: {[str(prev) for prev in self.click_record]}')
self.click_record_clear()
raise GameTooManyClickError(f'Too many click for a button: {count[0][0]}')
if len(count) >= 2 and count[0][1] >= 6 and count[1][1] >= 6:
logger.warning(f'Too many click between 2 buttons: {count[0][0]}, {count[1][0]}')
logger.warning(f'History click: {[str(prev) for prev in self.click_record]}')
self.click_record_clear()
raise GameTooManyClickError(f'Too many click between 2 buttons: {count[0][0]}, {count[1][0]}')
return False
def click_record_clear(self):
self.click_record.clear()
def click(self, button, record_check=True):
"""Method to click a button.

View File

@ -84,6 +84,7 @@ class LoginHandler(Combat):
"""
for _ in range(3):
self.device.stuck_record_clear()
self.device.click_record_clear()
try:
self._handle_app_login()
return True