1
0
mirror of https://gitee.com/sui-feng-cb/AzurLaneAutoScript1 synced 2026-03-27 03:48:21 +08:00

Merge pull request #1260 from LmeSzinc/dev

Bug fix
This commit is contained in:
LmeSzinc
2022-06-26 18:32:11 +08:00
committed by GitHub
51 changed files with 264 additions and 227 deletions

View File

@@ -22,7 +22,6 @@ MAP.weight_data = """
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
""" """
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 2}, {'battle': 0, 'enemy': 2},

View File

@@ -22,7 +22,6 @@ MAP.weight_data = """
90 90 90 90 90 90 90 10 05 90 90 90 90 90 90 90 90 90 10 05 90 90
90 90 90 90 90 25 20 15 90 90 90 90 90 90 90 90 25 20 15 90 90 90
90 90 90 40 35 30 90 90 90 90 90 90 90 90 40 35 30 90 90 90 90 90
""" """
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 3}, {'battle': 0, 'enemy': 3},

View File

@@ -22,7 +22,6 @@ MAP.weight_data = """
20 20 20 10 10 20 20 35 20 20 20 10 10 20 20 35
50 90 90 60 60 90 90 90 50 90 90 60 60 90 90 90
90 90 90 70 80 90 90 90 90 90 90 70 80 90 90 90
""" """
MAP.spawn_data = [ MAP.spawn_data = [
{'battle': 0, 'enemy': 3}, {'battle': 0, 'enemy': 3},

View File

@@ -14,7 +14,6 @@ MAP.map_data = '''
++ ++ ++ -- -- -- -- ++ -- ++ ++ ++ -- -- -- -- ++ --
MB -- ME ME -- ++ -- ME -- MB -- ME ME -- ++ -- ME --
-- ME -- -- SP ++ -- -- -- -- ME -- -- SP ++ -- -- --
''' '''
MAP.weight_data = ''' MAP.weight_data = '''
10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10

View File

@@ -1,5 +1,6 @@
import os import os
import re import re
from deploy.logger import logger
BASE_FOLDER = './deploy/AidLux' BASE_FOLDER = './deploy/AidLux'
@@ -41,10 +42,10 @@ def write_file(file, data):
def aidlux_requirements_generate(requirements_in='requirements-in.txt'): def aidlux_requirements_generate(requirements_in='requirements-in.txt'):
print('aidlux_requirements_generate') logger.info('aidlux_requirements_generate')
requirements = read_file(requirements_in) requirements = read_file(requirements_in)
for aidlux in iter_version(): for aidlux in iter_version():
print(f'Generate requirements for AidLux {aidlux}') logger.info(f'Generate requirements for AidLux {aidlux}')
pre_installed = read_file(os.path.join(BASE_FOLDER, f'./{aidlux}/pre-installed.txt')) pre_installed = read_file(os.path.join(BASE_FOLDER, f'./{aidlux}/pre-installed.txt'))
new = {} new = {}
for name, version in requirements.items(): for name, version in requirements.items():

View File

@@ -2,11 +2,12 @@ import logging
from deploy.config import DeployConfig from deploy.config import DeployConfig
from deploy.emulator import EmulatorConnect from deploy.emulator import EmulatorConnect
from deploy.logger import logger
from deploy.utils import * from deploy.utils import *
def show_fix_tip(module): def show_fix_tip(module):
print(f""" logger.info(f"""
To fix this: To fix this:
1. Open console.bat 1. Open console.bat
2. Execute the following commands: 2. Execute the following commands:
@@ -22,18 +23,18 @@ class AdbManager(DeployConfig):
return self.filepath('AdbExecutable') return self.filepath('AdbExecutable')
def adb_install(self): def adb_install(self):
hr0('Start ADB service') logger.hr('Start ADB service', 0)
emulator = EmulatorConnect(adb=self.adb) emulator = EmulatorConnect(adb=self.adb)
if self.ReplaceAdb: if self.ReplaceAdb:
hr1('Replace ADB') logger.hr('Replace ADB', 1)
emulator.adb_replace() emulator.adb_replace()
elif self.AutoConnect: elif self.AutoConnect:
hr1('ADB Connect') logger.hr('ADB Connect', 1)
emulator.brute_force_connect() emulator.brute_force_connect()
if self.InstallUiautomator2: if self.InstallUiautomator2:
hr1('Uiautomator2 Init') logger.hr('Uiautomator2 Init', 1)
try: try:
import adbutils import adbutils
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
@@ -57,8 +58,8 @@ class AdbManager(DeployConfig):
try: try:
init.install() init.install()
except AssertionError: except AssertionError:
print(f'AssertionError when installing uiautomator2 on device {device.serial}') logger.info(f'AssertionError when installing uiautomator2 on device {device.serial}')
print('If you are using BlueStacks or LD player or WSA, ' logger.info('If you are using BlueStacks or LD player or WSA, '
'please enable ADB in the settings of your emulator') 'please enable ADB in the settings of your emulator')
exit(1) exit(1)
init._device.shell(["rm", "/data/local/tmp/minicap"]) init._device.shell(["rm", "/data/local/tmp/minicap"])

View File

@@ -1,4 +1,5 @@
from deploy.config import DeployConfig from deploy.config import DeployConfig
from deploy.logger import logger
from deploy.utils import * from deploy.utils import *
@@ -25,7 +26,7 @@ class AlasManager(DeployConfig):
try: try:
from win32com.client import GetObject from win32com.client import GetObject
except ModuleNotFoundError: except ModuleNotFoundError:
print('pywin32 not installed, skip') logger.info('pywin32 not installed, skip')
return False return False
try: try:
@@ -44,7 +45,7 @@ class AlasManager(DeployConfig):
except Exception as e: except Exception as e:
# Possible exception # Possible exception
# pywintypes.com_error: (-2147217392, 'OLE error 0x80041010', None, None) # pywintypes.com_error: (-2147217392, 'OLE error 0x80041010', None, None)
print(str(e)) logger.info(str(e))
return False return False
def kill_by_name(self, name): def kill_by_name(self, name):
@@ -52,12 +53,12 @@ class AlasManager(DeployConfig):
Args: Args:
name (str): Process name name (str): Process name
""" """
hr1(f'Kill {name}') logger.hr(f'Kill {name}', 1)
for row in self.iter_process_by_name(name): for row in self.iter_process_by_name(name):
print(' '.join(map(str, row))) logger.info(' '.join(map(str, row)))
self.execute(f'taskkill /f /pid {row[2]}', allow_failure=True) self.execute(f'taskkill /f /pid {row[2]}', allow_failure=True, output=False)
def alas_kill(self): def alas_kill(self):
hr0(f'Kill existing Alas') logger.hr(f'Kill existing Alas', 0)
self.kill_by_name('alas.exe') self.kill_by_name('alas.exe')
self.kill_by_name('python.exe') self.kill_by_name('python.exe')

View File

@@ -2,6 +2,7 @@ import filecmp
import shutil import shutil
from deploy.config import DeployConfig from deploy.config import DeployConfig
from deploy.logger import logger
from deploy.utils import * from deploy.utils import *
@@ -17,36 +18,36 @@ class AppManager(DeployConfig):
bool: If updated. bool: If updated.
""" """
source = os.path.abspath(os.path.join(folder, path)) source = os.path.abspath(os.path.join(folder, path))
print(f'Old file: {source}') logger.info(f'Old file: {source}')
try: try:
import alas_webapp import alas_webapp
except ImportError: except ImportError:
print(f'Dependency alas_webapp not exists, skip updating') logger.info(f'Dependency alas_webapp not exists, skip updating')
return False return False
update = alas_webapp.app_file() update = alas_webapp.app_file()
print(f'New version: {alas_webapp.__version__}') logger.info(f'New version: {alas_webapp.__version__}')
print(f'New file: {update}') logger.info(f'New file: {update}')
if os.path.exists(source): if os.path.exists(source):
if filecmp.cmp(source, update, shallow=True): if filecmp.cmp(source, update, shallow=True):
print('app.asar is already up to date') logger.info('app.asar is already up to date')
return False return False
else: else:
print(f'Copy {update} -----> {source}') logger.info(f'Copy {update} -----> {source}')
os.remove(source) os.remove(source)
shutil.copy(update, source) shutil.copy(update, source)
return True return True
else: else:
print(f'{source} not exists, skip updating') logger.info(f'{source} not exists, skip updating')
return False return False
def app_update(self): def app_update(self):
hr0(f'Update app.asar') logger.hr(f'Update app.asar', 0)
if not self.AutoUpdate: if not self.AutoUpdate:
print('AutoUpdate is disabled, skip') logger.info('AutoUpdate is disabled, skip')
return False return False
return self.app_asar_replace(os.getcwd()) return self.app_asar_replace(os.getcwd())

View File

@@ -1,6 +1,7 @@
import copy import copy
from typing import Optional, Union from typing import Optional, Union
from deploy.logger import logger
from deploy.utils import * from deploy.utils import *
@@ -66,15 +67,15 @@ class DeployConfig(ConfigModel):
self.show_config() self.show_config()
def show_config(self): def show_config(self):
hr0("Show deploy config") logger.hr("Show deploy config", 1)
for k, v in self.config.items(): for k, v in self.config.items():
if k in ("Password"): if k in ("Password"):
continue continue
if self.config_template[k] == v: if self.config_template[k] == v:
continue continue
print(f"{k}: {v}") logger.info(f"{k}: {v}")
print(f"Rest of the configs are the same as default") logger.info(f"Rest of the configs are the same as default")
def read(self): def read(self):
self.config = poor_yaml_read(DEPLOY_TEMPLATE) self.config = poor_yaml_read(DEPLOY_TEMPLATE)
@@ -112,36 +113,40 @@ class DeployConfig(ConfigModel):
.replace('"', '"') .replace('"', '"')
) )
def execute(self, command, allow_failure=False): def execute(self, command, allow_failure=False, output=True):
""" """
Args: Args:
command (str): command (str):
allow_failure (bool): allow_failure (bool):
output(bool):
Returns: Returns:
bool: If success. bool: If success.
Terminate installation if failed to execute and not allow_failure. Terminate installation if failed to execute and not allow_failure.
""" """
command = command.replace(r"\\", "/").replace("\\", "/").replace('"', '"') command = command.replace(r"\\", "/").replace("\\", "/").replace('"', '"')
print(command) if not output:
command = command + ' >nul 2>nul'
logger.info(command)
error_code = os.system(command) error_code = os.system(command)
if error_code: if error_code:
if allow_failure: if allow_failure:
print(f"[ allowed failure ], error_code: {error_code}") logger.info(f"[ allowed failure ], error_code: {error_code}")
return False return False
else: else:
print(f"[ failure ], error_code: {error_code}") logger.info(f"[ failure ], error_code: {error_code}")
self.show_error() self.show_error(command, error_code)
raise ExecutionError raise ExecutionError
else: else:
print(f"[ success ]") logger.info(f"[ success ]")
return True return True
def show_error(self): def show_error(self, command=None, error_code=None):
logger.hr("Update failed", 0)
self.show_config() self.show_config()
print("") logger.info("")
hr1("Update failed") logger.info(f"Last command: {command}\nerror_code: {error_code}")
print( logger.info(
"Please check your deploy settings in config/deploy.yaml " "Please check your deploy settings in config/deploy.yaml "
"and re-open Alas.exe" "and re-open Alas.exe"
) )

View File

@@ -1,7 +1,8 @@
import os import os
from deploy.logger import logger
BASE_FOLDER = os.path.dirname(os.path.abspath(__file__)) BASE_FOLDER = os.path.dirname(os.path.abspath(__file__))
print(BASE_FOLDER) logger.info(BASE_FOLDER)
def read_file(file): def read_file(file):
out = {} out = {}
@@ -37,10 +38,10 @@ def docker_requirements_generate(requirements_in='requirements-in.txt'):
requirements = read_file(requirements_in) requirements = read_file(requirements_in)
print(f'Generate requirements for Docker image') logger.info(f'Generate requirements for Docker image')
new = {} new = {}
print(requirements) logger.info(requirements)
for name, version in requirements.items(): for name, version in requirements.items():
# alas-webapp is for windows only # alas-webapp is for windows only
if name == 'alas-webapp': if name == 'alas-webapp':

View File

@@ -6,6 +6,7 @@ import shutil
import subprocess import subprocess
import winreg import winreg
from deploy.logger import logger
from deploy.utils import cached_property from deploy.utils import cached_property
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
@@ -13,6 +14,7 @@ asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
class VirtualBoxEmulator: class VirtualBoxEmulator:
UNINSTALL_REG = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" UNINSTALL_REG = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
UNINSTALL_REG_2 = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
def __init__(self, name, root_path, adb_path, vbox_path, vbox_name): def __init__(self, name, root_path, adb_path, vbox_path, vbox_name):
""" """
@@ -38,7 +40,10 @@ class VirtualBoxEmulator:
Raises: Raises:
FileNotFoundError: If emulator not installed. FileNotFoundError: If emulator not installed.
""" """
reg = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, f'{self.UNINSTALL_REG}\\{self.name}', 0) try:
reg = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, f'{self.UNINSTALL_REG}\\{self.name}', 0)
except FileNotFoundError:
reg = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, f'{self.UNINSTALL_REG_2}\\{self.name}', 0)
res = winreg.QueryValueEx(reg, 'UninstallString')[0] res = winreg.QueryValueEx(reg, 'UninstallString')[0]
file = re.search('"(.*?)"', res) file = re.search('"(.*?)"', res)
@@ -96,31 +101,31 @@ class VirtualBoxEmulator:
adb (str): Absolute path to adb.exe adb (str): Absolute path to adb.exe
""" """
for ori, bak in zip(self.adb_binary, self.adb_backup): for ori, bak in zip(self.adb_binary, self.adb_backup):
print(f'Replacing {ori}') logger.info(f'Replacing {ori}')
if os.path.exists(ori): if os.path.exists(ori):
if filecmp.cmp(adb, ori, shallow=True): if filecmp.cmp(adb, ori, shallow=True):
print(f'{adb} is same as {ori}, skip') logger.info(f'{adb} is same as {ori}, skip')
else: else:
print(f'{ori} -----> {bak}') logger.info(f'{ori} -----> {bak}')
shutil.move(ori, bak) shutil.move(ori, bak)
print(f'{adb} -----> {ori}') logger.info(f'{adb} -----> {ori}')
shutil.copy(adb, ori) shutil.copy(adb, ori)
else: else:
print(f'{ori} not exists, skip') logger.info(f'{ori} not exists, skip')
def adb_recover(self): def adb_recover(self):
""" Revert adb replacement """ """ Revert adb replacement """
for ori in self.adb_binary: for ori in self.adb_binary:
print(f'Recovering {ori}') logger.info(f'Recovering {ori}')
bak = f'{ori}.bak' bak = f'{ori}.bak'
if os.path.exists(bak): if os.path.exists(bak):
print(f'Delete {ori}') logger.info(f'Delete {ori}')
if os.path.exists(ori): if os.path.exists(ori):
os.remove(ori) os.remove(ori)
print(f'{bak} -----> {ori}') logger.info(f'{bak} -----> {ori}')
shutil.move(bak, ori) shutil.move(bak, ori)
else: else:
print(f'Not exists {bak}, skip') logger.info(f'Not exists {bak}, skip')
# NoxPlayer 夜神模拟器 # NoxPlayer 夜神模拟器
@@ -184,16 +189,28 @@ class EmulatorConnect:
def __init__(self, adb='adb.exe'): def __init__(self, adb='adb.exe'):
self.adb_binary = adb self.adb_binary = adb
def _execute(self, cmd, timeout=10): def _execute(self, cmd, timeout=10, output=True):
print(' '.join(cmd)) """
Returns:
Object: Stdout(str) of cmd if output,
return code(int) of cmd if not output.
"""
if not output:
cmd.extend(['>nul', '2>nul'])
logger.info(' '.join(cmd))
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
try: try:
stdout, stderr = process.communicate(timeout=timeout) stdout, stderr = process.communicate(timeout=timeout)
ret_code = process.returncode
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
process.kill() process.kill()
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
print(f'TimeoutExpired, stdout={stdout}, stderr={stderr}') ret_code = 1
return stdout logger.info(f'TimeoutExpired, stdout={stdout}, stderr={stderr}')
if output:
return stdout
else:
return ret_code
@cached_property @cached_property
def emulators(self): def emulators(self):
@@ -209,7 +226,7 @@ class EmulatorConnect:
except FileNotFoundError: except FileNotFoundError:
continue continue
if len(serial): if len(serial):
print(f'Emulator {emulator.name} found, instances: {serial}') logger.info(f'Emulator {emulator.name} found, instances: {serial}')
return emulators return emulators
@@ -227,7 +244,7 @@ class EmulatorConnect:
if status == 'device': if status == 'device':
devices.append(serial) devices.append(serial)
print(f'Devices: {devices}') logger.info(f'Devices: {devices}')
return devices return devices
def adb_kill(self): def adb_kill(self):
@@ -235,7 +252,7 @@ class EmulatorConnect:
# self._execute([self.adb_binary, 'kill-server']) # self._execute([self.adb_binary, 'kill-server'])
# Just kill it, because some adb don't obey. # Just kill it, because some adb don't obey.
print('Kill all known ADB') logger.info('Kill all known ADB')
for exe in [ for exe in [
# Most emulator use this # Most emulator use this
'adb.exe', 'adb.exe',
@@ -246,7 +263,13 @@ class EmulatorConnect:
# Bluestacks 蓝叠模拟器 # Bluestacks 蓝叠模拟器
'HD-Adb.exe' 'HD-Adb.exe'
]: ]:
self._execute(['taskkill', '/f', '/im', exe]) ret_code = self._execute(['taskkill', '/f', '/im', exe], output=False)
if ret_code == 0:
logger.info(f'Task {exe} killed')
elif ret_code == 128:
logger.info(f'Task {exe} not found')
else:
logger.info(f'Error occurred when killing task {exe}, return code {ret_code}')
@cached_property @cached_property
def serial(self): def serial(self):
@@ -303,4 +326,4 @@ class EmulatorConnect:
if __name__ == '__main__': if __name__ == '__main__':
emu = EmulatorConnect() emu = EmulatorConnect()
print(emu.brute_force_connect()) logger.info(emu.brute_force_connect())

View File

@@ -1,4 +1,5 @@
from deploy.config import DeployConfig from deploy.config import DeployConfig
from deploy.logger import logger
from deploy.utils import * from deploy.utils import *
@@ -8,10 +9,10 @@ class GitManager(DeployConfig):
return self.filepath('GitExecutable') return self.filepath('GitExecutable')
def git_repository_init(self, repo, source='origin', branch='master', proxy='', keep_changes=False): def git_repository_init(self, repo, source='origin', branch='master', proxy='', keep_changes=False):
hr1('Git Init') logger.hr('Git Init', 1)
self.execute(f'"{self.git}" init') self.execute(f'"{self.git}" init')
hr1('Set Git Proxy') logger.hr('Set Git Proxy', 1)
if proxy: if proxy:
self.execute(f'"{self.git}" config --local http.proxy {proxy}') self.execute(f'"{self.git}" config --local http.proxy {proxy}')
self.execute(f'"{self.git}" config --local https.proxy {proxy}') self.execute(f'"{self.git}" config --local https.proxy {proxy}')
@@ -19,18 +20,18 @@ class GitManager(DeployConfig):
self.execute(f'"{self.git}" config --local --unset http.proxy', allow_failure=True) self.execute(f'"{self.git}" config --local --unset http.proxy', allow_failure=True)
self.execute(f'"{self.git}" config --local --unset https.proxy', allow_failure=True) self.execute(f'"{self.git}" config --local --unset https.proxy', allow_failure=True)
hr1('Set Git Repository') logger.hr('Set Git Repository', 1)
if not self.execute(f'"{self.git}" remote set-url {source} {repo}', allow_failure=True): if not self.execute(f'"{self.git}" remote set-url {source} {repo}', allow_failure=True):
self.execute(f'"{self.git}" remote add {source} {repo}') self.execute(f'"{self.git}" remote add {source} {repo}')
hr1('Fetch Repository Branch') logger.hr('Fetch Repository Branch', 1)
self.execute(f'"{self.git}" fetch {source} {branch}') self.execute(f'"{self.git}" fetch {source} {branch}')
hr1('Pull Repository Branch') logger.hr('Pull Repository Branch', 1)
# Remove git lock # Remove git lock
lock_file = './.git/index.lock' lock_file = './.git/index.lock'
if os.path.exists(lock_file): if os.path.exists(lock_file):
print(f'Lock file {lock_file} exists, removing') logger.info(f'Lock file {lock_file} exists, removing')
os.remove(lock_file) os.remove(lock_file)
if keep_changes: if keep_changes:
if self.execute(f'"{self.git}" stash', allow_failure=True): if self.execute(f'"{self.git}" stash', allow_failure=True):
@@ -39,23 +40,23 @@ class GitManager(DeployConfig):
pass pass
else: else:
# No local changes to existing files, untracked files not included # No local changes to existing files, untracked files not included
print('Stash pop failed, there seems to be no local changes, skip instead') logger.info('Stash pop failed, there seems to be no local changes, skip instead')
else: else:
print('Stash failed, this may be the first installation, drop changes instead') logger.info('Stash failed, this may be the first installation, drop changes instead')
self.execute(f'"{self.git}" reset --hard {source}/{branch}') self.execute(f'"{self.git}" reset --hard {source}/{branch}')
self.execute(f'"{self.git}" pull --ff-only {source} {branch}') self.execute(f'"{self.git}" pull --ff-only {source} {branch}')
else: else:
self.execute(f'"{self.git}" reset --hard {source}/{branch}') self.execute(f'"{self.git}" reset --hard {source}/{branch}')
self.execute(f'"{self.git}" pull --ff-only {source} {branch}') self.execute(f'"{self.git}" pull --ff-only {source} {branch}')
hr1('Show Version') logger.hr('Show Version', 1)
self.execute(f'"{self.git}" log --no-merges -1') self.execute(f'"{self.git}" log --no-merges -1')
def git_install(self): def git_install(self):
hr0('Update Alas') logger.hr('Update Alas', 0)
if not self.AutoUpdate: if not self.AutoUpdate:
print('AutoUpdate is disabled, skip') logger.info('AutoUpdate is disabled, skip')
return return
self.git_repository_init( self.git_repository_init(

33
deploy/logger.py Normal file
View File

@@ -0,0 +1,33 @@
import logging
import sys
logger = logging.getLogger("deploy")
_logger = logger
formatter = logging.Formatter(fmt="%(message)s")
hdlr = logging.StreamHandler(stream=sys.stdout)
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
def hr(title, level=3):
if logger is not _logger:
return logger.hr(title, level)
title = str(title).upper()
if level == 0:
middle = "|" + " " * 20 + title + " " * 20 + "|"
border = "+" + "-" * (len(middle) - 2) + "+"
logger.info(border)
logger.info(middle)
logger.info(border)
if level == 1:
logger.info("=" * 20 + " " + title + " " + "=" * 20)
if level == 2:
logger.info("-" * 20 + " " + title + " " + "-" * 20)
if level == 3:
logger.info(f"<<< {title} >>>")
logger.hr = hr

View File

@@ -1,6 +1,7 @@
from urllib.parse import urlparse from urllib.parse import urlparse
from deploy.config import DeployConfig from deploy.config import DeployConfig
from deploy.logger import logger
from deploy.utils import * from deploy.utils import *
@@ -21,13 +22,13 @@ class PipManager(DeployConfig):
return f'"{self.python}" -m pip' return f'"{self.python}" -m pip'
def pip_install(self): def pip_install(self):
hr0('Update Dependencies') logger.hr('Update Dependencies', 0)
if not self.InstallDependencies: if not self.InstallDependencies:
print('InstallDependencies is disabled, skip') logger.info('InstallDependencies is disabled, skip')
return return
hr1('Check Python') logger.hr('Check Python', 1)
self.execute(f'"{self.python}" --version') self.execute(f'"{self.python}" --version')
arg = [] arg = []
@@ -39,10 +40,10 @@ class PipManager(DeployConfig):
arg += ['--trusted-host', urlparse(mirror).hostname] arg += ['--trusted-host', urlparse(mirror).hostname]
# Don't update pip, just leave it. # Don't update pip, just leave it.
# hr1('Update pip') # logger.hr('Update pip', 1)
# self.execute(f'"{self.pip}" install --upgrade pip{arg}') # self.execute(f'"{self.pip}" install --upgrade pip{arg}')
arg += ['--disable-pip-version-check'] arg += ['--disable-pip-version-check']
hr1('Update Dependencies') logger.hr('Update Dependencies', 1)
arg = ' ' + ' '.join(arg) if arg else '' arg = ' ' + ' '.join(arg) if arg else ''
self.execute(f'{self.pip} install -r {self.requirements_file}{arg}') self.execute(f'{self.pip} install -r {self.requirements_file}{arg}')

View File

@@ -83,15 +83,3 @@ def poor_yaml_write(data, file, template_file=DEPLOY_TEMPLATE):
with open(file, 'w', encoding='utf-8', newline='') as f: with open(file, 'w', encoding='utf-8', newline='') as f:
f.write(text) f.write(text)
def hr1(title):
print('=' * 20 + ' ' + title + ' ' + '=' * 20)
def hr0(title):
middle = '|' + ' ' * 20 + title + ' ' * 20 + '|'
border = '+' + '-' * (len(middle) - 2) + '+'
print(border)
print(middle)
print(border)

View File

@@ -48,7 +48,7 @@ class OSChapter:
if not isinstance(index, int) or index >= 200: if not isinstance(index, int) or index >= 200:
continue continue
name = chapter['name'] name = chapter['name']
name = name.replace('é', 'e') # OCR can't recognise letter "é" name = name.replace('é', 'e') # OCR can't recognize letter "é"
out[index] = name out[index] = name
# Zone 40000 is zone 154 # Zone 40000 is zone 154

2
gui.py
View File

@@ -14,7 +14,7 @@ def func(ev: threading.Event):
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
State.researt_event = ev State.restart_event = ev
parser = argparse.ArgumentParser(description="Alas web service") parser = argparse.ArgumentParser(description="Alas web service")
parser.add_argument( parser.add_argument(

View File

@@ -1,5 +1,3 @@
import builtins
from deploy.git import GitManager from deploy.git import GitManager
from deploy.utils import * from deploy.utils import *
from module.handler.login import LoginHandler from module.handler.login import LoginHandler
@@ -28,7 +26,6 @@ class AzurLaneUncensored(LoginHandler):
# Running in ./toolkit/AzurLaneUncensored # Running in ./toolkit/AzurLaneUncensored
os.chdir(folder) os.chdir(folder)
# Monkey patch `print()` build-in to show logs. # Monkey patch `print()` build-in to show logs.
backup, builtins.print = builtins.print, logger.info
manager.git_repository_init( manager.git_repository_init(
repo=repo, repo=repo,
source='origin', source='origin',
@@ -36,7 +33,6 @@ class AzurLaneUncensored(LoginHandler):
proxy=manager.config['GitProxy'], proxy=manager.config['GitProxy'],
keep_changes=False keep_changes=False
) )
builtins.print = backup
logger.hr('Push Uncensored Files', level=1) logger.hr('Push Uncensored Files', level=1)
logger.info('This will take a few seconds') logger.info('This will take a few seconds')

View File

@@ -5,6 +5,7 @@ from functools import wraps
from adbutils.errors import AdbError from adbutils.errors import AdbError
from module.base.decorator import cached_property from module.base.decorator import cached_property
from module.base.timer import Timer
from module.base.utils import * from module.base.utils import *
from module.device.connection import Connection from module.device.connection import Connection
from module.device.method.utils import (RETRY_DELAY, RETRY_TRIES, from module.device.method.utils import (RETRY_DELAY, RETRY_TRIES,
@@ -280,31 +281,46 @@ class Minitouch(Connection):
# No need, minitouch already started by uiautomator2 # No need, minitouch already started by uiautomator2
# self.adb_shell([self.config.MINITOUCH_FILEPATH_REMOTE]) # self.adb_shell([self.config.MINITOUCH_FILEPATH_REMOTE])
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) retry_timeout = Timer(2).start()
client.settimeout(1) while 1:
client.connect(('127.0.0.1', self._minitouch_port)) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._minitouch_client = client client.settimeout(1)
client.connect(('127.0.0.1', self._minitouch_port))
self._minitouch_client = client
# get minitouch server info # get minitouch server info
socket_out = client.makefile() socket_out = client.makefile()
# v <version> # v <version>
# protocol version, usually it is 1. needn't use this # protocol version, usually it is 1. needn't use this
try: try:
out = socket_out.readline().replace("\n", "").replace("\r", "")
except socket.timeout:
client.close()
raise MinitouchOccupiedError(
'Timeout when connecting to minitouch, '
'probably because another connection has been established'
)
logger.info(out)
# ^ <max-contacts> <max-x> <max-y> <max-pressure>
out = socket_out.readline().replace("\n", "").replace("\r", "") out = socket_out.readline().replace("\n", "").replace("\r", "")
except socket.timeout: logger.info(out)
raise MinitouchOccupiedError('Timeout when connecting to minitouch, ' try:
'probably because another connection has been established') _, max_contacts, max_x, max_y, max_pressure, *_ = out.split(" ")
logger.info(out) break
except ValueError:
client.close()
if retry_timeout.reached():
raise MinitouchNotInstalledError(
'Received empty data from minitouch, '
'probably because minitouch is not installed'
)
else:
# Minitouch may not start that fast
self.sleep(1)
continue
# ^ <max-contacts> <max-x> <max-y> <max-pressure>
out = socket_out.readline().replace("\n", "").replace("\r", "")
logger.info(out)
try:
_, max_contacts, max_x, max_y, max_pressure, *_ = out.split(" ")
except ValueError:
raise MinitouchNotInstalledError('Received empty data from minitouch, '
'probably because minitouch is not installed')
# self.max_contacts = max_contacts # self.max_contacts = max_contacts
self.max_x = int(max_x) self.max_x = int(max_x)
self.max_y = int(max_y) self.max_y = int(max_y)

View File

@@ -18,13 +18,13 @@ OCR_BUILD_SUBMIT_WW_COUNT = Digit(BUILD_SUBMIT_WW_COUNT, letter=(255, 247, 247),
class RewardGacha(GachaUI, GeneralShop, Retirement): class RewardGacha(GachaUI, GeneralShop, Retirement):
build_cube_count = 0 build_cube_count = 0
def gacha_prep(self, target, skip_first_scrrenshot=True): def gacha_prep(self, target, skip_first_screenshot=True):
""" """
Initiate preparation to submit build orders. Initiate preparation to submit build orders.
Args: Args:
target (int): Number of build orders to submit target (int): Number of build orders to submit
skip_first_scrrenshot (bool): skip_first_screenshot (bool):
Returns: Returns:
bool: True if prep complete otherwise False. bool: True if prep complete otherwise False.
@@ -51,8 +51,8 @@ class RewardGacha(GachaUI, GeneralShop, Retirement):
ocr_submit = None ocr_submit = None
index_offset = (60, 20) index_offset = (60, 20)
while 1: while 1:
if skip_first_scrrenshot: if skip_first_screenshot:
skip_first_scrrenshot = False skip_first_screenshot = False
else: else:
self.device.screenshot() self.device.screenshot()

View File

@@ -55,7 +55,7 @@ class AmbushHandler(Combat):
logger.attr('Ambush_evade', 'failed') logger.attr('Ambush_evade', 'failed')
self.combat(expected_end='no_searching', fleet_index=self.fleet_show_index) self.combat(expected_end='no_searching', fleet_index=self.fleet_show_index)
else: else:
logger.warning('Unrecognised info when ambush evade.') logger.warning('Unrecognized info when ambush evade.')
self.ensure_no_info_bar() self.ensure_no_info_bar()
if self.combat_appear(): if self.combat_appear():
self.combat(fleet_index=self.fleet_show_index) self.combat(fleet_index=self.fleet_show_index)

View File

@@ -207,7 +207,7 @@ class InfoHandler(ModuleBase):
""" """
Story Story
""" """
story_popup_timout = Timer(10, count=20) story_popup_timeout = Timer(10, count=20)
map_has_clear_mode = False # Will be override in fast_forward.py map_has_clear_mode = False # Will be override in fast_forward.py
# Area to detect the options, should include at least 3 options. # Area to detect the options, should include at least 3 options.
@@ -255,14 +255,14 @@ class InfoHandler(ModuleBase):
return buttons return buttons
def story_skip(self, drop=None): def story_skip(self, drop=None):
if self.story_popup_timout.started() and not self.story_popup_timout.reached(): if self.story_popup_timeout.started() and not self.story_popup_timeout.reached():
if self.handle_popup_confirm('STORY_SKIP'): if self.handle_popup_confirm('STORY_SKIP'):
self.story_popup_timout = Timer(10) self.story_popup_timeout = Timer(10)
self.interval_reset(STORY_SKIP) self.interval_reset(STORY_SKIP)
self.interval_reset(STORY_LETTERS_ONLY) self.interval_reset(STORY_LETTERS_ONLY)
return True return True
if self.appear(STORY_LETTER_BLACK) and self.appear_then_click(STORY_LETTERS_ONLY, offset=(20, 20), interval=2): if self.appear(STORY_LETTER_BLACK) and self.appear_then_click(STORY_LETTERS_ONLY, offset=(20, 20), interval=2):
self.story_popup_timout.reset() self.story_popup_timeout.reset()
return True return True
if self._story_option_timer.reached() and self.appear(STORY_SKIP, offset=(20, 20), interval=0): if self._story_option_timer.reached() and self.appear(STORY_SKIP, offset=(20, 20), interval=0):
options = self._story_option_buttons() options = self._story_option_buttons()
@@ -279,7 +279,7 @@ class InfoHandler(ModuleBase):
select = options[0] select = options[0]
self.device.click(select) self.device.click(select)
self._story_option_timer.reset() self._story_option_timer.reset()
self.story_popup_timout.reset() self.story_popup_timeout.reset()
self.interval_reset(STORY_SKIP) self.interval_reset(STORY_SKIP)
self.interval_reset(STORY_LETTERS_ONLY) self.interval_reset(STORY_LETTERS_ONLY)
self._story_option_record = 0 self._story_option_record = 0
@@ -292,10 +292,10 @@ class InfoHandler(ModuleBase):
if drop: if drop:
drop.handle_add(self, before=2) drop.handle_add(self, before=2)
self.device.click(STORY_SKIP) self.device.click(STORY_SKIP)
self.story_popup_timout.reset() self.story_popup_timeout.reset()
return True return True
if self.appear_then_click(GAME_TIPS, offset=(20, 20), interval=2): if self.appear_then_click(GAME_TIPS, offset=(20, 20), interval=2):
self.story_popup_timout.reset() self.story_popup_timeout.reset()
return True return True
return False return False

View File

@@ -61,7 +61,7 @@ class MeowfficerEnhance(MeowfficerBase):
Scan for meowfficers that can be fed Scan for meowfficers that can be fed
according to the MEOWFFICER_FEED_GRID (4x3) according to the MEOWFFICER_FEED_GRID (4x3)
into target meowfficer for enhancement into target meowfficer for enhancement
Ensure through green check mark apperance Ensure through green check mark appearance
after click after click
Pages: Pages:

View File

@@ -147,7 +147,7 @@ class AlOcr(CnOcr):
""" """
:param img: image array with type mx.nd.NDArray or np.ndarray, :param img: image array with type mx.nd.NDArray or np.ndarray,
with shape [height, width] or [height, width, channel]. with shape [height, width] or [height, width, channel].
channel shoule be 1 (gray image) or 3 (color image). channel should be 1 (gray image) or 3 (color image).
:return: np.ndarray, with shape (1, height, width) :return: np.ndarray, with shape (1, height, width)
""" """

View File

@@ -526,7 +526,7 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh):
logger.info('Fleet left boss, boss found') logger.info('Fleet left boss, boss found')
break break
# Re-enter boss accidently # Re-enter boss accidentally
if self.combat_appear(): if self.combat_appear():
self.ui_back(check_button=self.is_in_map) self.ui_back(check_button=self.is_in_map)

View File

@@ -26,7 +26,7 @@ class FleetSelector:
def get(self): def get(self):
""" """
Returns: Returns:
int: Index of current fleet, 1 to 4. return 0 if unrecognised. int: Index of current fleet, 1 to 4. return 0 if unrecognized.
""" """
for index, button in enumerate([FLEET_1, FLEET_2, FLEET_3, FLEET_4]): for index, button in enumerate([FLEET_1, FLEET_2, FLEET_3, FLEET_4]):
if self.main.appear(button, offset=(20, 20)): if self.main.appear(button, offset=(20, 20)):

View File

@@ -23,7 +23,7 @@ CARD_RARITY_COLORS = {
class Retirement(Enhancement): class Retirement(Enhancement):
_unable_to_enhance = False _unable_to_enhance = False
_have_keeped_cv = True _have_kept_cv = True
def _retirement_choose(self, amount=10, target_rarity=('N',)): def _retirement_choose(self, amount=10, target_rarity=('N',)):
""" """
@@ -92,7 +92,7 @@ class Retirement(Enhancement):
self.device.click(SHIP_CONFIRM) self.device.click(SHIP_CONFIRM)
continue continue
if self.appear(SHIP_CONFIRM_2, offset=(30, 30), interval=2): if self.appear(SHIP_CONFIRM_2, offset=(30, 30), interval=2):
if self.config.RETIRE_KEEP_COMMON_CV and not self._have_keeped_cv: if self.config.RETIRE_KEEP_COMMON_CV and not self._have_kept_cv:
self.keep_one_common_cv() self.keep_one_common_cv()
self.device.click(SHIP_CONFIRM_2) self.device.click(SHIP_CONFIRM_2)
self.interval_clear(GET_ITEMS_1) self.interval_clear(GET_ITEMS_1)
@@ -154,7 +154,7 @@ class Retirement(Enhancement):
total = 0 total = 0
if self.config.RETIRE_KEEP_COMMON_CV: if self.config.RETIRE_KEEP_COMMON_CV:
self._have_keeped_cv = False self._have_kept_cv = False
while 1: while 1:
self.handle_info_bar() self.handle_info_bar()
@@ -217,7 +217,7 @@ class Retirement(Enhancement):
total = 0 total = 0
if self.config.RETIRE_KEEP_COMMON_CV: if self.config.RETIRE_KEEP_COMMON_CV:
self._have_keeped_cv = False self._have_kept_cv = False
while amount: while amount:
selected = self._retirement_choose( selected = self._retirement_choose(
@@ -364,15 +364,15 @@ class Retirement(Enhancement):
Button: Button:
""" """
if self.config.GemsFarming_CommonCV == 'any': if self.config.GemsFarming_CommonCV == 'any':
for commen_cv_name in ['BOGUE', 'HERMES', 'LANGLEY', 'RANGER']: for common_cv_name in ['BOGUE', 'HERMES', 'LANGLEY', 'RANGER']:
template = globals()[f'TEMPLATE_{commen_cv_name}'] template = globals()[f'TEMPLATE_{common_cv_name}']
sim, button = template.match_result( sim, button = template.match_result(
resize(self.device.image, size=(1189, 669))) resize(self.device.image, size=(1189, 669)))
if sim > self.config.COMMON_CV_THRESHOLD: if sim > self.config.COMMON_CV_THRESHOLD:
return Button(button=tuple(_ * 155 // 144 for _ in button.button), area=button.area, return Button(button=tuple(_ * 155 // 144 for _ in button.button), area=button.area,
color=button.color, color=button.color,
name=f'TEMPLATE_{commen_cv_name}_RETIRE') name=f'TEMPLATE_{common_cv_name}_RETIRE')
return None return None
else: else:
@@ -392,4 +392,4 @@ class Retirement(Enhancement):
button = self.retirement_get_common_rarity_cv() button = self.retirement_get_common_rarity_cv()
if button is not None: if button is not None:
self._retire_select_one(button, skip_first_screenshot=False) self._retire_select_one(button, skip_first_screenshot=False)
self._have_keeped_cv = True self._have_kept_cv = True

View File

@@ -113,7 +113,7 @@ class ShopBase(ModuleBase):
Custom steps for variant shop Custom steps for variant shop
if needed to ensure shop has if needed to ensure shop has
loaded completely loaded completely
ShopMedal for example will initally ShopMedal for example will initially
display default items at default prices display default items at default prices
Args: Args:

View File

@@ -141,7 +141,7 @@ class ShopClerk(ShopBase, Retirement):
click_timer.reset() click_timer.reset()
# Scan for plus/minus locations; searching within # Scan for plus/minus locations; searching within
# offset will update the click posiion automatically # offset will update the click position automatically
self.device.screenshot() self.device.screenshot()
if self.appear(SELECT_MINUS, offset=select_offset) and self.appear(SELECT_PLUS, offset=select_offset): if self.appear(SELECT_MINUS, offset=select_offset) and self.appear(SELECT_PLUS, offset=select_offset):
break break

View File

@@ -1,2 +1,5 @@
# This must be the first to import # This must be the first to import
from module.logger import logger # Change folder from module.logger import logger # Change folder
import deploy.logger
deploy.logger.logger = logger

View File

@@ -373,7 +373,7 @@ class AlasGUI(Frame):
self.task_handler.add(switch_scheduler.g(), 1, True) self.task_handler.add(switch_scheduler.g(), 1, True)
self.task_handler.add(switch_log_scroll.g(), 1, True) self.task_handler.add(switch_log_scroll.g(), 1, True)
self.task_handler.add(self.alas_update_overiew_task, 10, True) self.task_handler.add(self.alas_update_overview_task, 10, True)
self.task_handler.add(log.put_log(self.alas), 0.25, True) self.task_handler.add(log.put_log(self.alas), 0.25, True)
def _alas_thread_wait_config_change(self) -> None: def _alas_thread_wait_config_change(self) -> None:
@@ -457,7 +457,7 @@ class AlasGUI(Frame):
invalid.clear() invalid.clear()
break break
def alas_update_overiew_task(self) -> None: def alas_update_overview_task(self) -> None:
if not self.visible: if not self.visible:
return return
self.alas_config.load() self.alas_config.load()
@@ -628,10 +628,10 @@ class AlasGUI(Frame):
# ).style(f'--menu-Raise--') # ).style(f'--menu-Raise--')
def _force_restart(): def _force_restart():
if State.researt_event is not None: if State.restart_event is not None:
toast("Alas will restart in 3 seconds", duration=0, color="error") toast("Alas will restart in 3 seconds", duration=0, color="error")
clearup() clearup()
State.researt_event.set() State.restart_event.set()
else: else:
toast("Reload not enabled", color="error") toast("Reload not enabled", color="error")
@@ -651,7 +651,7 @@ class AlasGUI(Frame):
self.init_menu(name="Update") self.init_menu(name="Update")
self.set_title(t("Gui.MenuDevelop.Update")) self.set_title(t("Gui.MenuDevelop.Update"))
if State.researt_event is None: if State.restart_event is None:
put_warning(t("Gui.Update.DisabledWarn")) put_warning(t("Gui.Update.DisabledWarn"))
put_row( put_row(
@@ -995,7 +995,7 @@ class AlasGUI(Frame):
status={ status={
True: [ True: [
lambda: self.__setattr__("visible", True), lambda: self.__setattr__("visible", True),
lambda: self.alas_update_overiew_task() lambda: self.alas_update_overview_task()
if self.page == "Overview" if self.page == "Overview"
else 0, else 0,
lambda: self.task_handler._task.__setattr__("delay", 15), lambda: self.task_handler._task.__setattr__("delay", 15),

View File

@@ -16,7 +16,7 @@ class State:
deploy_config = DeployConfig() deploy_config = DeployConfig()
config_updater = ConfigUpdater() config_updater = ConfigUpdater()
researt_event: threading.Event = None restart_event: threading.Event = None
manager: SyncManager = None manager: SyncManager = None
electron: bool = False electron: bool = False
theme: str = "default" theme: str = "default"

View File

@@ -1,6 +1,4 @@
import builtins
import datetime import datetime
import os
import subprocess import subprocess
import threading import threading
import time import time
@@ -25,31 +23,6 @@ class Updater(DeployConfig, GitManager, PipManager):
self.state = 0 self.state = 0
self.event: threading.Event = None self.event: threading.Event = None
def execute(self, command, allow_failure=False):
"""
Args:
command (str):
allow_failure (bool):
Returns:
bool: If success.
Terminate installation if failed to execute and not allow_failure.
"""
command = command.replace(r"\\", "/").replace("\\", "/").replace('"', '"')
print(command)
error_code = os.system(command)
if error_code:
if allow_failure:
print(f"[ allowed failure ], error_code: {error_code}")
return False
else:
print(f"[ failure ], error_code: {error_code}")
# self.show_error()
raise ExecutionError
else:
print(f"[ success ]")
return True
@property @property
def delay(self): def delay(self):
self.read() self.read()
@@ -117,7 +90,7 @@ class Updater(DeployConfig, GitManager, PipManager):
sha1, _, _, message = self.get_commit(f"..{source}/{self.Branch}") sha1, _, _, message = self.get_commit(f"..{source}/{self.Branch}")
if sha1: if sha1:
logger.info(f"New update avaliable") logger.info(f"New update available")
logger.info(f"{sha1[:8]} - {message}") logger.info(f"{sha1[:8]} - {message}")
return True return True
else: else:
@@ -191,7 +164,7 @@ class Updater(DeployConfig, GitManager, PipManager):
) )
return 0 return 0
logger.info(f"Update {sha[:8]} avaliable") logger.info(f"Update {sha[:8]} available")
return 1 return 1
def check_update(self): def check_update(self):
@@ -208,14 +181,11 @@ class Updater(DeployConfig, GitManager, PipManager):
def update(self): def update(self):
logger.hr("Run update") logger.hr("Run update")
backup, builtins.print = builtins.print, logger.info
try: try:
self.git_install() self.git_install()
self.pip_install() self.pip_install()
except ExecutionError: except ExecutionError:
builtins.print = backup
return False return False
builtins.print = backup
return True return True
def run_update(self): def run_update(self):
@@ -258,7 +228,7 @@ class Updater(DeployConfig, GitManager, PipManager):
logger.info("All alas stopped, start updating") logger.info("All alas stopped, start updating")
if self.update(): if self.update():
if State.researt_event is not None: if State.restart_event is not None:
self.state = "reload" self.state = "reload"
with open("./config/reloadalas", mode="w") as f: with open("./config/reloadalas", mode="w") as f:
f.writelines(names) f.writelines(names)
@@ -281,7 +251,7 @@ class Updater(DeployConfig, GitManager, PipManager):
# with open("./config/reloadflag", mode="w"): # with open("./config/reloadflag", mode="w"):
# # app ended here and uvicorn will restart whole app # # app ended here and uvicorn will restart whole app
# pass # pass
State.researt_event.set() State.restart_event.set()
timer = threading.Timer(delay, trigger) timer = threading.Timer(delay, trigger)
timer.start() timer.start()
@@ -300,7 +270,7 @@ class Updater(DeployConfig, GitManager, PipManager):
th._task.delay = get_next_time(self.schedule_time) th._task.delay = get_next_time(self.schedule_time)
yield yield
continue continue
if State.researt_event is None: if State.restart_event is None:
yield yield
continue continue
if not self.run_update(): if not self.run_update():