From 0af3593fd35acf370ab3c0cf5080582c69cda1dc Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Sat, 11 Jun 2022 11:55:38 +0800 Subject: [PATCH 01/15] Squash commits Add: Check server status before running a task, wait until available Opt: Add request headers and calm the users Fix: Config won't update after server recovered Update argument.yaml Revert inappropriate changes and make code more pretty Fix: Check server after get_next_task Fix: KeyError when Alas restarts after recovery Fix: fix bug and optimize code; Add: EN support Fix typo; Optimize API calls Opt: Further reduce API calls Opt: Use random UA --- alas.py | 33 ++++++ module/config/argument/args.json | 12 ++ module/config/argument/argument.yaml | 3 + module/config/i18n/en-US.json | 10 ++ module/config/i18n/ja-JP.json | 10 ++ module/config/i18n/zh-CN.json | 10 ++ module/config/i18n/zh-TW.json | 10 ++ module/server_checker.py | 167 +++++++++++++++++++++++++++ 8 files changed, 255 insertions(+) create mode 100644 module/server_checker.py diff --git a/alas.py b/alas.py index c7af7af3d..ed89a2902 100644 --- a/alas.py +++ b/alas.py @@ -47,6 +47,20 @@ class AzurLaneAutoScript: logger.exception(e) exit(1) + @cached_property + def checker(self): + try: + from module.server_checker import ServerChecker + checker = ServerChecker(server=self.config.Emulator_ServerPlatform) + except Exception as e: + logger.critical(e) + logger.warning('There may be something wrong with server checker.') + logger.warning('Server checker will be temporarily forced off.') + self.config.Emulator_ServerPlatform = 'disabled' + checker = ServerChecker(server=self.config.Emulator_ServerPlatform) + finally: + return checker + def run(self, command): try: self.device.screenshot() @@ -403,12 +417,26 @@ class AzurLaneAutoScript: failure_record = {} while 1: + self.checker.wait_until_available() + if self.checker.is_recovered(): + # There is an accidental bug hard to reproduce + # Sometimes, config won't be updated due to blocking + # even though it has been changed + # So update it once recovered + if 'config' in self.__dict__: + del self.__dict__['config'] + if self.checker.is_after_maintenance(): + logger.info('Server maintenance is over. Restart game client to update.') + self.run('restart') + if self.stop_event is not None: if self.stop_event.is_set(): logger.info("Update event detected") logger.info(f"Alas [{self.config_name}] exited.") break task = self.get_next_task() + if not self.checker.is_available(): + continue # Skip first restart if is_first and task == 'Restart': @@ -445,6 +473,11 @@ class AzurLaneAutoScript: elif self.config.Error_HandleError: # self.config.task_delay(success=False) del self.__dict__['config'] + + self.checker.check_now() + if not self.checker.is_enabled(): + if self.config.Emulator_ServerPlatform != 'disabled': + self.config.Emulator_ServerPlatform = 'disabled' continue else: break diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 56b415f64..2b768a988 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -29,6 +29,18 @@ "com.hkmanjuu.azurlane.gp.mc" ] }, + "ServerPlatform": { + "type": "select", + "value": "disabled", + "option": [ + "disabled", + "cn_android", + "cn_ios", + "cn_channel", + "en", + "en_channel" + ] + }, "ScreenshotMethod": { "type": "select", "value": "ADB", diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index cb7c3e0fa..8b46a55fc 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -24,6 +24,9 @@ Emulator: PackageName: value: auto option: [auto, ] + ServerPlatform: + value: disabled + option: [disabled, cn_android, cn_ios, cn_channel, en, en_channel] ScreenshotMethod: value: ADB option: [ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc] diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index ecce2fe49..662ffacec 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -299,6 +299,16 @@ "com.yiwu.blhx.yx15": "CN com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "TW com.hkmanjuu.azurlane.gp.mc" }, + "ServerPlatform": { + "name": "Server Platform", + "help": "Select your server platform to enable server status detection\nScript will hang up when server is being maintained or network is broken", + "disabled": "Disabled", + "cn_android": "CN-Android", + "cn_ios": "CN-IOS", + "cn_channel": "CN-Channel", + "en": "EN", + "en_channel": "EN-Channel" + }, "ScreenshotMethod": { "name": "Screenshot Method", "help": "Speed: aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\nRun Tools - Performance Test to find the fastest method", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index 3f4808823..eab8d5eb1 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -299,6 +299,16 @@ "com.yiwu.blhx.yx15": "CN com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "TW com.hkmanjuu.azurlane.gp.mc" }, + "ServerPlatform": { + "name": "Emulator.ServerPlatform.name", + "help": "Emulator.ServerPlatform.help", + "disabled": "Disabled", + "cn_android": "CN-Android", + "cn_ios": "CN-IOS", + "cn_channel": "CN-Channel", + "en": "EN", + "en_channel": "EN-Channel" + }, "ScreenshotMethod": { "name": "Emulator.ScreenshotMethod.name", "help": "Emulator.ScreenshotMethod.help", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index c40e5e950..f733c1fff 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -299,6 +299,16 @@ "com.yiwu.blhx.yx15": "国服 一五游戏渠道服 com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "台服 com.hkmanjuu.azurlane.gp.mc" }, + "ServerPlatform": { + "name": "服务器平台", + "help": "选择服务器平台以启用服务器状态检测\n当服务器维护或网络不可用时挂起直到恢复", + "disabled": "不使用", + "cn_android": "国服-安卓端", + "cn_ios": "国服-IOS端", + "cn_channel": "国服-渠道服", + "en": "国际服", + "en_channel": "国际服-渠道服" + }, "ScreenshotMethod": { "name": "模拟器截图方案", "help": "速度: aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n运行 工具 - 性能测试 以寻找最快的方案", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 284e9b181..e4d2a17e3 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -299,6 +299,16 @@ "com.yiwu.blhx.yx15": "國服 com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "台服 MyCard渠道服 com.hkmanjuu.azurlane.gp.mc" }, + "ServerPlatform": { + "name": "伺服器平台", + "help": "選擇伺服器平台以啓用伺服器狀態檢測\n當伺服器維護或網路不可用時挂起直到恢複", + "disabled": "不使用", + "cn_android": "國服-安卓端", + "cn_ios": "國服-IOS端", + "cn_channel": "國服-渠道服", + "en": "國際服", + "en_channel": "國際服-渠道服" + }, "ScreenshotMethod": { "name": "模擬器截圖方案", "help": "速度: aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n運行 工具 - 性能測試 以尋找最快的方案", diff --git a/module/server_checker.py b/module/server_checker.py new file mode 100644 index 000000000..519f78cf9 --- /dev/null +++ b/module/server_checker.py @@ -0,0 +1,167 @@ +import random +from collections import deque +from json import JSONDecodeError + +import requests + +from module.base.timer import Timer +from module.exception import ScriptError +from module.logger import logger + + +class ServerChecker: + def __init__(self, server: str) -> None: + self._base: dict = { + 'cn_android': '', + 'cn_ios': '', + 'cn_channel': '', + 'en': '', + 'en_channel': '', + 'disabled': '' + } + + self._UA: list = [ + 'Dalvik/2.1.0 (Linux; U; Android 6.0.1; MuMu Build/V417IR)', + ] + + if server not in self._base: + logger.warning(f'Unsupported server platform "{server}" for server checker.') + logger.warning('Disable server checker by default.') + server = 'disabled' + + self._server: str = server + self._state: deque = deque(maxlen=2) + self._reason: str = '' + self._interval: int = 0 + self._timer: Timer = Timer(60 * 5) # check per 5 mins + + self.check_now() + + def _load_server(self) -> None: + """ + Get server status using API. + Set reason if server is unavailable. + + ScriptError will be raised if somthing is wrong with API. + """ + if self._server == 'disabled': + self._state.append(True) + return + + try: + resp = requests.get( + # the last '?' will be escaped if use params, don't do so + url=f'{self._base[self._server]}?cmd=load_server?', + headers={ + 'User-Agent': f'{random.choice(self._UA)}', + 'Accept-Encoding': 'gzip', + 'Accept': '*/*', + 'Connection': 'Keep-Alive', + 'X-Unity-Version': '2018.4.34f1', + 'Host': f'{self._base[self._server]}' + }, + timeout=3, + ) + if resp.ok: + j = resp.json() + server_state = sum([1 if server['state'] == 1 else 0 for server in j]) + if server_state / len(j) > 0.5: + self._reason = f'The server "{self._server}" is being maintained. Please wait' + self._state.append(False) + else: + self._state.append(True) + else: + self._reason = f'Server "{self._server}" return status code {resp.status_code}' + self._state.append(False) + raise ScriptError(self._reason) + except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout): + self._reason = 'Unable to connect to the server. Please check your network status' + self._state.append(False) + except JSONDecodeError: + self._reason = f'Response of "{self._server}" seems not to be a JSON' + self._state.append(False) + raise ScriptError(self._reason) + except Exception as e: + self._reason = str(e) + self._state.append(False) + + def wait_until_available(self) -> None: + while not self.is_available(): + self._timer.wait() + self.check_now() + + def check_now(self) -> None: + """ + Ignore timer and get server status immediately. + + If server is available, timer will be set to 30 mins. + Otherwise, timer will gradually increases from 1 to 5 min(s). + + If a ScriptError occurs, server checker will be temporarily forced off. + """ + try: + self._load_server() + if self._state[-1]: + self._interval = 0 + else: + if self._interval < 5: + self._interval += 1 + + # Only show reason when server is unavailable. + if not self._state[-1]: + if "Unable" in self._reason: + logger.warning(f'{self._reason}. Server checker will retry after {self._interval} mins') + else: + logger.info(f'{self._reason}. Server checker will retry after {self._interval} mins') + except ScriptError as e: + logger.critical(e) + logger.warning('There may be something wrong with server checker.') + logger.warning('Server checker will be temporarily forced off.') + self._server = 'disabled' + self._interval = 0 + self._state.clear() + self._state.append(True) + finally: + self._timer.limit = 60 * (30 if self._interval == 0 else self._interval) + self._timer.reset() + + def is_available(self) -> bool: + """ + Return server status using cache. + + Returns: + bool: True if server is available. + """ + if self._interval != 0 and self._timer.reached(): + self.check_now() + + return self._state[-1] # return the latest state + + def is_recovered(self) -> bool: + """ + Returns: + bool: True if server is recovered from an unavailable state. + """ + if len(self._state) < 2: + return False + + return self._state[0] is False and self._state[-1] is True + + def is_after_maintenance(self) -> bool: + """ + Reason will only be updated when server is unavailable + Thus, client need to reesart when server recovers + with keyword 'maintained' in self._reason + + Returns: + bool: True if server is after maintenance. + """ + if self._server == 'disabled': + return False + if not self._state[-1]: + return False + + return 'maintained' in self._reason + + def is_enabled(self) -> bool: + return self._server != 'disabled' From aa4d7b4b08ef287270956d68d771fb42332af7a9 Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Thu, 21 Jul 2022 10:09:20 +0800 Subject: [PATCH 02/15] Opt: Use common API --- alas.py | 20 +--- config/template.json | 1 + module/config/argument/args.json | 49 +++++++- module/config/argument/argument.yaml | 4 +- module/config/config_generated.py | 1 + module/config/config_updater.py | 18 ++- module/config/i18n/en-US.json | 55 +++++++-- module/config/i18n/ja-JP.json | 55 +++++++-- module/config/i18n/zh-CN.json | 55 +++++++-- module/config/i18n/zh-TW.json | 49 +++++++- module/config/server.py | 19 +++ module/server_checker.py | 165 ++++++++++++++------------- 12 files changed, 358 insertions(+), 133 deletions(-) diff --git a/alas.py b/alas.py index ed89a2902..3fef5419c 100644 --- a/alas.py +++ b/alas.py @@ -51,15 +51,11 @@ class AzurLaneAutoScript: def checker(self): try: from module.server_checker import ServerChecker - checker = ServerChecker(server=self.config.Emulator_ServerPlatform) - except Exception as e: - logger.critical(e) - logger.warning('There may be something wrong with server checker.') - logger.warning('Server checker will be temporarily forced off.') - self.config.Emulator_ServerPlatform = 'disabled' - checker = ServerChecker(server=self.config.Emulator_ServerPlatform) - finally: + checker = ServerChecker(server=self.config.Emulator_ServerName) return checker + except Exception as e: + logger.exception(e) + exit(1) def run(self, command): try: @@ -425,7 +421,7 @@ class AzurLaneAutoScript: # So update it once recovered if 'config' in self.__dict__: del self.__dict__['config'] - if self.checker.is_after_maintenance(): + if self.checker.is_maintenance_over(): logger.info('Server maintenance is over. Restart game client to update.') self.run('restart') @@ -435,8 +431,6 @@ class AzurLaneAutoScript: logger.info(f"Alas [{self.config_name}] exited.") break task = self.get_next_task() - if not self.checker.is_available(): - continue # Skip first restart if is_first and task == 'Restart': @@ -473,11 +467,7 @@ class AzurLaneAutoScript: elif self.config.Error_HandleError: # self.config.task_delay(success=False) del self.__dict__['config'] - self.checker.check_now() - if not self.checker.is_enabled(): - if self.config.Emulator_ServerPlatform != 'disabled': - self.config.Emulator_ServerPlatform = 'disabled' continue else: break diff --git a/config/template.json b/config/template.json index ff445a475..20d871607 100644 --- a/config/template.json +++ b/config/template.json @@ -3,6 +3,7 @@ "Emulator": { "Serial": "auto", "PackageName": "auto", + "ServerName": "disabled", "ScreenshotMethod": "ADB", "ControlMethod": "minitouch", "ScreenshotDedithering": false diff --git a/module/config/argument/args.json b/module/config/argument/args.json index 2b768a988..28fd6fa75 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -29,16 +29,53 @@ "com.hkmanjuu.azurlane.gp.mc" ] }, - "ServerPlatform": { + "ServerName": { "type": "select", "value": "disabled", "option": [ "disabled", - "cn_android", - "cn_ios", - "cn_channel", - "en", - "en_channel" + "cn_android-0", + "cn_android-1", + "cn_android-2", + "cn_android-3", + "cn_android-4", + "cn_android-5", + "cn_android-6", + "cn_android-7", + "cn_android-8", + "cn_android-9", + "cn_android-10", + "cn_android-11", + "cn_android-12", + "cn_android-13", + "cn_android-14", + "cn_android-15", + "cn_android-16", + "cn_android-17", + "cn_android-18", + "cn_android-19", + "cn_android-20", + "cn_android-21", + "cn_ios-0", + "cn_ios-1", + "cn_ios-2", + "cn_ios-3", + "cn_ios-4", + "cn_ios-5", + "cn_ios-6", + "cn_ios-7", + "cn_ios-8", + "cn_ios-9", + "cn_ios-10", + "cn_channel-0", + "cn_channel-1", + "cn_channel-2", + "cn_channel-3", + "en-0", + "en-1", + "en-2", + "en-3", + "en-4" ] }, "ScreenshotMethod": { diff --git a/module/config/argument/argument.yaml b/module/config/argument/argument.yaml index 8b46a55fc..dfdf6b40e 100644 --- a/module/config/argument/argument.yaml +++ b/module/config/argument/argument.yaml @@ -24,9 +24,9 @@ Emulator: PackageName: value: auto option: [auto, ] - ServerPlatform: + ServerName: value: disabled - option: [disabled, cn_android, cn_ios, cn_channel, en, en_channel] + option: [disabled, ] ScreenshotMethod: value: ADB option: [ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc] diff --git a/module/config/config_generated.py b/module/config/config_generated.py index b960a31ac..c7fb719e7 100644 --- a/module/config/config_generated.py +++ b/module/config/config_generated.py @@ -20,6 +20,7 @@ class GeneratedConfig: # Group `Emulator` Emulator_Serial = 'auto' Emulator_PackageName = 'auto' # auto, com.bilibili.azurlane, com.YoStarEN.AzurLane, com.YoStarJP.AzurLane, com.hkmanjuu.azurlane.gp, com.bilibili.blhx.huawei, com.bilibili.blhx.mi, com.tencent.tmgp.bilibili.blhx, com.bilibili.blhx.baidu, com.bilibili.blhx.qihoo, com.bilibili.blhx.oppo, com.bilibili.blhx.vivo, com.bilibili.blhx.mz, com.bilibili.blhx.uc, com.bilibili.blhx.mzw, com.yiwu.blhx.yx15, com.hkmanjuu.azurlane.gp.mc + Emulator_ServerName = 'disabled' # disabled, cn_android-0, cn_android-1, cn_android-2, cn_android-3, cn_android-4, cn_android-5, cn_android-6, cn_android-7, cn_android-8, cn_android-9, cn_android-10, cn_android-11, cn_android-12, cn_android-13, cn_android-14, cn_android-15, cn_android-16, cn_android-17, cn_android-18, cn_android-19, cn_android-20, cn_android-21, cn_ios-0, cn_ios-1, cn_ios-2, cn_ios-3, cn_ios-4, cn_ios-5, cn_ios-6, cn_ios-7, cn_ios-8, cn_ios-9, cn_ios-10, cn_channel-0, cn_channel-1, cn_channel-2, cn_channel-3, en-0, en-1, en-2, en-3, en-4 Emulator_ScreenshotMethod = 'ADB' # ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc Emulator_ControlMethod = 'minitouch' # ADB, uiautomator2, minitouch, Hermit Emulator_ScreenshotDedithering = False diff --git a/module/config/config_updater.py b/module/config/config_updater.py index 8189e385c..e5d002d02 100644 --- a/module/config/config_updater.py +++ b/module/config/config_updater.py @@ -7,7 +7,7 @@ from deploy.utils import DEPLOY_TEMPLATE, poor_yaml_read, poor_yaml_write from module.base.timer import timer from module.config.redirect_utils.shop_filter import bp_redirect from module.config.redirect_utils.utils import upload_redirect, api_redirect -from module.config.server import to_server, to_package, VALID_PACKAGE, VALID_CHANNEL_PACKAGE +from module.config.server import to_server, to_package, VALID_PACKAGE, VALID_CHANNEL_PACKAGE, VALID_SERVER_LIST from module.config.utils import * CONFIG_IMPORT = ''' @@ -282,6 +282,11 @@ class ConfigGenerator: else: value = f'{name} {package}' deep_set(new, keys=['Emulator', 'PackageName', package], value=value) + # Game server names + for server, _list in VALID_SERVER_LIST.items(): + for index in range(len(_list)): + path = ['Emulator', 'ServerName', f'{server}-{index}'] + deep_set(new, keys=path, value=_list[index]) # GUI i18n for path, _ in deep_iter(self.gui, depth=2): group, key = path @@ -406,6 +411,16 @@ class ConfigGenerator: deep_set(self.argument, keys='Emulator.PackageName.option', value=option) deep_set(self.args, keys='Alas.Emulator.PackageName.option', value=option) + def insert_server(self): + option = deep_get(self.argument, keys='Emulator.ServerName.option') + server_list = [] + for server, _list in VALID_SERVER_LIST.items(): + for index in range(len(_list)): + server_list.append(f'{server}-{index}') + option += server_list + deep_set(self.argument, keys='Emulator.ServerName.option', value=option) + deep_set(self.args, keys='Alas.Emulator.ServerName.option', value=option) + @timer def generate(self): _ = self.args @@ -413,6 +428,7 @@ class ConfigGenerator: _ = self.event self.insert_event() self.insert_package() + self.insert_server() write_file(filepath_args(), self.args) write_file(filepath_args('menu'), self.menu) self.generate_code() diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index 662ffacec..e3413b44e 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -299,15 +299,52 @@ "com.yiwu.blhx.yx15": "CN com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "TW com.hkmanjuu.azurlane.gp.mc" }, - "ServerPlatform": { - "name": "Server Platform", - "help": "Select your server platform to enable server status detection\nScript will hang up when server is being maintained or network is broken", - "disabled": "Disabled", - "cn_android": "CN-Android", - "cn_ios": "CN-IOS", - "cn_channel": "CN-Channel", - "en": "EN", - "en_channel": "EN-Channel" + "ServerName": { + "name": "Server in Game Client", + "help": "Select the server where you are in the game to enable server status detection\nScript will hang up when server is being maintained or network is broken", + "disabled": "disabled", + "cn_android-0": "莱茵演习", + "cn_android-1": "巴巴罗萨", + "cn_android-2": "霸王行动", + "cn_android-3": "冰山行动", + "cn_android-4": "彩虹计划", + "cn_android-5": "发电机计划", + "cn_android-6": "瞭望台行动", + "cn_android-7": "十字路口行动", + "cn_android-8": "朱诺行动", + "cn_android-9": "杜立特空袭", + "cn_android-10": "地狱犬行动", + "cn_android-11": "开罗宣言", + "cn_android-12": "奥林匹克行动", + "cn_android-13": "小王冠行动", + "cn_android-14": "波茨坦公告", + "cn_android-15": "白色方案", + "cn_android-16": "瓦尔基里行动", + "cn_android-17": "曼哈顿计划", + "cn_android-18": "八月风暴", + "cn_android-19": "秋季旅行", + "cn_android-20": "水星行动", + "cn_android-21": "莱茵河卫兵", + "cn_ios-0": "夏威夷", + "cn_ios-1": "珊瑚海", + "cn_ios-2": "中途岛", + "cn_ios-3": "铁底湾", + "cn_ios-4": "所罗门", + "cn_ios-5": "马里亚纳", + "cn_ios-6": "莱特湾", + "cn_ios-7": "硫磺岛", + "cn_ios-8": "冲绳岛", + "cn_ios-9": "阿留申群岛", + "cn_ios-10": "马耳他", + "cn_channel-0": "皇家巡游", + "cn_channel-1": "大西洋宪章", + "cn_channel-2": "十字军行动", + "cn_channel-3": "龙骑兵行动", + "en-0": "Avrora", + "en-1": "Lexington", + "en-2": "Sandy", + "en-3": "Washington", + "en-4": "Amagi" }, "ScreenshotMethod": { "name": "Screenshot Method", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index eab8d5eb1..ec3c67184 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -299,15 +299,52 @@ "com.yiwu.blhx.yx15": "CN com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "TW com.hkmanjuu.azurlane.gp.mc" }, - "ServerPlatform": { - "name": "Emulator.ServerPlatform.name", - "help": "Emulator.ServerPlatform.help", - "disabled": "Disabled", - "cn_android": "CN-Android", - "cn_ios": "CN-IOS", - "cn_channel": "CN-Channel", - "en": "EN", - "en_channel": "EN-Channel" + "ServerName": { + "name": "Emulator.ServerName.name", + "help": "Emulator.ServerName.help", + "disabled": "disabled", + "cn_android-0": "莱茵演习", + "cn_android-1": "巴巴罗萨", + "cn_android-2": "霸王行动", + "cn_android-3": "冰山行动", + "cn_android-4": "彩虹计划", + "cn_android-5": "发电机计划", + "cn_android-6": "瞭望台行动", + "cn_android-7": "十字路口行动", + "cn_android-8": "朱诺行动", + "cn_android-9": "杜立特空袭", + "cn_android-10": "地狱犬行动", + "cn_android-11": "开罗宣言", + "cn_android-12": "奥林匹克行动", + "cn_android-13": "小王冠行动", + "cn_android-14": "波茨坦公告", + "cn_android-15": "白色方案", + "cn_android-16": "瓦尔基里行动", + "cn_android-17": "曼哈顿计划", + "cn_android-18": "八月风暴", + "cn_android-19": "秋季旅行", + "cn_android-20": "水星行动", + "cn_android-21": "莱茵河卫兵", + "cn_ios-0": "夏威夷", + "cn_ios-1": "珊瑚海", + "cn_ios-2": "中途岛", + "cn_ios-3": "铁底湾", + "cn_ios-4": "所罗门", + "cn_ios-5": "马里亚纳", + "cn_ios-6": "莱特湾", + "cn_ios-7": "硫磺岛", + "cn_ios-8": "冲绳岛", + "cn_ios-9": "阿留申群岛", + "cn_ios-10": "马耳他", + "cn_channel-0": "皇家巡游", + "cn_channel-1": "大西洋宪章", + "cn_channel-2": "十字军行动", + "cn_channel-3": "龙骑兵行动", + "en-0": "Avrora", + "en-1": "Lexington", + "en-2": "Sandy", + "en-3": "Washington", + "en-4": "Amagi" }, "ScreenshotMethod": { "name": "Emulator.ScreenshotMethod.name", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index f733c1fff..d459dd5f4 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -299,15 +299,52 @@ "com.yiwu.blhx.yx15": "国服 一五游戏渠道服 com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "台服 com.hkmanjuu.azurlane.gp.mc" }, - "ServerPlatform": { - "name": "服务器平台", - "help": "选择服务器平台以启用服务器状态检测\n当服务器维护或网络不可用时挂起直到恢复", - "disabled": "不使用", - "cn_android": "国服-安卓端", - "cn_ios": "国服-IOS端", - "cn_channel": "国服-渠道服", - "en": "国际服", - "en_channel": "国际服-渠道服" + "ServerName": { + "name": "游戏内服务器", + "help": "选择游戏内所在的服务器以启用服务器状态检测\n当服务器维护或网络不可用时挂起直到恢复", + "disabled": "disabled", + "cn_android-0": "莱茵演习", + "cn_android-1": "巴巴罗萨", + "cn_android-2": "霸王行动", + "cn_android-3": "冰山行动", + "cn_android-4": "彩虹计划", + "cn_android-5": "发电机计划", + "cn_android-6": "瞭望台行动", + "cn_android-7": "十字路口行动", + "cn_android-8": "朱诺行动", + "cn_android-9": "杜立特空袭", + "cn_android-10": "地狱犬行动", + "cn_android-11": "开罗宣言", + "cn_android-12": "奥林匹克行动", + "cn_android-13": "小王冠行动", + "cn_android-14": "波茨坦公告", + "cn_android-15": "白色方案", + "cn_android-16": "瓦尔基里行动", + "cn_android-17": "曼哈顿计划", + "cn_android-18": "八月风暴", + "cn_android-19": "秋季旅行", + "cn_android-20": "水星行动", + "cn_android-21": "莱茵河卫兵", + "cn_ios-0": "夏威夷", + "cn_ios-1": "珊瑚海", + "cn_ios-2": "中途岛", + "cn_ios-3": "铁底湾", + "cn_ios-4": "所罗门", + "cn_ios-5": "马里亚纳", + "cn_ios-6": "莱特湾", + "cn_ios-7": "硫磺岛", + "cn_ios-8": "冲绳岛", + "cn_ios-9": "阿留申群岛", + "cn_ios-10": "马耳他", + "cn_channel-0": "皇家巡游", + "cn_channel-1": "大西洋宪章", + "cn_channel-2": "十字军行动", + "cn_channel-3": "龙骑兵行动", + "en-0": "Avrora", + "en-1": "Lexington", + "en-2": "Sandy", + "en-3": "Washington", + "en-4": "Amagi" }, "ScreenshotMethod": { "name": "模拟器截图方案", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index e4d2a17e3..73ee4ba4c 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -299,9 +299,56 @@ "com.yiwu.blhx.yx15": "國服 com.yiwu.blhx.yx15", "com.hkmanjuu.azurlane.gp.mc": "台服 MyCard渠道服 com.hkmanjuu.azurlane.gp.mc" }, + "ServerName": { + "name": "遊戲内伺服器", + "help": "選擇遊戲內所在的伺服器以啓用伺服器狀態檢測\n當伺服器維護或網路不可用時挂起直到恢複", + "disabled": "disabled", + "cn_android-0": "莱茵演习", + "cn_android-1": "巴巴罗萨", + "cn_android-2": "霸王行动", + "cn_android-3": "冰山行动", + "cn_android-4": "彩虹计划", + "cn_android-5": "发电机计划", + "cn_android-6": "瞭望台行动", + "cn_android-7": "十字路口行动", + "cn_android-8": "朱诺行动", + "cn_android-9": "杜立特空袭", + "cn_android-10": "地狱犬行动", + "cn_android-11": "开罗宣言", + "cn_android-12": "奥林匹克行动", + "cn_android-13": "小王冠行动", + "cn_android-14": "波茨坦公告", + "cn_android-15": "白色方案", + "cn_android-16": "瓦尔基里行动", + "cn_android-17": "曼哈顿计划", + "cn_android-18": "八月风暴", + "cn_android-19": "秋季旅行", + "cn_android-20": "水星行动", + "cn_android-21": "莱茵河卫兵", + "cn_ios-0": "夏威夷", + "cn_ios-1": "珊瑚海", + "cn_ios-2": "中途岛", + "cn_ios-3": "铁底湾", + "cn_ios-4": "所罗门", + "cn_ios-5": "马里亚纳", + "cn_ios-6": "莱特湾", + "cn_ios-7": "硫磺岛", + "cn_ios-8": "冲绳岛", + "cn_ios-9": "阿留申群岛", + "cn_ios-10": "马耳他", + "cn_channel-0": "皇家巡游", + "cn_channel-1": "大西洋宪章", + "cn_channel-2": "十字军行动", + "cn_channel-3": "龙骑兵行动", + "en-0": "Avrora", + "en-1": "Lexington", + "en-2": "Sandy", + "en-3": "Washington", + "en-4": "Amagi" + }, "ServerPlatform": { "name": "伺服器平台", - "help": "選擇伺服器平台以啓用伺服器狀態檢測\n當伺服器維護或網路不可用時挂起直到恢複", + "help": "", "disabled": "不使用", "cn_android": "國服-安卓端", "cn_ios": "國服-IOS端", diff --git a/module/config/server.py b/module/config/server.py index 9ab9badab..1bfc7235b 100644 --- a/module/config/server.py +++ b/module/config/server.py @@ -32,6 +32,25 @@ VALID_CHANNEL_PACKAGE = { # Tw 'com.hkmanjuu.azurlane.gp.mc': ('tw', 'MyCard'), } +VALID_SERVER_LIST = { + 'cn_android': [ + '莱茵演习', '巴巴罗萨', '霸王行动', '冰山行动', '彩虹计划', + '发电机计划', '瞭望台行动', '十字路口行动', '朱诺行动', + '杜立特空袭', '地狱犬行动', '开罗宣言', '奥林匹克行动', + '小王冠行动', '波茨坦公告', '白色方案', '瓦尔基里行动', + '曼哈顿计划', '八月风暴', '秋季旅行', '水星行动', '莱茵河卫兵' + ], + 'cn_ios': [ + '夏威夷', '珊瑚海', '中途岛', '铁底湾', '所罗门', '马里亚纳', + '莱特湾', '硫磺岛', '冲绳岛', '阿留申群岛', '马耳他' + ], + 'cn_channel': [ + '皇家巡游', '大西洋宪章', '十字军行动', '龙骑兵行动' + ], + 'en': [ + 'Avrora', 'Lexington', 'Sandy', 'Washington', 'Amagi' + ] +} def set_server(package_or_server: str): diff --git a/module/server_checker.py b/module/server_checker.py index 519f78cf9..ed076464c 100644 --- a/module/server_checker.py +++ b/module/server_checker.py @@ -1,39 +1,36 @@ -import random from collections import deque from json import JSONDecodeError import requests from module.base.timer import Timer +from module.config.server import VALID_SERVER_LIST as server_list from module.exception import ScriptError from module.logger import logger class ServerChecker: def __init__(self, server: str) -> None: - self._base: dict = { - 'cn_android': '', - 'cn_ios': '', - 'cn_channel': '', - 'en': '', - 'en_channel': '', - 'disabled': '' + self._base: str = 'http://43.132.174.132:20002' + self._api: dict = { + 'get_state': '/server/get_state', # post + 'get_all_state': '/server/get_all_state', # post + 'list': '/server/list' # get } - self._UA: list = [ - 'Dalvik/2.1.0 (Linux; U; Android 6.0.1; MuMu Build/V417IR)', - ] - - if server not in self._base: - logger.warning(f'Unsupported server platform "{server}" for server checker.') - logger.warning('Disable server checker by default.') - server = 'disabled' + if server != 'disabled': + server = server.split('-') + server = server_list[server[0]][int(server[-1])] self._server: str = server self._state: deque = deque(maxlen=2) - self._reason: str = '' - self._interval: int = 0 - self._timer: Timer = Timer(60 * 5) # check per 5 mins + self._timestamp: int = 0 + self._expired: int = 0 + self._timer: Timer = Timer(0) + + # Status flags + self._recover: bool = False + self._maintained: bool = False self.check_now() @@ -49,41 +46,46 @@ class ServerChecker: return try: - resp = requests.get( - # the last '?' will be escaped if use params, don't do so - url=f'{self._base[self._server]}?cmd=load_server?', - headers={ - 'User-Agent': f'{random.choice(self._UA)}', - 'Accept-Encoding': 'gzip', - 'Accept': '*/*', - 'Connection': 'Keep-Alive', - 'X-Unity-Version': '2018.4.34f1', - 'Host': f'{self._base[self._server]}' + resp = requests.post( + url=f'{self._base}{self._api["get_state"]}', + params={ + 'server_name': self._server }, - timeout=3, + timeout=15 ) - if resp.ok: + if resp.status_code == 200: j = resp.json() - server_state = sum([1 if server['state'] == 1 else 0 for server in j]) - if server_state / len(j) > 0.5: - self._reason = f'The server "{self._server}" is being maintained. Please wait' - self._state.append(False) - else: + if j['state'] != 1: self._state.append(True) - else: - self._reason = f'Server "{self._server}" return status code {resp.status_code}' + logger.info(f'Server "{self._server}" is available.') + else: + self._state.append(False) + self._maintained = True + logger.info(f'Server "{self._server}" is under maintenance.') + + # Check if API server was died + if j['last_update'] > self._timestamp: + self._timestamp = j['last_update'] + self._expired = 0 + else: + self._expired += 1 + if self._expired > 3: + logger.info(f'Last update timestamp = {self._timestamp}') + raise ScriptError('Timestamp has not been updated for 3 times.') + elif resp.status_code == 404: self._state.append(False) - raise ScriptError(self._reason) + raise ScriptError(f'Server "{self._server}" does not exist!') + else: + raise ScriptError(f'Get status_code {resp.status_code}. Response is {resp.text}') except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout): - self._reason = 'Unable to connect to the server. Please check your network status' + logger.warning('Unable to connect to the server. Please check your network status.') self._state.append(False) except JSONDecodeError: - self._reason = f'Response of "{self._server}" seems not to be a JSON' self._state.append(False) - raise ScriptError(self._reason) + raise ScriptError(f'Response "{resp.text}" seems not to be a JSON.') except Exception as e: - self._reason = str(e) self._state.append(False) + raise e def wait_until_available(self) -> None: while not self.is_available(): @@ -94,36 +96,41 @@ class ServerChecker: """ Ignore timer and get server status immediately. - If server is available, timer will be set to 30 mins. - Otherwise, timer will gradually increases from 1 to 5 min(s). + If server is available, server checker will keep silence. + Otherwise, timer will gradually increases from 2 to 10 min(s). If a ScriptError occurs, server checker will be temporarily forced off. """ try: self._load_server() if self._state[-1]: - self._interval = 0 + self._timer.limit = 0 + # Recover means state[-1] is True and state[0] is False + if not self._state[0]: + self._recover = True else: - if self._interval < 5: - self._interval += 1 - - # Only show reason when server is unavailable. - if not self._state[-1]: - if "Unable" in self._reason: - logger.warning(f'{self._reason}. Server checker will retry after {self._interval} mins') - else: - logger.info(f'{self._reason}. Server checker will retry after {self._interval} mins') - except ScriptError as e: - logger.critical(e) - logger.warning('There may be something wrong with server checker.') - logger.warning('Server checker will be temporarily forced off.') - self._server = 'disabled' - self._interval = 0 - self._state.clear() - self._state.append(True) - finally: - self._timer.limit = 60 * (30 if self._interval == 0 else self._interval) + if self._timer.limit < 600: + self._timer.limit += 120 + logger.info(f'Server checker will retry after {self._timer.limit}s') self._timer.reset() + except ScriptError as e: + logger.warning(str(e)) + logger.warning('There may be something wrong with server checker.') + logger.warning('Please contact the developer to fix it.') + logger.warning('Server checker will be temporarily forced off.') + self.reset() + self._server = 'disabled' + self._recover = True + self._state.append(True) + except Exception as e: + raise e + + def reset(self) -> None: + self._timestamp = 0 + self._expired = 0 + self._timer.limit = 0 + self._recover = False + self._maintained = False def is_available(self) -> bool: """ @@ -132,7 +139,7 @@ class ServerChecker: Returns: bool: True if server is available. """ - if self._interval != 0 and self._timer.reached(): + if self._timer.limit != 0 and self._timer.reached(): self.check_now() return self._state[-1] # return the latest state @@ -145,23 +152,19 @@ class ServerChecker: if len(self._state) < 2: return False - return self._state[0] is False and self._state[-1] is True + if self._recover: + self._recover = False + return True - def is_after_maintenance(self) -> bool: + return False + + def is_maintenance_over(self) -> bool: """ - Reason will only be updated when server is unavailable - Thus, client need to reesart when server recovers - with keyword 'maintained' in self._reason - Returns: - bool: True if server is after maintenance. + bool: True if server maintenance is over. """ - if self._server == 'disabled': - return False - if not self._state[-1]: - return False + if self._maintained: + self._maintained = False + return True - return 'maintained' in self._reason - - def is_enabled(self) -> bool: - return self._server != 'disabled' + return False From 70f1a68e943e14dec46865d113f87ab0bb4bd98e Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Thu, 21 Jul 2022 10:20:28 +0800 Subject: [PATCH 03/15] Opt: Handler GamePageUnknownError when server is under maintenance --- alas.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/alas.py b/alas.py index 3fef5419c..9b3954cdc 100644 --- a/alas.py +++ b/alas.py @@ -85,9 +85,15 @@ class AzurLaneAutoScript: self.device.sleep(10) return False except GamePageUnknownError: - logger.critical('Game page unknown') - self.save_error_log() - exit(1) + logger.info('Game server may be under maintenance, check server status now') + self.checker.check_now() + if self.checker.is_available(): + logger.critical('Game page unknown') + self.save_error_log() + exit(1) + else: + self.checker.wait_until_available() + 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') From d6952ef02526f377b900ae2075552263f85b2e3b Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Fri, 22 Jul 2022 12:12:19 +0800 Subject: [PATCH 04/15] Opt: Reduce status; Restart when recovered --- alas.py | 7 +++---- module/server_checker.py | 14 -------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/alas.py b/alas.py index 9b3954cdc..fa93f7e75 100644 --- a/alas.py +++ b/alas.py @@ -85,7 +85,7 @@ class AzurLaneAutoScript: self.device.sleep(10) return False except GamePageUnknownError: - logger.info('Game server may be under maintenance, check server status now') + logger.info('Game server may be under maintenance or network may be broken, check server status now') self.checker.check_now() if self.checker.is_available(): logger.critical('Game page unknown') @@ -427,9 +427,8 @@ class AzurLaneAutoScript: # So update it once recovered if 'config' in self.__dict__: del self.__dict__['config'] - if self.checker.is_maintenance_over(): - logger.info('Server maintenance is over. Restart game client to update.') - self.run('restart') + logger.info('Server or network is recovered. Restart game client') + self.run('restart') if self.stop_event is not None: if self.stop_event.is_set(): diff --git a/module/server_checker.py b/module/server_checker.py index ed076464c..54eb5a4de 100644 --- a/module/server_checker.py +++ b/module/server_checker.py @@ -30,7 +30,6 @@ class ServerChecker: # Status flags self._recover: bool = False - self._maintained: bool = False self.check_now() @@ -60,7 +59,6 @@ class ServerChecker: logger.info(f'Server "{self._server}" is available.') else: self._state.append(False) - self._maintained = True logger.info(f'Server "{self._server}" is under maintenance.') # Check if API server was died @@ -130,7 +128,6 @@ class ServerChecker: self._expired = 0 self._timer.limit = 0 self._recover = False - self._maintained = False def is_available(self) -> bool: """ @@ -157,14 +154,3 @@ class ServerChecker: return True return False - - def is_maintenance_over(self) -> bool: - """ - Returns: - bool: True if server maintenance is over. - """ - if self._maintained: - self._maintained = False - return True - - return False From 105eb4dd1aa64f1b3b7f72785357ac7669794251 Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Fri, 22 Jul 2022 12:44:20 +0800 Subject: [PATCH 05/15] Opt: Skip restart if fail when init --- module/server_checker.py | 1 + 1 file changed, 1 insertion(+) diff --git a/module/server_checker.py b/module/server_checker.py index 54eb5a4de..c82654c44 100644 --- a/module/server_checker.py +++ b/module/server_checker.py @@ -147,6 +147,7 @@ class ServerChecker: bool: True if server is recovered from an unavailable state. """ if len(self._state) < 2: + self._recover = False return False if self._recover: From 80488c9c71fcc29b668913e4b336f6d1c7b3afc8 Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Thu, 28 Jul 2022 19:04:48 +0800 Subject: [PATCH 06/15] Opt: Use domain name instead of ip address --- module/server_checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/server_checker.py b/module/server_checker.py index c82654c44..d6e0df9dc 100644 --- a/module/server_checker.py +++ b/module/server_checker.py @@ -11,7 +11,7 @@ from module.logger import logger class ServerChecker: def __init__(self, server: str) -> None: - self._base: str = 'http://43.132.174.132:20002' + self._base: str = 'http://sc.shiratama.cn:20002' self._api: dict = { 'get_state': '/server/get_state', # post 'get_all_state': '/server/get_all_state', # post From 79ca99eccb8ee05f233ac92e6cae7c4c495b62c9 Mon Sep 17 00:00:00 2001 From: Horizon101011 <43370844+Horizon101011@users.noreply.github.com> Date: Mon, 1 Aug 2022 10:41:20 +0800 Subject: [PATCH 07/15] Opt: Remove port; Add server prefix --- alas.py | 4 +- module/config/config_updater.py | 4 +- module/config/i18n/en-US.json | 84 ++++++++++++++++----------------- module/config/i18n/ja-JP.json | 84 ++++++++++++++++----------------- module/config/i18n/zh-CN.json | 84 ++++++++++++++++----------------- module/config/i18n/zh-TW.json | 84 ++++++++++++++++----------------- module/server_checker.py | 2 +- 7 files changed, 174 insertions(+), 172 deletions(-) diff --git a/alas.py b/alas.py index fa93f7e75..628076e25 100644 --- a/alas.py +++ b/alas.py @@ -7,6 +7,7 @@ from datetime import datetime, timedelta import inflection from cached_property import cached_property +from module.base.resource import del_cached_property from module.config.config import AzurLaneConfig, TaskEnd from module.config.config_updater import ConfigUpdater from module.config.utils import deep_get, deep_set @@ -425,8 +426,7 @@ class AzurLaneAutoScript: # Sometimes, config won't be updated due to blocking # even though it has been changed # So update it once recovered - if 'config' in self.__dict__: - del self.__dict__['config'] + del_cached_property(self, 'config') logger.info('Server or network is recovered. Restart game client') self.run('restart') diff --git a/module/config/config_updater.py b/module/config/config_updater.py index e5d002d02..0380e5e49 100644 --- a/module/config/config_updater.py +++ b/module/config/config_updater.py @@ -286,7 +286,9 @@ class ConfigGenerator: for server, _list in VALID_SERVER_LIST.items(): for index in range(len(_list)): path = ['Emulator', 'ServerName', f'{server}-{index}'] - deep_set(new, keys=path, value=_list[index]) + prefix = server.split('_')[0].upper() + prefix = '国服' if prefix == 'CN' else prefix + deep_set(new, keys=path, value=f'[{prefix}] {_list[index]}') # GUI i18n for path, _ in deep_iter(self.gui, depth=2): group, key = path diff --git a/module/config/i18n/en-US.json b/module/config/i18n/en-US.json index e3413b44e..4b2320188 100644 --- a/module/config/i18n/en-US.json +++ b/module/config/i18n/en-US.json @@ -303,48 +303,48 @@ "name": "Server in Game Client", "help": "Select the server where you are in the game to enable server status detection\nScript will hang up when server is being maintained or network is broken", "disabled": "disabled", - "cn_android-0": "莱茵演习", - "cn_android-1": "巴巴罗萨", - "cn_android-2": "霸王行动", - "cn_android-3": "冰山行动", - "cn_android-4": "彩虹计划", - "cn_android-5": "发电机计划", - "cn_android-6": "瞭望台行动", - "cn_android-7": "十字路口行动", - "cn_android-8": "朱诺行动", - "cn_android-9": "杜立特空袭", - "cn_android-10": "地狱犬行动", - "cn_android-11": "开罗宣言", - "cn_android-12": "奥林匹克行动", - "cn_android-13": "小王冠行动", - "cn_android-14": "波茨坦公告", - "cn_android-15": "白色方案", - "cn_android-16": "瓦尔基里行动", - "cn_android-17": "曼哈顿计划", - "cn_android-18": "八月风暴", - "cn_android-19": "秋季旅行", - "cn_android-20": "水星行动", - "cn_android-21": "莱茵河卫兵", - "cn_ios-0": "夏威夷", - "cn_ios-1": "珊瑚海", - "cn_ios-2": "中途岛", - "cn_ios-3": "铁底湾", - "cn_ios-4": "所罗门", - "cn_ios-5": "马里亚纳", - "cn_ios-6": "莱特湾", - "cn_ios-7": "硫磺岛", - "cn_ios-8": "冲绳岛", - "cn_ios-9": "阿留申群岛", - "cn_ios-10": "马耳他", - "cn_channel-0": "皇家巡游", - "cn_channel-1": "大西洋宪章", - "cn_channel-2": "十字军行动", - "cn_channel-3": "龙骑兵行动", - "en-0": "Avrora", - "en-1": "Lexington", - "en-2": "Sandy", - "en-3": "Washington", - "en-4": "Amagi" + "cn_android-0": "[国服] 莱茵演习", + "cn_android-1": "[国服] 巴巴罗萨", + "cn_android-2": "[国服] 霸王行动", + "cn_android-3": "[国服] 冰山行动", + "cn_android-4": "[国服] 彩虹计划", + "cn_android-5": "[国服] 发电机计划", + "cn_android-6": "[国服] 瞭望台行动", + "cn_android-7": "[国服] 十字路口行动", + "cn_android-8": "[国服] 朱诺行动", + "cn_android-9": "[国服] 杜立特空袭", + "cn_android-10": "[国服] 地狱犬行动", + "cn_android-11": "[国服] 开罗宣言", + "cn_android-12": "[国服] 奥林匹克行动", + "cn_android-13": "[国服] 小王冠行动", + "cn_android-14": "[国服] 波茨坦公告", + "cn_android-15": "[国服] 白色方案", + "cn_android-16": "[国服] 瓦尔基里行动", + "cn_android-17": "[国服] 曼哈顿计划", + "cn_android-18": "[国服] 八月风暴", + "cn_android-19": "[国服] 秋季旅行", + "cn_android-20": "[国服] 水星行动", + "cn_android-21": "[国服] 莱茵河卫兵", + "cn_ios-0": "[国服] 夏威夷", + "cn_ios-1": "[国服] 珊瑚海", + "cn_ios-2": "[国服] 中途岛", + "cn_ios-3": "[国服] 铁底湾", + "cn_ios-4": "[国服] 所罗门", + "cn_ios-5": "[国服] 马里亚纳", + "cn_ios-6": "[国服] 莱特湾", + "cn_ios-7": "[国服] 硫磺岛", + "cn_ios-8": "[国服] 冲绳岛", + "cn_ios-9": "[国服] 阿留申群岛", + "cn_ios-10": "[国服] 马耳他", + "cn_channel-0": "[国服] 皇家巡游", + "cn_channel-1": "[国服] 大西洋宪章", + "cn_channel-2": "[国服] 十字军行动", + "cn_channel-3": "[国服] 龙骑兵行动", + "en-0": "[EN] Avrora", + "en-1": "[EN] Lexington", + "en-2": "[EN] Sandy", + "en-3": "[EN] Washington", + "en-4": "[EN] Amagi" }, "ScreenshotMethod": { "name": "Screenshot Method", diff --git a/module/config/i18n/ja-JP.json b/module/config/i18n/ja-JP.json index ec3c67184..515280456 100644 --- a/module/config/i18n/ja-JP.json +++ b/module/config/i18n/ja-JP.json @@ -303,48 +303,48 @@ "name": "Emulator.ServerName.name", "help": "Emulator.ServerName.help", "disabled": "disabled", - "cn_android-0": "莱茵演习", - "cn_android-1": "巴巴罗萨", - "cn_android-2": "霸王行动", - "cn_android-3": "冰山行动", - "cn_android-4": "彩虹计划", - "cn_android-5": "发电机计划", - "cn_android-6": "瞭望台行动", - "cn_android-7": "十字路口行动", - "cn_android-8": "朱诺行动", - "cn_android-9": "杜立特空袭", - "cn_android-10": "地狱犬行动", - "cn_android-11": "开罗宣言", - "cn_android-12": "奥林匹克行动", - "cn_android-13": "小王冠行动", - "cn_android-14": "波茨坦公告", - "cn_android-15": "白色方案", - "cn_android-16": "瓦尔基里行动", - "cn_android-17": "曼哈顿计划", - "cn_android-18": "八月风暴", - "cn_android-19": "秋季旅行", - "cn_android-20": "水星行动", - "cn_android-21": "莱茵河卫兵", - "cn_ios-0": "夏威夷", - "cn_ios-1": "珊瑚海", - "cn_ios-2": "中途岛", - "cn_ios-3": "铁底湾", - "cn_ios-4": "所罗门", - "cn_ios-5": "马里亚纳", - "cn_ios-6": "莱特湾", - "cn_ios-7": "硫磺岛", - "cn_ios-8": "冲绳岛", - "cn_ios-9": "阿留申群岛", - "cn_ios-10": "马耳他", - "cn_channel-0": "皇家巡游", - "cn_channel-1": "大西洋宪章", - "cn_channel-2": "十字军行动", - "cn_channel-3": "龙骑兵行动", - "en-0": "Avrora", - "en-1": "Lexington", - "en-2": "Sandy", - "en-3": "Washington", - "en-4": "Amagi" + "cn_android-0": "[国服] 莱茵演习", + "cn_android-1": "[国服] 巴巴罗萨", + "cn_android-2": "[国服] 霸王行动", + "cn_android-3": "[国服] 冰山行动", + "cn_android-4": "[国服] 彩虹计划", + "cn_android-5": "[国服] 发电机计划", + "cn_android-6": "[国服] 瞭望台行动", + "cn_android-7": "[国服] 十字路口行动", + "cn_android-8": "[国服] 朱诺行动", + "cn_android-9": "[国服] 杜立特空袭", + "cn_android-10": "[国服] 地狱犬行动", + "cn_android-11": "[国服] 开罗宣言", + "cn_android-12": "[国服] 奥林匹克行动", + "cn_android-13": "[国服] 小王冠行动", + "cn_android-14": "[国服] 波茨坦公告", + "cn_android-15": "[国服] 白色方案", + "cn_android-16": "[国服] 瓦尔基里行动", + "cn_android-17": "[国服] 曼哈顿计划", + "cn_android-18": "[国服] 八月风暴", + "cn_android-19": "[国服] 秋季旅行", + "cn_android-20": "[国服] 水星行动", + "cn_android-21": "[国服] 莱茵河卫兵", + "cn_ios-0": "[国服] 夏威夷", + "cn_ios-1": "[国服] 珊瑚海", + "cn_ios-2": "[国服] 中途岛", + "cn_ios-3": "[国服] 铁底湾", + "cn_ios-4": "[国服] 所罗门", + "cn_ios-5": "[国服] 马里亚纳", + "cn_ios-6": "[国服] 莱特湾", + "cn_ios-7": "[国服] 硫磺岛", + "cn_ios-8": "[国服] 冲绳岛", + "cn_ios-9": "[国服] 阿留申群岛", + "cn_ios-10": "[国服] 马耳他", + "cn_channel-0": "[国服] 皇家巡游", + "cn_channel-1": "[国服] 大西洋宪章", + "cn_channel-2": "[国服] 十字军行动", + "cn_channel-3": "[国服] 龙骑兵行动", + "en-0": "[EN] Avrora", + "en-1": "[EN] Lexington", + "en-2": "[EN] Sandy", + "en-3": "[EN] Washington", + "en-4": "[EN] Amagi" }, "ScreenshotMethod": { "name": "Emulator.ScreenshotMethod.name", diff --git a/module/config/i18n/zh-CN.json b/module/config/i18n/zh-CN.json index d459dd5f4..0e62f4287 100644 --- a/module/config/i18n/zh-CN.json +++ b/module/config/i18n/zh-CN.json @@ -303,48 +303,48 @@ "name": "游戏内服务器", "help": "选择游戏内所在的服务器以启用服务器状态检测\n当服务器维护或网络不可用时挂起直到恢复", "disabled": "disabled", - "cn_android-0": "莱茵演习", - "cn_android-1": "巴巴罗萨", - "cn_android-2": "霸王行动", - "cn_android-3": "冰山行动", - "cn_android-4": "彩虹计划", - "cn_android-5": "发电机计划", - "cn_android-6": "瞭望台行动", - "cn_android-7": "十字路口行动", - "cn_android-8": "朱诺行动", - "cn_android-9": "杜立特空袭", - "cn_android-10": "地狱犬行动", - "cn_android-11": "开罗宣言", - "cn_android-12": "奥林匹克行动", - "cn_android-13": "小王冠行动", - "cn_android-14": "波茨坦公告", - "cn_android-15": "白色方案", - "cn_android-16": "瓦尔基里行动", - "cn_android-17": "曼哈顿计划", - "cn_android-18": "八月风暴", - "cn_android-19": "秋季旅行", - "cn_android-20": "水星行动", - "cn_android-21": "莱茵河卫兵", - "cn_ios-0": "夏威夷", - "cn_ios-1": "珊瑚海", - "cn_ios-2": "中途岛", - "cn_ios-3": "铁底湾", - "cn_ios-4": "所罗门", - "cn_ios-5": "马里亚纳", - "cn_ios-6": "莱特湾", - "cn_ios-7": "硫磺岛", - "cn_ios-8": "冲绳岛", - "cn_ios-9": "阿留申群岛", - "cn_ios-10": "马耳他", - "cn_channel-0": "皇家巡游", - "cn_channel-1": "大西洋宪章", - "cn_channel-2": "十字军行动", - "cn_channel-3": "龙骑兵行动", - "en-0": "Avrora", - "en-1": "Lexington", - "en-2": "Sandy", - "en-3": "Washington", - "en-4": "Amagi" + "cn_android-0": "[国服] 莱茵演习", + "cn_android-1": "[国服] 巴巴罗萨", + "cn_android-2": "[国服] 霸王行动", + "cn_android-3": "[国服] 冰山行动", + "cn_android-4": "[国服] 彩虹计划", + "cn_android-5": "[国服] 发电机计划", + "cn_android-6": "[国服] 瞭望台行动", + "cn_android-7": "[国服] 十字路口行动", + "cn_android-8": "[国服] 朱诺行动", + "cn_android-9": "[国服] 杜立特空袭", + "cn_android-10": "[国服] 地狱犬行动", + "cn_android-11": "[国服] 开罗宣言", + "cn_android-12": "[国服] 奥林匹克行动", + "cn_android-13": "[国服] 小王冠行动", + "cn_android-14": "[国服] 波茨坦公告", + "cn_android-15": "[国服] 白色方案", + "cn_android-16": "[国服] 瓦尔基里行动", + "cn_android-17": "[国服] 曼哈顿计划", + "cn_android-18": "[国服] 八月风暴", + "cn_android-19": "[国服] 秋季旅行", + "cn_android-20": "[国服] 水星行动", + "cn_android-21": "[国服] 莱茵河卫兵", + "cn_ios-0": "[国服] 夏威夷", + "cn_ios-1": "[国服] 珊瑚海", + "cn_ios-2": "[国服] 中途岛", + "cn_ios-3": "[国服] 铁底湾", + "cn_ios-4": "[国服] 所罗门", + "cn_ios-5": "[国服] 马里亚纳", + "cn_ios-6": "[国服] 莱特湾", + "cn_ios-7": "[国服] 硫磺岛", + "cn_ios-8": "[国服] 冲绳岛", + "cn_ios-9": "[国服] 阿留申群岛", + "cn_ios-10": "[国服] 马耳他", + "cn_channel-0": "[国服] 皇家巡游", + "cn_channel-1": "[国服] 大西洋宪章", + "cn_channel-2": "[国服] 十字军行动", + "cn_channel-3": "[国服] 龙骑兵行动", + "en-0": "[EN] Avrora", + "en-1": "[EN] Lexington", + "en-2": "[EN] Sandy", + "en-3": "[EN] Washington", + "en-4": "[EN] Amagi" }, "ScreenshotMethod": { "name": "模拟器截图方案", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index 73ee4ba4c..2936024dd 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -303,48 +303,48 @@ "name": "遊戲内伺服器", "help": "選擇遊戲內所在的伺服器以啓用伺服器狀態檢測\n當伺服器維護或網路不可用時挂起直到恢複", "disabled": "disabled", - "cn_android-0": "莱茵演习", - "cn_android-1": "巴巴罗萨", - "cn_android-2": "霸王行动", - "cn_android-3": "冰山行动", - "cn_android-4": "彩虹计划", - "cn_android-5": "发电机计划", - "cn_android-6": "瞭望台行动", - "cn_android-7": "十字路口行动", - "cn_android-8": "朱诺行动", - "cn_android-9": "杜立特空袭", - "cn_android-10": "地狱犬行动", - "cn_android-11": "开罗宣言", - "cn_android-12": "奥林匹克行动", - "cn_android-13": "小王冠行动", - "cn_android-14": "波茨坦公告", - "cn_android-15": "白色方案", - "cn_android-16": "瓦尔基里行动", - "cn_android-17": "曼哈顿计划", - "cn_android-18": "八月风暴", - "cn_android-19": "秋季旅行", - "cn_android-20": "水星行动", - "cn_android-21": "莱茵河卫兵", - "cn_ios-0": "夏威夷", - "cn_ios-1": "珊瑚海", - "cn_ios-2": "中途岛", - "cn_ios-3": "铁底湾", - "cn_ios-4": "所罗门", - "cn_ios-5": "马里亚纳", - "cn_ios-6": "莱特湾", - "cn_ios-7": "硫磺岛", - "cn_ios-8": "冲绳岛", - "cn_ios-9": "阿留申群岛", - "cn_ios-10": "马耳他", - "cn_channel-0": "皇家巡游", - "cn_channel-1": "大西洋宪章", - "cn_channel-2": "十字军行动", - "cn_channel-3": "龙骑兵行动", - "en-0": "Avrora", - "en-1": "Lexington", - "en-2": "Sandy", - "en-3": "Washington", - "en-4": "Amagi" + "cn_android-0": "[国服] 莱茵演习", + "cn_android-1": "[国服] 巴巴罗萨", + "cn_android-2": "[国服] 霸王行动", + "cn_android-3": "[国服] 冰山行动", + "cn_android-4": "[国服] 彩虹计划", + "cn_android-5": "[国服] 发电机计划", + "cn_android-6": "[国服] 瞭望台行动", + "cn_android-7": "[国服] 十字路口行动", + "cn_android-8": "[国服] 朱诺行动", + "cn_android-9": "[国服] 杜立特空袭", + "cn_android-10": "[国服] 地狱犬行动", + "cn_android-11": "[国服] 开罗宣言", + "cn_android-12": "[国服] 奥林匹克行动", + "cn_android-13": "[国服] 小王冠行动", + "cn_android-14": "[国服] 波茨坦公告", + "cn_android-15": "[国服] 白色方案", + "cn_android-16": "[国服] 瓦尔基里行动", + "cn_android-17": "[国服] 曼哈顿计划", + "cn_android-18": "[国服] 八月风暴", + "cn_android-19": "[国服] 秋季旅行", + "cn_android-20": "[国服] 水星行动", + "cn_android-21": "[国服] 莱茵河卫兵", + "cn_ios-0": "[国服] 夏威夷", + "cn_ios-1": "[国服] 珊瑚海", + "cn_ios-2": "[国服] 中途岛", + "cn_ios-3": "[国服] 铁底湾", + "cn_ios-4": "[国服] 所罗门", + "cn_ios-5": "[国服] 马里亚纳", + "cn_ios-6": "[国服] 莱特湾", + "cn_ios-7": "[国服] 硫磺岛", + "cn_ios-8": "[国服] 冲绳岛", + "cn_ios-9": "[国服] 阿留申群岛", + "cn_ios-10": "[国服] 马耳他", + "cn_channel-0": "[国服] 皇家巡游", + "cn_channel-1": "[国服] 大西洋宪章", + "cn_channel-2": "[国服] 十字军行动", + "cn_channel-3": "[国服] 龙骑兵行动", + "en-0": "[EN] Avrora", + "en-1": "[EN] Lexington", + "en-2": "[EN] Sandy", + "en-3": "[EN] Washington", + "en-4": "[EN] Amagi" }, "ServerPlatform": { "name": "伺服器平台", diff --git a/module/server_checker.py b/module/server_checker.py index d6e0df9dc..b6ab04fa2 100644 --- a/module/server_checker.py +++ b/module/server_checker.py @@ -11,7 +11,7 @@ from module.logger import logger class ServerChecker: def __init__(self, server: str) -> None: - self._base: str = 'http://sc.shiratama.cn:20002' + self._base: str = 'http://sc.shiratama.cn' self._api: dict = { 'get_state': '/server/get_state', # post 'get_all_state': '/server/get_all_state', # post From d734bf0f001905c9d0e670a0375163ce1ee1462d Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Tue, 2 Aug 2022 20:55:38 +0800 Subject: [PATCH 08/15] Fix: receive_6th_research timeout --- module/research/research.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/research/research.py b/module/research/research.py index 56fed8032..3c1e990bb 100644 --- a/module/research/research.py +++ b/module/research/research.py @@ -476,6 +476,8 @@ class RewardResearch(ResearchSelector, ResearchQueue): break if 'unknown' in status: continue + if sum([s == 'detail' for s in status]) == 5: + break return True From e02a15f28106ea117571fb2cc7c22b5177776b73 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:32:16 +0800 Subject: [PATCH 09/15] Fix: Handle uncollected zone exploration rewards (#1478) --- module/os/globe_operation.py | 7 +++++-- module/os/map.py | 20 +++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/module/os/globe_operation.py b/module/os/globe_operation.py index bc5c41b7d..dbc9600d8 100644 --- a/module/os/globe_operation.py +++ b/module/os/globe_operation.py @@ -1,6 +1,5 @@ from module.base.timer import Timer from module.base.utils import * -from module.exception import GameTooManyClickError from module.logger import logger from module.os.assets import * from module.os_handler.action_point import ActionPointHandler @@ -16,6 +15,10 @@ class OSExploreError(Exception): pass +class RewardUncollectedError(Exception): + pass + + class GlobeOperation(ActionPointHandler, MapEventHandler): def is_in_globe(self): return self.appear(GLOBE_GOTO_MAP, offset=(20, 20)) @@ -295,7 +298,7 @@ class GlobeOperation(ActionPointHandler, MapEventHandler): # When there's zone exploration reward, AL just don't let you go. logger.warning('Unable to goto globe, ' 'there might be uncollected zone exploration rewards preventing exit') - raise GameTooManyClickError(f'Too many click for a button: {MAP_GOTO_GLOBE}') + raise RewardUncollectedError continue if self.handle_map_event(): continue diff --git a/module/os/map.py b/module/os/map.py index 385477d8c..b355f22a7 100644 --- a/module/os/map.py +++ b/module/os/map.py @@ -4,13 +4,14 @@ from module.base.button import Button from module.base.timer import Timer from module.config.utils import get_os_reset_remain from module.exception import CampaignEnd, RequestHumanTakeover +from module.exception import GameTooManyClickError from module.exception import MapWalkError, ScriptError from module.logger import logger from module.map.map import Map from module.os.assets import FLEET_EMP_DEBUFF from module.os.fleet import OSFleet from module.os.globe_camera import GlobeCamera -from module.ui.assets import OS_CHECK +from module.os.globe_operation import RewardUncollectedError from module.ui.ui import page_os FLEET_LOW_RESOLVE = Button( @@ -148,6 +149,23 @@ class OSMap(OSFleet, Map, GlobeCamera): # self.map_init() return True + def os_map_goto_globe(self, *args, **kwargs): + """ + Wraps os_map_goto_globe() + When zone has uncollected exploration rewards preventing exit, + run auto search and goto globe again + """ + for _ in range(3): + try: + super().os_map_goto_globe(*args, **kwargs) + return + except RewardUncollectedError: + self.run_auto_search() + continue + + logger.error('Failed to solve uncollected rewards') + raise GameTooManyClickError + def port_goto(self): """ Wraps `port_goto()`, handle walk_out_of_step From 66870333773f3a3d6ba8df97be34772af1da6d29 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Wed, 3 Aug 2022 00:45:44 +0800 Subject: [PATCH 10/15] Fix: Story skip interrupts auto search (#1478) --- module/handler/info_handler.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/module/handler/info_handler.py b/module/handler/info_handler.py index 5483b2c5a..52ffd5df3 100644 --- a/module/handler/info_handler.py +++ b/module/handler/info_handler.py @@ -228,6 +228,7 @@ class InfoHandler(ModuleBase): story_popup_timeout = Timer(10, count=20) map_has_clear_mode = False # Will be override in fast_forward.py + _story_confirm = Timer(0.5, count=1) # Area to detect the options, should include at least 3 options. _story_option_area = (730, 188, 1140, 480) # Background color of the left part of the option. @@ -307,11 +308,18 @@ class InfoHandler(ModuleBase): self._story_option_record = options_count self._story_option_confirm.reset() if self.appear(STORY_SKIP, offset=(20, 20), interval=2): - if drop: - drop.handle_add(self, before=2) - self.device.click(STORY_SKIP) - self.story_popup_timeout.reset() - return True + # Confirm it's story + # When story play speed is Very Fast, Alas clicked story skip but story disappeared + # This click will interrupt auto search + if self._story_confirm.reached(): + if drop: + drop.handle_add(self, before=2) + self.device.click(STORY_SKIP) + self._story_confirm.reset() + self.story_popup_timeout.reset() + return True + else: + self._story_confirm.reset() if self.appear_then_click(GAME_TIPS, offset=(20, 20), interval=2): self.story_popup_timeout.reset() return True From 428cf48b252e372b24ca08cd610b30186feb8804 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Thu, 4 Aug 2022 18:54:33 +0800 Subject: [PATCH 11/15] Fix: Confirm to submit items, in siren scanning devices --- module/os/fleet.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/module/os/fleet.py b/module/os/fleet.py index 7a7d10fd3..a47892d36 100644 --- a/module/os/fleet.py +++ b/module/os/fleet.py @@ -286,6 +286,10 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh): raise MapWalkError('walk_out_of_step') else: continue + if self.handle_popup_confirm(): + # Confirm to submit items, in siren scanning devices + confirm_timer.reset() + continue # Accident click if self.is_in_globe(): From 532d3b937fd2d7182484a76a7b6eb3910a52b73c Mon Sep 17 00:00:00 2001 From: Zorachristine Date: Thu, 4 Aug 2022 19:54:49 +0800 Subject: [PATCH 12/15] Upd: [TW] Skybound Oratorio Rerun --- campaign/Readme.md | 3 +- module/config/argument/args.json | 98 ++++++++------------------------ module/config/i18n/zh-TW.json | 60 +------------------ 3 files changed, 29 insertions(+), 132 deletions(-) diff --git a/campaign/Readme.md b/campaign/Readme.md index 3638a94f9..f064802f5 100644 --- a/campaign/Readme.md +++ b/campaign/Readme.md @@ -103,4 +103,5 @@ To add a new event, add a new row in here, and run `python -m dev_tools.event_ex | 20220630 | raid 20220630 | Angel of Iris | 来自鸢尾的天使 | Angel of Iris | アイリスの天使 | - | | 20220714 | event 20201029 cn | Universe in Unison | - | - | - | 激唱的UNIVERSE | | 20220714 | event 20200917 cn | Dreamwaker's Butterfly | 复刻蝶海梦花 | Dreamwaker's Butterfly Rerun | 刹那觀る胡蝶の夢(復刻) | - | -| 20220728 | event 20220728 cn | Aquilifer's Ballade | 雄鹰的叙事歌 | Aquilifer's Ballade | 鋼鷲の冒険譚 | - | \ No newline at end of file +| 20220728 | event 20220728 cn | Aquilifer's Ballade | 雄鹰的叙事歌 | Aquilifer's Ballade | 鋼鷲の冒険譚 | - | +| 20220804 | event 20211028 cn | Skybound Oratorio Rerun | - | - | - | 復刻穹頂下的聖詠曲 | \ No newline at end of file diff --git a/module/config/argument/args.json b/module/config/argument/args.json index f5d263a8f..c5de44ef6 100644 --- a/module/config/argument/args.json +++ b/module/config/argument/args.json @@ -26,58 +26,10 @@ "com.bilibili.blhx.uc", "com.bilibili.blhx.mzw", "com.yiwu.blhx.yx15", + "com.bilibili.blhx.m4399", "com.hkmanjuu.azurlane.gp.mc" ] }, - "ServerName": { - "type": "select", - "value": "disabled", - "option": [ - "disabled", - "cn_android-0", - "cn_android-1", - "cn_android-2", - "cn_android-3", - "cn_android-4", - "cn_android-5", - "cn_android-6", - "cn_android-7", - "cn_android-8", - "cn_android-9", - "cn_android-10", - "cn_android-11", - "cn_android-12", - "cn_android-13", - "cn_android-14", - "cn_android-15", - "cn_android-16", - "cn_android-17", - "cn_android-18", - "cn_android-19", - "cn_android-20", - "cn_android-21", - "cn_ios-0", - "cn_ios-1", - "cn_ios-2", - "cn_ios-3", - "cn_ios-4", - "cn_ios-5", - "cn_ios-6", - "cn_ios-7", - "cn_ios-8", - "cn_ios-9", - "cn_ios-10", - "cn_channel-0", - "cn_channel-1", - "cn_channel-2", - "cn_channel-3", - "en-0", - "en-1", - "en-2", - "en-3", - "en-4" - ] - }, "ScreenshotMethod": { "type": "select", "value": "ADB", @@ -1442,6 +1394,7 @@ "value": "campaign_main", "option": [ "campaign_main", + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -1464,7 +1417,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -1493,10 +1445,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -1830,6 +1782,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -1852,7 +1805,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -1881,10 +1833,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -2239,6 +2191,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -2261,7 +2214,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -2290,10 +2242,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -2658,6 +2610,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -2680,7 +2633,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -2709,10 +2661,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -3077,6 +3029,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -3099,7 +3052,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -3128,10 +3080,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -3496,6 +3448,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -3518,7 +3471,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -3547,10 +3499,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -3915,6 +3867,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -3937,7 +3890,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -3966,10 +3918,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", @@ -4324,6 +4276,7 @@ "type": "select", "value": "campaign_main", "option": [ + "event_20211028_cn", "event_20220728_cn", "event_20200917_cn", "event_20201029_cn", @@ -4346,7 +4299,6 @@ "event_20211125_cn", "event_20211111_cn", "event_20211028_tw", - "event_20211028_cn", "event_20210916_cn", "event_20210722_cn", "event_20210819_cn", @@ -4375,10 +4327,10 @@ "event_20200326_cn", "event_20200227_cn" ], + "tw": "event_20211028_cn", "cn": "event_20220728_cn", "en": "event_20220728_cn", - "jp": "event_20220728_cn", - "tw": "event_20201029_cn" + "jp": "event_20220728_cn" }, "Mode": { "type": "hide", diff --git a/module/config/i18n/zh-TW.json b/module/config/i18n/zh-TW.json index d34d2e1c0..7bef11d80 100644 --- a/module/config/i18n/zh-TW.json +++ b/module/config/i18n/zh-TW.json @@ -305,65 +305,9 @@ "com.bilibili.blhx.uc": "國服 com.bilibili.blhx.uc", "com.bilibili.blhx.mzw": "國服 com.bilibili.blhx.mzw", "com.yiwu.blhx.yx15": "國服 com.yiwu.blhx.yx15", + "com.bilibili.blhx.m4399": "國服 com.bilibili.blhx.m4399", "com.hkmanjuu.azurlane.gp.mc": "台服 MyCard渠道服 com.hkmanjuu.azurlane.gp.mc" }, - "ServerName": { - "name": "遊戲内伺服器", - "help": "選擇遊戲內所在的伺服器以啓用伺服器狀態檢測\n當伺服器維護或網路不可用時挂起直到恢複", - "disabled": "disabled", - "cn_android-0": "[国服] 莱茵演习", - "cn_android-1": "[国服] 巴巴罗萨", - "cn_android-2": "[国服] 霸王行动", - "cn_android-3": "[国服] 冰山行动", - "cn_android-4": "[国服] 彩虹计划", - "cn_android-5": "[国服] 发电机计划", - "cn_android-6": "[国服] 瞭望台行动", - "cn_android-7": "[国服] 十字路口行动", - "cn_android-8": "[国服] 朱诺行动", - "cn_android-9": "[国服] 杜立特空袭", - "cn_android-10": "[国服] 地狱犬行动", - "cn_android-11": "[国服] 开罗宣言", - "cn_android-12": "[国服] 奥林匹克行动", - "cn_android-13": "[国服] 小王冠行动", - "cn_android-14": "[国服] 波茨坦公告", - "cn_android-15": "[国服] 白色方案", - "cn_android-16": "[国服] 瓦尔基里行动", - "cn_android-17": "[国服] 曼哈顿计划", - "cn_android-18": "[国服] 八月风暴", - "cn_android-19": "[国服] 秋季旅行", - "cn_android-20": "[国服] 水星行动", - "cn_android-21": "[国服] 莱茵河卫兵", - "cn_ios-0": "[国服] 夏威夷", - "cn_ios-1": "[国服] 珊瑚海", - "cn_ios-2": "[国服] 中途岛", - "cn_ios-3": "[国服] 铁底湾", - "cn_ios-4": "[国服] 所罗门", - "cn_ios-5": "[国服] 马里亚纳", - "cn_ios-6": "[国服] 莱特湾", - "cn_ios-7": "[国服] 硫磺岛", - "cn_ios-8": "[国服] 冲绳岛", - "cn_ios-9": "[国服] 阿留申群岛", - "cn_ios-10": "[国服] 马耳他", - "cn_channel-0": "[国服] 皇家巡游", - "cn_channel-1": "[国服] 大西洋宪章", - "cn_channel-2": "[国服] 十字军行动", - "cn_channel-3": "[国服] 龙骑兵行动", - "en-0": "[EN] Avrora", - "en-1": "[EN] Lexington", - "en-2": "[EN] Sandy", - "en-3": "[EN] Washington", - "en-4": "[EN] Amagi" - }, - "ServerPlatform": { - "name": "伺服器平台", - "help": "", - "disabled": "不使用", - "cn_android": "國服-安卓端", - "cn_ios": "國服-IOS端", - "cn_channel": "國服-渠道服", - "en": "國際服", - "en_channel": "國際服-渠道服" - }, "ScreenshotMethod": { "name": "模擬器截圖方案", "help": "速度: aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB\n運行 工具 - 性能測試 以尋找最快的方案", @@ -562,6 +506,7 @@ "name": "活動名稱", "help": "自動選擇至最新的活動圖", "campaign_main": "主線圖", + "event_20211028_cn": "復刻穹頂下的聖詠曲", "event_20220728_cn": "Aquilifers Ballade", "event_20200917_cn": "蝶海夢花", "event_20201029_cn": "激唱的UNIVERSE", @@ -588,7 +533,6 @@ "event_20211125_cn": "交匯世界的弧光", "event_20211111_cn": "The Flame-Touched Dagger", "event_20211028_tw": "復刻光與影的鳶尾之華", - "event_20211028_cn": "Skybound Oratorio Rerun", "event_20210916_cn": "Upon the Shimmering Blue", "event_20210722_cn": "響徹碧海的偶像歌", "event_20210819_cn": "Microlayer Medley Rerun", From e2a55e1b580b23f72962f32ff84bcfa1927f96e1 Mon Sep 17 00:00:00 2001 From: Zorachristine Date: Thu, 4 Aug 2022 20:01:23 +0800 Subject: [PATCH 13/15] Fix: [TW] DORM_INFO --- assets/tw/ui/DORM_INFO.png | Bin 6576 -> 9721 bytes module/ui/assets.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/tw/ui/DORM_INFO.png b/assets/tw/ui/DORM_INFO.png index 63387b3f4556adb1b29d9750ffa6b878ac6b52ac..e78c4f573d3e1dfbb8f5300e50aad7a25e6ecb2d 100644 GIT binary patch literal 9721 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 literal 6576 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 Date: Thu, 4 Aug 2022 21:10:50 +0800 Subject: [PATCH 14/15] Fix: Loop tries on 2 adjacent fleet mechanism (#1475) --- module/os/map.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/module/os/map.py b/module/os/map.py index b355f22a7..6f06f6a1f 100644 --- a/module/os/map.py +++ b/module/os/map.py @@ -456,8 +456,18 @@ class OSMap(OSFleet, Map, GlobeCamera): break def clear_question(self, drop): + """ + Clear nearly (and 3 grids from above) question marks on radar. + Try 3 times at max to avoid loop tries on 2 adjacent fleet mechanism. + + Args: + drop: + + Returns: + bool: If cleared + """ logger.hr('Clear question', level=2) - while 1: + for _ in range(3): grid = self.radar.predict_question(self.device.image) if grid is None: logger.info('No question mark above current fleet on this radar') @@ -487,6 +497,10 @@ class OSMap(OSFleet, Map, GlobeCamera): logger.warning(f'Arrive question with unexpected result: {result}, expected: {grid.str}') continue + logger.warning('Failed to goto question mark after 5 trail, ' + 'this might be 2 adjacent fleet mechanism, stopped') + return False + def run_auto_search(self, question=True, rescan=None): """ Clear current zone by running auto search. From 821b1b3295cd71d27001b8167bc4a0c321c064e5 Mon Sep 17 00:00:00 2001 From: LmeSzinc <37934724+LmeSzinc@users.noreply.github.com> Date: Thu, 4 Aug 2022 21:39:10 +0800 Subject: [PATCH 15/15] Opt: Check game server maintenance after GUI update event --- alas.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/alas.py b/alas.py index 0a536ddba..c08d300e7 100644 --- a/alas.py +++ b/alas.py @@ -429,6 +429,13 @@ class AzurLaneAutoScript: failure_record = {} while 1: + # Check update event from GUI + if self.stop_event is not None: + if self.stop_event.is_set(): + logger.info("Update event detected") + logger.info(f"Alas [{self.config_name}] exited.") + break + # Check game server maintenance self.checker.wait_until_available() if self.checker.is_recovered(): # There is an accidental bug hard to reproduce @@ -438,15 +445,10 @@ class AzurLaneAutoScript: del_cached_property(self, 'config') logger.info('Server or network is recovered. Restart game client') self.run('restart') - - if self.stop_event is not None: - if self.stop_event.is_set(): - logger.info("Update event detected") - logger.info(f"Alas [{self.config_name}] exited.") - break + # Get task task = self.get_next_task() + # Init device and change server _ = self.device - # Skip first restart if is_first and task == 'Restart': logger.info('Skip task `Restart` at scheduler start')