mirror of
https://github.com/LmeSzinc/AzurLaneAutoScript.git
synced 2025-01-08 12:07:36 +08:00
Refactor: More accurate exceptions and add friendly advices
This commit is contained in:
parent
5dd0459de9
commit
61cbe75527
111
alas.py
111
alas.py
@ -1,4 +1,7 @@
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import inflection
|
||||
from cached_property import cached_property
|
||||
@ -11,7 +14,8 @@ from module.config.db import Database
|
||||
from module.device.device import Device
|
||||
from module.exception import *
|
||||
from module.handler.login import LoginHandler
|
||||
from module.logger import logger
|
||||
from module.handler.sensitive_info import handle_sensitive_image, handle_sensitive_logs
|
||||
from module.logger import logger, log_file
|
||||
from module.research.research import RewardResearch
|
||||
from module.tactical.tactical_class import RewardTacticalClass
|
||||
from module.ui.ui import UI, page_main
|
||||
@ -33,50 +37,68 @@ class AzurLaneAutoScript:
|
||||
return device
|
||||
|
||||
def run(self, command):
|
||||
while 1:
|
||||
try:
|
||||
self.__getattribute__(command)()
|
||||
UI(config=self.config, device=self.device).ui_ensure(page_main)
|
||||
return True
|
||||
except TaskEnd:
|
||||
return True
|
||||
except GameNotRunningError as e:
|
||||
logger.warning(e)
|
||||
az = LoginHandler(self.config, device=self.device)
|
||||
az.app_restart()
|
||||
az.ensure_no_unfinished_campaign()
|
||||
continue
|
||||
except GameTooManyClickError as e:
|
||||
logger.warning(e)
|
||||
self.save_error_log()
|
||||
az = LoginHandler(self.config, device=self.device)
|
||||
az.handle_game_stuck()
|
||||
continue
|
||||
except GameStuckError as e:
|
||||
logger.warning(e)
|
||||
self.save_error_log()
|
||||
az = LoginHandler(self.config, device=self.device)
|
||||
az.handle_game_stuck()
|
||||
continue
|
||||
except LogisticsRefreshBugHandler as e:
|
||||
logger.warning(e)
|
||||
self.save_error_log()
|
||||
az = LoginHandler(self.config, device=self.device)
|
||||
az.device.app_stop()
|
||||
time.sleep(600)
|
||||
az.app_ensure_start()
|
||||
continue
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
self.save_error_log()
|
||||
return False
|
||||
try:
|
||||
self.__getattribute__(command)()
|
||||
UI(config=self.config, device=self.device).ui_ensure(page_main)
|
||||
return True
|
||||
except TaskEnd:
|
||||
return True
|
||||
except GameNotRunningError as e:
|
||||
logger.warning(e)
|
||||
self.config.task_call('Restart')
|
||||
return True
|
||||
except (GameStuckError, GameTooManyClickError) as e:
|
||||
logger.warning(e)
|
||||
self.save_error_log()
|
||||
logger.warning(f'Game stuck, {self.config.Emulator_PackageName} will be restarted in 10 seconds')
|
||||
logger.warning('If you are playing by hand, please stop Alas')
|
||||
self.config.task_call('Restart')
|
||||
self.device.sleep(10)
|
||||
return False
|
||||
except LogisticsRefreshBugHandler as e:
|
||||
logger.warning(e)
|
||||
self.save_error_log()
|
||||
self.config.task_call('Restart')
|
||||
self.device.sleep(10)
|
||||
return False
|
||||
except ScriptError as e:
|
||||
logger.critical(e)
|
||||
logger.critical('This is likely to be a mistake of developers, but sometimes just random issues')
|
||||
exit(1)
|
||||
except RequestHumanTakeover:
|
||||
logger.critical('Request human takeover')
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
self.save_error_log()
|
||||
return False
|
||||
|
||||
def save_error_log(self):
|
||||
"""
|
||||
Save last 60 screenshots in ./log/error/<timestamp>
|
||||
Save logs to ./log/error/<timestamp>/log.txt
|
||||
"""
|
||||
pass
|
||||
if self.config.Error_SaveError:
|
||||
folder = f'./log/error/{int(time.time() * 1000)}'
|
||||
logger.warning(f'Saving error: {folder}')
|
||||
os.mkdir(folder)
|
||||
for data in self.device.screenshot_deque:
|
||||
image_time = datetime.strftime(data['time'], '%Y-%m-%d_%H-%M-%S-%f')
|
||||
image = handle_sensitive_image(data['image'])
|
||||
image.save(f'{folder}/{image_time}.png')
|
||||
with open(log_file, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
start = 0
|
||||
for index, line in enumerate(lines):
|
||||
if re.search('\+-{15,}\+', line):
|
||||
start = index
|
||||
lines = lines[start - 2:]
|
||||
lines = handle_sensitive_logs(lines)
|
||||
with open(f'{folder}/log.txt', 'w', encoding='utf-8') as f:
|
||||
f.writelines(lines)
|
||||
|
||||
def restart(self):
|
||||
LoginHandler(self.config, device=self.device).app_restart()
|
||||
|
||||
def research(self):
|
||||
RewardResearch(config=self.config, device=self.device).run()
|
||||
@ -102,12 +124,19 @@ class AzurLaneAutoScript:
|
||||
def loop(self):
|
||||
while 1:
|
||||
logger.info(f'Scheduler: Start task `{self.config.task}`')
|
||||
logger.hr(self.config.task, level=0)
|
||||
success = self.run(inflection.underscore(self.config.task))
|
||||
|
||||
logger.info(f'Scheduler: End task `{self.config.task}`')
|
||||
del self.__dict__['config']
|
||||
|
||||
if not success:
|
||||
if success:
|
||||
del self.__dict__['config']
|
||||
continue
|
||||
elif self.config.Error_HandleError:
|
||||
# self.config.task_delay(success=False)
|
||||
del self.__dict__['config']
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
from module.base.button import Button
|
||||
from module.base.utils import area_offset, get_color, random_rectangle_vector
|
||||
from module.base.utils import random_rectangle_vector
|
||||
from module.campaign.campaign_base import CampaignBase as CampaignBase_
|
||||
from module.exception import RequestHumanTakeover
|
||||
from module.logger import logger
|
||||
from module.ui.assets import WAR_ARCHIVES_CHECK
|
||||
from module.ui.page import page_archives
|
||||
@ -90,10 +90,9 @@ class CampaignBase(CampaignBase_):
|
||||
skip_first_screenshot=True)
|
||||
self.handle_stage_icon_spawn()
|
||||
else:
|
||||
logger.warning(
|
||||
'Respective server may not yet support the chosen War Archives campaign, check back in the next '
|
||||
'app update')
|
||||
exit(1)
|
||||
logger.critical('Respective server may not yet support the chosen War Archives campaign, '
|
||||
'check back in the next app update')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
# Subsequent runs all set False
|
||||
if self.first_run:
|
||||
|
@ -44,6 +44,14 @@ General:
|
||||
OldRetireR: true
|
||||
OldRetireSR: false
|
||||
OldRetireSSR: false
|
||||
Restart:
|
||||
Scheduler:
|
||||
Enable: false
|
||||
NextRun: 2020-01-01 00:00:00
|
||||
Command: Restart
|
||||
SuccessInterval: 0
|
||||
FailureInterval: 0
|
||||
ServerUpdate: 00:00
|
||||
Main:
|
||||
Scheduler:
|
||||
Enable: main
|
||||
|
@ -5,6 +5,7 @@ import os
|
||||
from module.campaign.assets import *
|
||||
from module.campaign.campaign_base import CampaignBase
|
||||
from module.config.config import AzurLaneConfig
|
||||
from module.exception import RequestHumanTakeover
|
||||
from module.exception import ScriptEnd
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Digit
|
||||
@ -53,7 +54,11 @@ class CampaignRun(UI):
|
||||
else:
|
||||
files = [f[:-3] for f in os.listdir(folder) if f[-3:] == '.py']
|
||||
logger.warning(f'Existing files: {files}')
|
||||
exit(1)
|
||||
|
||||
logger.critical('Please update Alas')
|
||||
logger.critical('If file is still missing after update, '
|
||||
'contact developers, or make map files yourself using dev_tools/map_extractor.py')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
config = copy.copy(self.config).merge(self.module.Config())
|
||||
device = self.device
|
||||
|
@ -56,6 +56,16 @@ General:
|
||||
OldRetireR: true
|
||||
OldRetireSR: false
|
||||
OldRetireSSR: false
|
||||
Restart:
|
||||
_info:
|
||||
Menu: Alas
|
||||
Scheduler:
|
||||
Enable: false
|
||||
NextRun: 2020-01-01 00:00:00
|
||||
Command: Restart
|
||||
SuccessInterval: 0
|
||||
FailureInterval: 0
|
||||
ServerUpdate: 00:00
|
||||
Main:
|
||||
_info:
|
||||
Menu: Main
|
||||
|
@ -8,6 +8,7 @@ from module.base.utils import ensure_time
|
||||
from module.config.config_generated import GeneratedConfig
|
||||
from module.config.config_manual import ManualConfig
|
||||
from module.config.utils import *
|
||||
from module.exception import RequestHumanTakeover, ScriptError
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
@ -123,8 +124,9 @@ class AzurLaneConfig(ManualConfig, GeneratedConfig):
|
||||
time.sleep(waiting.next_run.timestamp() - datetime.now().timestamp() + 1)
|
||||
return self.get_next()
|
||||
else:
|
||||
logger.warning('No task waiting or pending')
|
||||
exit(1)
|
||||
logger.critical('No task waiting or pending')
|
||||
logger.critical('Please enable at least one task')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def save(self):
|
||||
if not self.modified:
|
||||
@ -187,7 +189,7 @@ class AzurLaneConfig(ManualConfig, GeneratedConfig):
|
||||
logger.info(f'Delay task `{self.task}` to {run} ({kv})')
|
||||
self.Scheduler_NextRun = run
|
||||
else:
|
||||
logger.warning('Missing argument in delay_next_run, should set at least one')
|
||||
raise ScriptError('Missing argument in delay_next_run, should set at least one')
|
||||
|
||||
def task_call(self, task):
|
||||
"""
|
||||
@ -203,9 +205,12 @@ class AzurLaneConfig(ManualConfig, GeneratedConfig):
|
||||
"""
|
||||
path = f'{task}.Scheduler.NextRun'
|
||||
if deep_get(self.data, keys=path, default=None) is None:
|
||||
logger.warning(f'Task to call: `{task}` does not exist in user config')
|
||||
raise ScriptError(f'Task to call: `{task}` does not exist in user config')
|
||||
else:
|
||||
self.modified[path] = datetime.now().replace(microsecond=0)
|
||||
if task == 'Restart':
|
||||
# Restart is forced to enable
|
||||
self.modified[f'{task}.Scheduler.Enable'] = True
|
||||
self.update()
|
||||
|
||||
def task_stop(self, message=''):
|
||||
|
@ -44,6 +44,8 @@ class GeneratedConfig:
|
||||
Retirement_OldRetireSR = False
|
||||
Retirement_OldRetireSSR = False
|
||||
|
||||
# Func `Restart`
|
||||
|
||||
# Func `Main`
|
||||
Campaign_Name = '7-2'
|
||||
Campaign_Event = 'campaign_main'
|
||||
|
@ -489,6 +489,96 @@ type: input
|
||||
value: false
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: _info
|
||||
arg: _info
|
||||
lang: en-US
|
||||
name: Restart._info._info.name
|
||||
help: Restart._info._info.help
|
||||
type: ''
|
||||
value: ''
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: _info
|
||||
arg: Menu
|
||||
lang: en-US
|
||||
name: Restart._info.Menu.name
|
||||
help: Restart._info.Menu.help
|
||||
type: input
|
||||
value: Alas
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: _info
|
||||
lang: en-US
|
||||
name: Restart.Scheduler._info.name
|
||||
help: Restart.Scheduler._info.help
|
||||
type: ''
|
||||
value: ''
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: Enable
|
||||
lang: en-US
|
||||
name: Restart.Scheduler.Enable.name
|
||||
help: Restart.Scheduler.Enable.help
|
||||
type: input
|
||||
value: false
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: NextRun
|
||||
lang: en-US
|
||||
name: Restart.Scheduler.NextRun.name
|
||||
help: Restart.Scheduler.NextRun.help
|
||||
type: input
|
||||
value: 2020-01-01 00:00:00
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: Command
|
||||
lang: en-US
|
||||
name: Restart.Scheduler.Command.name
|
||||
help: Restart.Scheduler.Command.help
|
||||
type: input
|
||||
value: Restart
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: SuccessInterval
|
||||
lang: en-US
|
||||
name: Restart.Scheduler.SuccessInterval.name
|
||||
help: Restart.Scheduler.SuccessInterval.help
|
||||
type: input
|
||||
value: 0
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: FailureInterval
|
||||
lang: en-US
|
||||
name: Restart.Scheduler.FailureInterval.name
|
||||
help: Restart.Scheduler.FailureInterval.help
|
||||
type: input
|
||||
value: 0
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: ServerUpdate
|
||||
lang: en-US
|
||||
name: Restart.Scheduler.ServerUpdate.name
|
||||
help: Restart.Scheduler.ServerUpdate.help
|
||||
type: input
|
||||
value: 00:00
|
||||
option: {}
|
||||
---
|
||||
func: Main
|
||||
group: _info
|
||||
arg: _info
|
||||
@ -1611,7 +1701,7 @@ lang: en-US
|
||||
name: GemsFarming.Fleet.FleetOrder.name
|
||||
help: GemsFarming.Fleet.FleetOrder.help
|
||||
type: input
|
||||
value: fleet1_mob_fleet2_boss
|
||||
value: fleet1_all_fleet2_standby
|
||||
option:
|
||||
fleet1_mob_fleet2_boss: fleet1_mob_fleet2_boss
|
||||
fleet1_all_fleet2_standby: fleet1_all_fleet2_standby
|
||||
@ -1623,7 +1713,7 @@ lang: en-US
|
||||
name: GemsFarming.Fleet.AutoSearchFleetOrder.name
|
||||
help: GemsFarming.Fleet.AutoSearchFleetOrder.help
|
||||
type: input
|
||||
value: fleet1_mob_fleet2_boss
|
||||
value: fleet1_all_fleet2_standby
|
||||
option:
|
||||
fleet1_mob_fleet2_boss: fleet1_mob_fleet2_boss
|
||||
fleet1_boss_fleet2_mob: fleet1_boss_fleet2_mob
|
||||
|
@ -489,6 +489,96 @@ type: input
|
||||
value: false
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: _info
|
||||
arg: _info
|
||||
lang: zh-CN
|
||||
name: Restart._info._info.name
|
||||
help: Restart._info._info.help
|
||||
type: ''
|
||||
value: ''
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: _info
|
||||
arg: Menu
|
||||
lang: zh-CN
|
||||
name: Restart._info.Menu.name
|
||||
help: Restart._info.Menu.help
|
||||
type: input
|
||||
value: Alas
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: _info
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler._info.name
|
||||
help: Restart.Scheduler._info.help
|
||||
type: ''
|
||||
value: ''
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: Enable
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler.Enable.name
|
||||
help: Restart.Scheduler.Enable.help
|
||||
type: input
|
||||
value: false
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: NextRun
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler.NextRun.name
|
||||
help: Restart.Scheduler.NextRun.help
|
||||
type: input
|
||||
value: 2020-01-01 00:00:00
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: Command
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler.Command.name
|
||||
help: Restart.Scheduler.Command.help
|
||||
type: input
|
||||
value: Restart
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: SuccessInterval
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler.SuccessInterval.name
|
||||
help: Restart.Scheduler.SuccessInterval.help
|
||||
type: input
|
||||
value: 0
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: FailureInterval
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler.FailureInterval.name
|
||||
help: Restart.Scheduler.FailureInterval.help
|
||||
type: input
|
||||
value: 0
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: ServerUpdate
|
||||
lang: zh-CN
|
||||
name: Restart.Scheduler.ServerUpdate.name
|
||||
help: Restart.Scheduler.ServerUpdate.help
|
||||
type: input
|
||||
value: 00:00
|
||||
option: {}
|
||||
---
|
||||
func: Main
|
||||
group: _info
|
||||
arg: _info
|
||||
@ -1611,7 +1701,7 @@ lang: zh-CN
|
||||
name: GemsFarming.Fleet.FleetOrder.name
|
||||
help: GemsFarming.Fleet.FleetOrder.help
|
||||
type: input
|
||||
value: fleet1_mob_fleet2_boss
|
||||
value: fleet1_all_fleet2_standby
|
||||
option:
|
||||
fleet1_mob_fleet2_boss: fleet1_mob_fleet2_boss
|
||||
fleet1_all_fleet2_standby: fleet1_all_fleet2_standby
|
||||
@ -1623,7 +1713,7 @@ lang: zh-CN
|
||||
name: GemsFarming.Fleet.AutoSearchFleetOrder.name
|
||||
help: GemsFarming.Fleet.AutoSearchFleetOrder.help
|
||||
type: input
|
||||
value: fleet1_mob_fleet2_boss
|
||||
value: fleet1_all_fleet2_standby
|
||||
option:
|
||||
fleet1_mob_fleet2_boss: fleet1_mob_fleet2_boss
|
||||
fleet1_boss_fleet2_mob: fleet1_boss_fleet2_mob
|
||||
|
@ -489,6 +489,96 @@ type: input
|
||||
value: false
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: _info
|
||||
arg: _info
|
||||
lang: zh-TW
|
||||
name: Restart._info._info.name
|
||||
help: Restart._info._info.help
|
||||
type: ''
|
||||
value: ''
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: _info
|
||||
arg: Menu
|
||||
lang: zh-TW
|
||||
name: Restart._info.Menu.name
|
||||
help: Restart._info.Menu.help
|
||||
type: input
|
||||
value: Alas
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: _info
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler._info.name
|
||||
help: Restart.Scheduler._info.help
|
||||
type: ''
|
||||
value: ''
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: Enable
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler.Enable.name
|
||||
help: Restart.Scheduler.Enable.help
|
||||
type: input
|
||||
value: false
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: NextRun
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler.NextRun.name
|
||||
help: Restart.Scheduler.NextRun.help
|
||||
type: input
|
||||
value: 2020-01-01 00:00:00
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: Command
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler.Command.name
|
||||
help: Restart.Scheduler.Command.help
|
||||
type: input
|
||||
value: Restart
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: SuccessInterval
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler.SuccessInterval.name
|
||||
help: Restart.Scheduler.SuccessInterval.help
|
||||
type: input
|
||||
value: 0
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: FailureInterval
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler.FailureInterval.name
|
||||
help: Restart.Scheduler.FailureInterval.help
|
||||
type: input
|
||||
value: 0
|
||||
option: {}
|
||||
---
|
||||
func: Restart
|
||||
group: Scheduler
|
||||
arg: ServerUpdate
|
||||
lang: zh-TW
|
||||
name: Restart.Scheduler.ServerUpdate.name
|
||||
help: Restart.Scheduler.ServerUpdate.help
|
||||
type: input
|
||||
value: 00:00
|
||||
option: {}
|
||||
---
|
||||
func: Main
|
||||
group: _info
|
||||
arg: _info
|
||||
@ -1611,7 +1701,7 @@ lang: zh-TW
|
||||
name: GemsFarming.Fleet.FleetOrder.name
|
||||
help: GemsFarming.Fleet.FleetOrder.help
|
||||
type: input
|
||||
value: fleet1_mob_fleet2_boss
|
||||
value: fleet1_all_fleet2_standby
|
||||
option:
|
||||
fleet1_mob_fleet2_boss: fleet1_mob_fleet2_boss
|
||||
fleet1_all_fleet2_standby: fleet1_all_fleet2_standby
|
||||
@ -1623,7 +1713,7 @@ lang: zh-TW
|
||||
name: GemsFarming.Fleet.AutoSearchFleetOrder.name
|
||||
help: GemsFarming.Fleet.AutoSearchFleetOrder.help
|
||||
type: input
|
||||
value: fleet1_mob_fleet2_boss
|
||||
value: fleet1_all_fleet2_standby
|
||||
option:
|
||||
fleet1_mob_fleet2_boss: fleet1_mob_fleet2_boss
|
||||
fleet1_boss_fleet2_mob: fleet1_boss_fleet2_mob
|
||||
|
@ -1,5 +1,7 @@
|
||||
from module.device.connection import Connection
|
||||
from module.logger import logger
|
||||
from uiautomator2.exceptions import BaseError
|
||||
from module.exception import RequestHumanTakeover
|
||||
|
||||
|
||||
class AppControl(Connection):
|
||||
@ -12,8 +14,16 @@ class AppControl(Connection):
|
||||
|
||||
def app_stop(self):
|
||||
logger.info(f'App stop: {self.config.Emulator_PackageName}')
|
||||
self.device.app_stop(self.config.Emulator_PackageName)
|
||||
try:
|
||||
self.device.app_stop(self.config.Emulator_PackageName)
|
||||
except BaseError as e:
|
||||
logger.critical(e)
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def app_start(self):
|
||||
logger.info(f'App start: {self.config.Emulator_PackageName}')
|
||||
self.device.app_start(self.config.Emulator_PackageName)
|
||||
try:
|
||||
self.device.app_start(self.config.Emulator_PackageName)
|
||||
except BaseError as e:
|
||||
logger.critical(e)
|
||||
raise RequestHumanTakeover
|
||||
|
@ -6,6 +6,7 @@ import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
from module.device.connection import Connection
|
||||
from module.exception import RequestHumanTakeover
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
@ -25,9 +26,9 @@ class AScreenCap(Connection):
|
||||
|
||||
filepath = os.path.join(self.config.ASCREENCAP_FILEPATH_LOCAL, arc, 'ascreencap')
|
||||
if int(sdk) not in range(21, 26) or not os.path.exists(filepath):
|
||||
logger.warning('No suitable version of aScreenCap lib is available')
|
||||
logger.info('Please use ADB or uiautomator2 screenshot instead')
|
||||
exit(1)
|
||||
logger.critical('No suitable version of aScreenCap lib available for this device')
|
||||
logger.critical('Please use ADB or uiautomator2 for screenshots instead')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
logger.info(f'pushing {filepath}')
|
||||
self.adb_push([filepath, self.config.ASCREENCAP_FILEPATH_REMOTE])
|
||||
|
@ -44,11 +44,11 @@ class Control(MiniTouch):
|
||||
count = sorted(count.items(), key=lambda item: item[1])
|
||||
if count[0][1] >= 12:
|
||||
logger.warning(f'Too many click for a button: {count[0][0]}')
|
||||
logger.info(f'History click: {[str(prev) for prev in self.click_record]}')
|
||||
logger.warning(f'History click: {[str(prev) for prev in self.click_record]}')
|
||||
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.info(f'History click: {[str(prev) for prev in self.click_record]}')
|
||||
logger.warning(f'History click: {[str(prev) for prev in self.click_record]}')
|
||||
raise GameTooManyClickError(f'Too many click between 2 buttons: {count[0][0]}, {count[1][0]}')
|
||||
|
||||
return False
|
||||
|
@ -1,15 +1,14 @@
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import get_color
|
||||
from module.config.utils import get_server_next_update
|
||||
from module.device.app import AppControl
|
||||
from module.device.control import Control
|
||||
from module.device.screenshot import Screenshot
|
||||
from module.exception import GameStuckError
|
||||
from module.exception import GameStuckError, RequestHumanTakeover
|
||||
from module.handler.assets import GET_MISSION
|
||||
from module.logger import logger
|
||||
from module.config.utils import get_server_next_update
|
||||
import sys
|
||||
|
||||
|
||||
class Device(Screenshot, Control, AppControl):
|
||||
@ -17,17 +16,18 @@ class Device(Screenshot, Control, AppControl):
|
||||
stuck_record = set()
|
||||
stuck_timer = Timer(60, count=60).start()
|
||||
stuck_timer_long = Timer(300, count=300).start()
|
||||
stuck_long_wait_list = ['BATTLE_STATUS_S', 'PAUSE']
|
||||
stuck_long_wait_list = ['BATTLE_STATUS_S', 'PAUSE', 'LOGIN_CHECK']
|
||||
|
||||
def send_notification(self, title, message):
|
||||
if self.config.ENABLE_NOTIFICATIONS and sys.platform == 'win32':
|
||||
from notifypy import Notify
|
||||
notification = Notify()
|
||||
notification.title = title
|
||||
notification.message = message
|
||||
notification.application_name = "AzurLaneAutoScript"
|
||||
notification.icon = "assets/gooey/icon.ico"
|
||||
notification.send(block=False)
|
||||
# if self.config.ENABLE_NOTIFICATIONS and sys.platform == 'win32':
|
||||
# from notifypy import Notify
|
||||
# notification = Notify()
|
||||
# notification.title = title
|
||||
# notification.message = message
|
||||
# notification.application_name = "AzurLaneAutoScript"
|
||||
# notification.icon = "assets/gooey/icon.ico"
|
||||
# notification.send(block=False)
|
||||
pass
|
||||
|
||||
def handle_night_commission(self, daily_trigger='21:00', threshold=30):
|
||||
"""
|
||||
@ -79,21 +79,20 @@ class Device(Screenshot, Control, AppControl):
|
||||
# Check screen size
|
||||
width, height = self.image.size
|
||||
logger.attr('Screen_size', f'{width}x{height}')
|
||||
if width == 1280 and height == 720:
|
||||
return True
|
||||
else:
|
||||
logger.warning(f'Not supported screen size: {width}x{height}')
|
||||
logger.warning('Alas requires 1280x720')
|
||||
logger.hr('Script end')
|
||||
exit(1)
|
||||
if not (width == 1280 and height == 720):
|
||||
logger.critical(f'Resolution not supported: {width}x{height}')
|
||||
logger.critical('Please set emulator resolution to 1280x720')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
# Check screen color
|
||||
# May get a pure black screenshot on some emulators.
|
||||
color = get_color(self.image, area=(0, 0, 1280, 720))
|
||||
if sum(color) < 1:
|
||||
logger.warning('Received a pure black screenshot')
|
||||
logger.warning(f'Color: {color}')
|
||||
exit(1)
|
||||
logger.critical(f'Received pure black screenshots from emulator, color: {color}')
|
||||
logger.critical(f'Screenshot method `{self.config.Emulator_ScreenshotMethod}` '
|
||||
f'may not work on emulator `{self.serial}`')
|
||||
logger.critical('Please use other screenshot methods')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def stuck_record_add(self, button):
|
||||
self.stuck_record.add(str(button))
|
||||
@ -118,8 +117,7 @@ class Device(Screenshot, Control, AppControl):
|
||||
logger.warning(f'Waiting for {self.stuck_record}')
|
||||
self.stuck_record_clear()
|
||||
|
||||
if self.config.ENABLE_GAME_STUCK_HANDLER:
|
||||
raise GameStuckError(f'Wait too long')
|
||||
raise GameStuckError(f'Wait too long')
|
||||
|
||||
def disable_stuck_detection(self):
|
||||
"""
|
||||
|
@ -19,6 +19,7 @@ class CampaignNameError(Exception):
|
||||
|
||||
|
||||
class ScriptError(Exception):
|
||||
# This is likely to be a mistake of developers, but sometimes a random issue
|
||||
pass
|
||||
|
||||
|
||||
@ -29,12 +30,20 @@ class ScriptEnd(Exception):
|
||||
class GameStuckError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LogisticsRefreshBugHandler(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class GameTooManyClickError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class GameNotRunningError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class RequestHumanTakeover(Exception):
|
||||
# Request human takeover
|
||||
# Alas is unable to handle such error, probably because of wrong settings.
|
||||
pass
|
||||
|
@ -340,6 +340,7 @@ class GuildLogistics(GuildBase):
|
||||
# To fix this, you have to enter guild logistics once, then restart.
|
||||
# If exchange for 5 times, this bug is considered to be triggered.
|
||||
logger.warning('Triggered guild logistics refresh bug')
|
||||
logger.warning('This is a bug in Azur Lane, Alas will close game and wait 600 seconds')
|
||||
raise LogisticsRefreshBugHandler('Triggered guild logistics refresh bug')
|
||||
|
||||
else:
|
||||
|
@ -3,7 +3,7 @@ from datetime import datetime
|
||||
import module.config.server as server
|
||||
from module.base.timer import Timer
|
||||
from module.combat.combat import Combat
|
||||
from module.exception import GameTooManyClickError, ScriptError
|
||||
from module.exception import GameTooManyClickError, GameStuckError, RequestHumanTakeover
|
||||
from module.handler.assets import *
|
||||
from module.logger import logger
|
||||
from module.map.assets import *
|
||||
@ -79,36 +79,30 @@ class LoginHandler(Combat):
|
||||
bool: If login success
|
||||
|
||||
Raises:
|
||||
ScriptError: If login failed more than 3
|
||||
RequestHumanTakeover: If login failed more than 3
|
||||
"""
|
||||
for _ in range(3):
|
||||
self.device.stuck_record_clear()
|
||||
try:
|
||||
self._handle_app_login()
|
||||
return True
|
||||
except GameTooManyClickError as e:
|
||||
except (GameTooManyClickError, GameStuckError) as e:
|
||||
logger.warning(e)
|
||||
self.device.app_stop()
|
||||
self.device.app_start()
|
||||
continue
|
||||
|
||||
logger.warning('Login failed more than 3')
|
||||
self.device.send_notification('ScriptError', 'Login failed more than 3')
|
||||
raise ScriptError('Login failed more than 3')
|
||||
logger.critical('Login failed more than 3')
|
||||
logger.critical('Azur Lane server may be under maintenance, or you may lost network connection')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def app_restart(self):
|
||||
logger.hr('App restart')
|
||||
self.device.app_stop()
|
||||
self.device.app_start()
|
||||
self.handle_app_login()
|
||||
|
||||
def app_ensure_start(self):
|
||||
if not self.device.app_is_running():
|
||||
self.device.app_start()
|
||||
self.handle_app_login()
|
||||
return True
|
||||
|
||||
return False
|
||||
self.ensure_no_unfinished_campaign()
|
||||
self.config.Scheduler_Enable = False
|
||||
|
||||
def ensure_no_unfinished_campaign(self, confirm_wait=3):
|
||||
"""
|
||||
@ -132,15 +126,6 @@ class LoginHandler(Combat):
|
||||
confirm_wait=confirm_wait, skip_first_screenshot=True)
|
||||
self.ui_goto_main()
|
||||
|
||||
def handle_game_stuck(self):
|
||||
logger.warning(f'{self.config.PACKAGE_NAME} will be restart in 10 seconds')
|
||||
logger.warning('If you are playing by hand, please stop Alas')
|
||||
self.device.send_notification('Game stucked', 'will be restart in 10 seconds')
|
||||
self.device.sleep(10)
|
||||
|
||||
self.app_restart()
|
||||
self.ensure_no_unfinished_campaign()
|
||||
|
||||
def handle_user_agreement(self):
|
||||
"""
|
||||
For CN only.
|
||||
|
@ -1,5 +1,6 @@
|
||||
from module.base.utils import *
|
||||
from module.config.config import AzurLaneConfig
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
from module.map_detection.utils import *
|
||||
from module.map_detection.utils_assets import *
|
||||
@ -163,7 +164,9 @@ class GridPredictor:
|
||||
for name, template in self.template_enemy_genre.items():
|
||||
if template is None:
|
||||
logger.warning(f'Enemy detection template not found: {name}')
|
||||
exit(1)
|
||||
logger.warning('Please create it with dev_tools/relative_record.py or dev_tools/relative_crop.py, '
|
||||
'then place it under ./assets/<server>/template')
|
||||
raise ScriptError(f'Enemy detection template not found: {name}')
|
||||
|
||||
short_name = name[6:] if name.startswith('Siren_') else name
|
||||
scaling = scaling_dic.get(short_name, 1)
|
||||
|
@ -8,6 +8,7 @@ from cnocr.cn_ocr import data_dir, read_charset, check_model_name, load_module,
|
||||
from cnocr.fit.ctc_metrics import CtcMetrics
|
||||
from cnocr.hyperparams.cn_hyperparams import CnHyperparams as Hyperparams
|
||||
|
||||
from module.exception import RequestHumanTakeover
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
@ -115,7 +116,9 @@ class AlOcr(CnOcr):
|
||||
# Disable auto downloading cnocr models when model not found.
|
||||
# get_model_file(model_dir)
|
||||
logger.warning(f'Ocr model not prepared: {model_dir}')
|
||||
exit(1)
|
||||
logger.warning(f'Required files: {model_files}')
|
||||
logger.critical('Please check if required files of pre-trained OCR model exist')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def _get_module(self, context):
|
||||
network, self._hp = gen_network(self._model_name, self._hp, self._net_prefix)
|
||||
|
@ -3,6 +3,7 @@ import numpy as np
|
||||
from module.campaign.run import OCR_OIL
|
||||
from module.combat.assets import *
|
||||
from module.combat.combat import Combat
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
from module.map.map_operation import MapOperation
|
||||
from module.ocr.ocr import DigitCounter
|
||||
@ -34,8 +35,7 @@ def raid_name_shorten(name):
|
||||
elif name == 'raid_20210708':
|
||||
return 'SURUGA'
|
||||
else:
|
||||
logger.warning(f'Unknown raid name: {name}')
|
||||
exit(1)
|
||||
raise ScriptError(f'Unknown raid name: {name}')
|
||||
|
||||
|
||||
def raid_entrance(raid, mode):
|
||||
@ -51,8 +51,7 @@ def raid_entrance(raid, mode):
|
||||
try:
|
||||
return globals()[key]
|
||||
except KeyError:
|
||||
logger.warning(f'Raid entrance asset not exists: {key}')
|
||||
exit(1)
|
||||
raise ScriptError(f'Raid entrance asset not exists: {key}')
|
||||
|
||||
|
||||
def raid_ocr(raid, mode):
|
||||
@ -73,8 +72,7 @@ def raid_ocr(raid, mode):
|
||||
elif raid == 'SURUGA':
|
||||
return RaidCounter(button, letter=(49, 48, 49), threshold=128)
|
||||
except KeyError:
|
||||
logger.warning(f'Raid entrance asset not exists: {key}')
|
||||
exit(1)
|
||||
raise ScriptError(f'Raid entrance asset not exists: {key}')
|
||||
|
||||
|
||||
class Raid(MapOperation, Combat):
|
||||
|
@ -2,6 +2,7 @@ from module.base.button import ButtonGrid
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import get_color, color_similar
|
||||
from module.combat.assets import GET_ITEMS_1
|
||||
from module.exception import RequestHumanTakeover, ScriptError
|
||||
from module.logger import logger
|
||||
from module.retire.assets import *
|
||||
from module.retire.enhancement import Enhancement
|
||||
@ -294,21 +295,19 @@ class Retirement(Enhancement):
|
||||
self.dock_favourite_set(enable=False)
|
||||
total = self.retire_ships_one_click()
|
||||
if not total:
|
||||
logger.warning('No ship retired, exit')
|
||||
logger.warning('Please configure your one-click-retire in game, '
|
||||
'make sure it can select ships to retire')
|
||||
exit(1)
|
||||
logger.critical('No ship retired')
|
||||
logger.critical('Please configure your one-click-retire in game, '
|
||||
'make sure it can select ships to retire')
|
||||
raise RequestHumanTakeover
|
||||
elif mode == 'old_retire':
|
||||
total = self.retire_ships_old()
|
||||
if not total:
|
||||
logger.warning('No ship retired, exit')
|
||||
logger.warning('Please configure your retirement settings in Alas, '
|
||||
'make sure it can select ships to retire')
|
||||
exit(1)
|
||||
logger.critical('No ship retired')
|
||||
logger.critical('Please configure your retirement settings in Alas, '
|
||||
'make sure it can select ships to retire')
|
||||
raise RequestHumanTakeover
|
||||
else:
|
||||
logger.warning(f'Unknown retire mode: {self.config.Retirement_RetireMode}')
|
||||
total = 0
|
||||
exit(1)
|
||||
raise ScriptError(f'Unknown retire mode: {self.config.Retirement_RetireMode}')
|
||||
|
||||
self._retirement_quit()
|
||||
self.config.DOCK_FULL_TRIGGERED = True
|
||||
@ -366,11 +365,5 @@ class Retirement(Enhancement):
|
||||
def keep_one_common_cv(self):
|
||||
button = self.retirement_get_common_rarity_cv()
|
||||
if button is not None:
|
||||
if self._retire_select_one(button, skip_first_screenshot=False):
|
||||
self._have_keeped_cv = True
|
||||
|
||||
else:
|
||||
logger.warning('No ship retired, exit')
|
||||
logger.info(
|
||||
'This may happens because some filters are set in dock')
|
||||
exit(1)
|
||||
self._retire_select_one(button, skip_first_screenshot=False)
|
||||
self._have_keeped_cv = True
|
||||
|
@ -1,7 +1,7 @@
|
||||
from module.base.button import Button
|
||||
from module.base.timer import Timer
|
||||
from module.combat.assets import *
|
||||
from module.exception import GameNotRunningError
|
||||
from module.exception import GameNotRunningError, RequestHumanTakeover
|
||||
from module.handler.assets import *
|
||||
from module.handler.info_handler import InfoHandler
|
||||
from module.logger import logger
|
||||
@ -125,7 +125,8 @@ class UI(InfoHandler):
|
||||
if not self.device.app_is_running():
|
||||
raise GameNotRunningError('Game not running')
|
||||
else:
|
||||
exit(1)
|
||||
logger.critical('Please switch to a supported page before starting Alas')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def ui_goto(self, destination, offset=(20, 20), confirm_wait=0, skip_first_screenshot=True):
|
||||
"""
|
||||
@ -260,6 +261,8 @@ class UI(InfoHandler):
|
||||
# Research popup, lost connection popup
|
||||
if self.handle_popup_confirm('UI_ADDITIONAL'):
|
||||
return True
|
||||
if self.handle_urgent_commission():
|
||||
return True
|
||||
|
||||
# Guild popup
|
||||
if self.handle_guild_popup_cancel():
|
||||
|
Loading…
Reference in New Issue
Block a user