Merge branch '20230309' into smallkai
BIN
assets/cn/dorm/DORM_MANAGE.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/cn/handler/FORMATION_1.BUTTON.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/cn/handler/FORMATION_2.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/cn/handler/FORMATION_3.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/cn/retire/TEMPLATE_AULICK.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
assets/cn/retire/TEMPLATE_CASSIN_1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/cn/retire/TEMPLATE_CASSIN_2.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/cn/retire/TEMPLATE_DOWNES_1.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/cn/retire/TEMPLATE_DOWNES_2.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
assets/cn/retire/TEMPLATE_FOOTE.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 7.9 KiB |
BIN
assets/en/dorm/DORM_MANAGE.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/en/handler/FORMATION_1.BUTTON.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/en/handler/FORMATION_2.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/en/handler/FORMATION_3.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/en/retire/TEMPLATE_AULICK.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
assets/en/retire/TEMPLATE_CASSIN_1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/en/retire/TEMPLATE_CASSIN_2.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/en/retire/TEMPLATE_DOWNES_1.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/en/retire/TEMPLATE_DOWNES_2.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
assets/en/retire/TEMPLATE_FOOTE.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 3.0 KiB |
BIN
assets/jp/dorm/DORM_MANAGE.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/jp/handler/FORMATION_1.BUTTON.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/jp/handler/FORMATION_2.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/jp/handler/FORMATION_3.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/jp/retire/TEMPLATE_AULICK.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
assets/jp/retire/TEMPLATE_CASSIN_1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/jp/retire/TEMPLATE_CASSIN_2.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/jp/retire/TEMPLATE_DOWNES_1.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/jp/retire/TEMPLATE_DOWNES_2.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
assets/jp/retire/TEMPLATE_FOOTE.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 3.0 KiB |
BIN
assets/tw/dorm/DORM_MANAGE.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/tw/handler/FORMATION_1.BUTTON.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/tw/handler/FORMATION_2.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/tw/handler/FORMATION_3.BUTTON.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
BIN
assets/tw/retire/TEMPLATE_AULICK.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
assets/tw/retire/TEMPLATE_CASSIN_1.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/tw/retire/TEMPLATE_CASSIN_2.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/tw/retire/TEMPLATE_DOWNES_1.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/tw/retire/TEMPLATE_DOWNES_2.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
assets/tw/retire/TEMPLATE_FOOTE.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -189,3 +189,5 @@ To add a new event, add a new row in here, and run `python -m module.config.conf
|
||||
| 20240314 | event 20220324 cn | Virtual Tower Rerun | 复刻虚像构筑之塔 | Virtual Tower Rerun | 幻像の塔(復刻) | - |
|
||||
| 20240321 | raid 20230629 | Reflections of the Oasis | - | - | - | 綠洲往事 |
|
||||
| 20240328 | raid 20240328 | From Zero to Hero | 从零开始的魔王讨伐之旅 | From Zero to Hero | ゼロから頑張る魔王討伐 | - |
|
||||
| 20240403 | event 20211111 cn | The Flame-Touched Dagger | - | - | - | 復刻杰諾瓦的焰火 |
|
||||
| 20240411 | event 20220224 cn | Abyssal Refrain Rerun | 复刻深度回音 | Abyssal Refrain Rerun | 鳴動せし星霜の淵(復刻) | - |
|
||||
@@ -54,6 +54,13 @@ class Config(ConfigBase):
|
||||
MAP_HAS_AMBUSH = False
|
||||
MAP_HAS_MYSTERY = True
|
||||
# ===== End of generated config =====
|
||||
HOMO_EDGE_COLOR_RANGE = (0, 12)
|
||||
HOMO_EDGE_HOUGHLINES_THRESHOLD = 210
|
||||
MAP_SWIPE_MULTIPLY = (1.101, 1.122)
|
||||
MAP_SWIPE_MULTIPLY_MINITOUCH = (1.065, 1.085)
|
||||
MAP_SWIPE_MULTIPLY_MAATOUCH = (1.034, 1.053)
|
||||
HOMO_STORAGE = ((6, 5), [(211, 175), (782, 175), (158, 569), (800, 569)])
|
||||
MAP_ENSURE_EDGE_INSIGHT_CORNER = 'top'
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
|
||||
@@ -58,6 +58,13 @@ class Config(ConfigBase):
|
||||
MAP_HAS_AMBUSH = False
|
||||
MAP_HAS_MYSTERY = False
|
||||
# ===== End of generated config =====
|
||||
HOMO_EDGE_COLOR_RANGE = (0, 12)
|
||||
HOMO_EDGE_HOUGHLINES_THRESHOLD = 210
|
||||
MAP_SWIPE_MULTIPLY = (1.101, 1.122)
|
||||
MAP_SWIPE_MULTIPLY_MINITOUCH = (1.065, 1.085)
|
||||
MAP_SWIPE_MULTIPLY_MAATOUCH = (1.034, 1.053)
|
||||
HOMO_STORAGE = ((6, 4), [(448, 180), (1051, 180), (426, 513), (1100, 513)])
|
||||
MAP_ENSURE_EDGE_INSIGHT_CORNER = 'top'
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
|
||||
@@ -55,6 +55,13 @@ class Config(ConfigBase):
|
||||
MAP_HAS_AMBUSH = False
|
||||
MAP_HAS_MYSTERY = True
|
||||
# ===== End of generated config =====
|
||||
HOMO_EDGE_COLOR_RANGE = (0, 12)
|
||||
HOMO_EDGE_HOUGHLINES_THRESHOLD = 210
|
||||
MAP_SWIPE_MULTIPLY = (1.101, 1.122)
|
||||
MAP_SWIPE_MULTIPLY_MINITOUCH = (1.065, 1.085)
|
||||
MAP_SWIPE_MULTIPLY_MAATOUCH = (1.034, 1.053)
|
||||
HOMO_STORAGE = ((6, 5), [(211, 175), (782, 175), (158, 569), (800, 569)])
|
||||
MAP_ENSURE_EDGE_INSIGHT_CORNER = 'top'
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
|
||||
@@ -58,6 +58,13 @@ class Config(ConfigBase):
|
||||
MAP_HAS_AMBUSH = False
|
||||
MAP_HAS_MYSTERY = False
|
||||
# ===== End of generated config =====
|
||||
HOMO_EDGE_COLOR_RANGE = (0, 12)
|
||||
HOMO_EDGE_HOUGHLINES_THRESHOLD = 210
|
||||
MAP_SWIPE_MULTIPLY = (1.101, 1.122)
|
||||
MAP_SWIPE_MULTIPLY_MINITOUCH = (1.065, 1.085)
|
||||
MAP_SWIPE_MULTIPLY_MAATOUCH = (1.034, 1.053)
|
||||
HOMO_STORAGE = ((6, 4), [(448, 180), (1051, 180), (426, 513), (1100, 513)])
|
||||
MAP_ENSURE_EDGE_INSIGHT_CORNER = 'top'
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
|
||||
@@ -315,11 +315,12 @@
|
||||
},
|
||||
"GemsFarming": {
|
||||
"ChangeFlagship": "ship",
|
||||
"CommonCV": "any",
|
||||
"ChangeVanguard": "ship",
|
||||
"CommonDD": "any",
|
||||
"ALLowLowVanguardLevel": true,
|
||||
"FleetNumberInHardMode": 0,
|
||||
"StopIFAutoNotEnsured": true,
|
||||
"CommonCV": "any",
|
||||
"CommissionLimit": true
|
||||
},
|
||||
"FlagshipFilter": {
|
||||
|
||||
@@ -53,5 +53,5 @@ class AppManager(DeployConfig):
|
||||
Progress.UpdateAlasApp()
|
||||
return False
|
||||
|
||||
self.app_asar_replace(os.getcwd())
|
||||
Progress.UpdateAlasApp()
|
||||
# self.app_asar_replace(os.getcwd())
|
||||
# Progress.UpdateAlasApp()
|
||||
|
||||
@@ -55,7 +55,7 @@ class ConfigModel:
|
||||
|
||||
# Webui
|
||||
WebuiHost: str = "0.0.0.0"
|
||||
WebuiPort: int = 22267
|
||||
WebuiPort: int = 22367
|
||||
Language: str = "en-US"
|
||||
Theme: str = "default"
|
||||
DpiScaling: bool = True
|
||||
@@ -80,42 +80,21 @@ class DeployConfig(ConfigModel):
|
||||
self.config_template = {}
|
||||
self.read()
|
||||
|
||||
# Redirection
|
||||
if self.Repository in [
|
||||
'https://gitee.com/LmeSzinc/AzurLaneAutoScript',
|
||||
'https://gitee.com/lmeszinc/azur-lane-auto-script-mirror',
|
||||
'https://e.coding.net/llop18870/alas/AzurLaneAutoScript.git',
|
||||
'https://e.coding.net/saarcenter/alas/AzurLaneAutoScript.git',
|
||||
'https://git.saarcenter.com/LmeSzinc/AzurLaneAutoScript.git',
|
||||
]:
|
||||
self.Repository = 'git://git.lyoko.io/AzurLaneAutoScript'
|
||||
|
||||
# Bypass webui.config.DeployConfig.__setattr__()
|
||||
# Don't write these into deploy.yaml
|
||||
super().__setattr__(
|
||||
'GitOverCdn',
|
||||
self.Repository == 'git://git.lyoko.io/AzurLaneAutoScript' and self.Branch == 'master'
|
||||
)
|
||||
if self.Repository in ['global']:
|
||||
super().__setattr__('Repository', 'https://github.com/LmeSzinc/AzurLaneAutoScript')
|
||||
if self.Repository in ['cn']:
|
||||
super().__setattr__('Repository', 'git://git.lyoko.io/AzurLaneAutoScript')
|
||||
super().__setattr__('GitOverCdn', self.Repository in ['cn'])
|
||||
if self.Repository in ['global', 'cn']:
|
||||
super().__setattr__('Repository', 'https://github.com/LmeSzinc/StarRailCopilot')
|
||||
|
||||
self.write()
|
||||
self.show_config()
|
||||
|
||||
@cached_property
|
||||
def flag_feature_test_0_4_0(self):
|
||||
flag = os.path.exists('./toolkit/flag_feature_test_0_4_0')
|
||||
logger.info(f'flag_feature_test_0_4_0: {flag}')
|
||||
return flag
|
||||
|
||||
def show_config(self):
|
||||
logger.hr("Show deploy config", 1)
|
||||
for k, v in self.config.items():
|
||||
if k in ("Password", "SSHUser"):
|
||||
continue
|
||||
if self.config_template.get(k) == v:
|
||||
if self.config_template[k] == v:
|
||||
continue
|
||||
logger.info(f"{k}: {v}")
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import asyncio
|
||||
import filecmp
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import typing as t
|
||||
from dataclasses import dataclass
|
||||
|
||||
@@ -9,7 +10,8 @@ from deploy.Windows.alas import AlasManager
|
||||
from deploy.Windows.logger import logger
|
||||
from deploy.Windows.utils import cached_property
|
||||
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
||||
if sys.platform.startswith("win"):
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -2,9 +2,10 @@ import configparser
|
||||
import os
|
||||
|
||||
from deploy.Windows.config import DeployConfig
|
||||
from deploy.git_over_cdn.client import GitOverCdnClient
|
||||
from deploy.Windows.logger import Progress, logger
|
||||
from deploy.Windows.utils import *
|
||||
from deploy.Windows.utils import cached_property
|
||||
from deploy.git_over_cdn.client import GitOverCdnClient
|
||||
|
||||
|
||||
class GitConfigParser(configparser.ConfigParser):
|
||||
def check(self, section, option, value):
|
||||
@@ -16,6 +17,25 @@ class GitConfigParser(configparser.ConfigParser):
|
||||
return False
|
||||
|
||||
|
||||
class GitOverCdnClientWindows(GitOverCdnClient):
|
||||
def update(self, *args, **kwargs):
|
||||
Progress.GitInit()
|
||||
_ = super().update(*args, **kwargs)
|
||||
Progress.GitShowVersion()
|
||||
return _
|
||||
|
||||
@cached_property
|
||||
def latest_commit(self) -> str:
|
||||
_ = super().latest_commit
|
||||
Progress.GitLatestCommit()
|
||||
return _
|
||||
|
||||
def download_pack(self):
|
||||
_ = super().download_pack()
|
||||
Progress.GitDownloadPack()
|
||||
return _
|
||||
|
||||
|
||||
class GitManager(DeployConfig):
|
||||
@staticmethod
|
||||
def remove(file):
|
||||
@@ -111,7 +131,7 @@ class GitManager(DeployConfig):
|
||||
@property
|
||||
def goc_client(self):
|
||||
client = GitOverCdnClient(
|
||||
url='https://vip.123pan.cn/1818706573/pack/LmeSzinc_AzurLaneAutoScript_master',
|
||||
url='https://vip.123pan.cn/1815343254/pack/LmeSzinc_StarRailCopilot_master',
|
||||
folder=self.root_filepath,
|
||||
source='origin',
|
||||
branch='master',
|
||||
|
||||
@@ -61,6 +61,9 @@ class Progress:
|
||||
GitCheckout = Percentage(48)
|
||||
GitShowVersion = Percentage(50)
|
||||
|
||||
GitLatestCommit = Percentage(25)
|
||||
GitDownloadPack = Percentage(40)
|
||||
|
||||
KillExisting = Percentage(60)
|
||||
UpdateDependency = Percentage(70)
|
||||
UpdateAlasApp = Percentage(75)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Deploy:
|
||||
Git:
|
||||
# URL of AzurLaneAutoScript repository
|
||||
# [CN user] Use 'git://git.lyoko.io/AzurLaneAutoScript' for faster and more stable download
|
||||
# [Other] Use 'https://github.com/LmeSzinc/AzurLaneAutoScript'
|
||||
Repository: 'https://github.com/LmeSzinc/AzurLaneAutoScript'
|
||||
# [CN user] Use 'cn' to get update from git-over-cdn service
|
||||
# [Other] Use 'global' to get update from https://github.com/LmeSzinc/StarRailCopilot
|
||||
Repository: 'global'
|
||||
# Branch of Alas
|
||||
# [Developer] Use 'dev', 'app', etc, to try new features
|
||||
# [Other] Use 'master', the stable branch
|
||||
@@ -128,13 +128,14 @@ Deploy:
|
||||
WebuiHost: 0.0.0.0
|
||||
# --port. Port to listen
|
||||
# You will be able to access webui via `http://{host}:{port}`
|
||||
# [In most cases] Default to 22267
|
||||
WebuiPort: 22267
|
||||
# [In most cases] Default to 22367
|
||||
WebuiPort: 22367
|
||||
# Language to use on web ui
|
||||
# 'zh-CN' for Chinese simplified
|
||||
# 'en-US' for English
|
||||
# 'ja-JP' for Japanese
|
||||
# 'zh-TW' for Chinese traditional
|
||||
# 'es-ES' for Spanish
|
||||
Language: en-US
|
||||
# Theme of web ui
|
||||
# 'default' for light theme
|
||||
|
||||
@@ -5,21 +5,29 @@ from module.combat.assets import BATTLE_PREPARATION
|
||||
from module.equipment.assets import *
|
||||
from module.equipment.equipment_change import EquipmentChange
|
||||
from module.equipment.fleet_equipment import OCR_FLEET_INDEX
|
||||
from module.exception import CampaignEnd, RequestHumanTakeover
|
||||
from module.exception import CampaignEnd, ScriptError, RequestHumanTakeover
|
||||
from module.handler.assets import AUTO_SEARCH_MAP_OPTION_OFF
|
||||
from module.logger import logger
|
||||
from module.map.assets import (FLEET_PREPARATION, MAP_PREPARATION, FLEET_ENTER_FLAGSHIP_HARD_1,
|
||||
from module.map.assets import (FLEET_ENTER_FLAGSHIP_HARD_1,
|
||||
FLEET_ENTER_FLAGSHIP_HARD_2, FLEET_ENTER_HARD_1, FLEET_ENTER_HARD_2,
|
||||
FLEET_ENTER_FLAGSHIP_HARD_1_3, FLEET_ENTER_FLAGSHIP_HARD_2_3, FLEET_ENTER_HARD_1_3,
|
||||
FLEET_ENTER_HARD_2_3)
|
||||
from module.retire.assets import (DOCK_CHECK, TEMPLATE_BOGUE, TEMPLATE_HERMES, TEMPLATE_LANGLEY, TEMPLATE_RANGER,
|
||||
from module.retire.assets import (
|
||||
DOCK_SHIP_DOWN)
|
||||
from module.map.assets import FLEET_PREPARATION, MAP_PREPARATION
|
||||
from module.retire.assets import (
|
||||
DOCK_CHECK,
|
||||
TEMPLATE_BOGUE, TEMPLATE_HERMES, TEMPLATE_LANGLEY, TEMPLATE_RANGER,
|
||||
TEMPLATE_CASSIN_1, TEMPLATE_CASSIN_2, TEMPLATE_DOWNES_1, TEMPLATE_DOWNES_2,
|
||||
TEMPLATE_AULICK, TEMPLATE_FOOTE
|
||||
)
|
||||
|
||||
from module.retire.dock import Dock
|
||||
from module.retire.scanner import ShipScanner
|
||||
from module.ui.page import page_fleet, page_event
|
||||
from module.ui.assets import BACK_ARROW
|
||||
from module.config.config import deep_get
|
||||
import inflection
|
||||
from module.ui.page import page_fleet
|
||||
|
||||
SIM_VALUE = 0.95
|
||||
|
||||
@@ -216,6 +224,7 @@ class GemsFarming(CampaignRun, Dock, EquipmentChange):
|
||||
Returns:
|
||||
bool: True if vanguard changed
|
||||
"""
|
||||
|
||||
logger.hr('Change vanguard', level=1)
|
||||
logger.attr('ChangeVanguard', self.config.GemsFarming_ChangeVanguard)
|
||||
if self.change_vanguard_equip:
|
||||
@@ -243,7 +252,8 @@ class GemsFarming(CampaignRun, Dock, EquipmentChange):
|
||||
|
||||
self.dock_select_one(button)
|
||||
self.dock_filter_set()
|
||||
self.dock_select_confirm(check_button=self.page_fleet_check_button)
|
||||
self.dock_sort_method_dsc_set()
|
||||
self.dock_select_confirm(check_button=page_fleet.check_button)
|
||||
|
||||
def get_common_rarity_cv(self, lv=31, emotion=16):
|
||||
"""
|
||||
@@ -260,7 +270,6 @@ class GemsFarming(CampaignRun, Dock, EquipmentChange):
|
||||
scanner.disable('rarity')
|
||||
|
||||
if self.config.GemsFarming_CommonCV == 'any':
|
||||
logger.info('')
|
||||
|
||||
self.dock_sort_method_dsc_set(False)
|
||||
|
||||
@@ -326,13 +335,61 @@ class GemsFarming(CampaignRun, Dock, EquipmentChange):
|
||||
fleet=self.config.Fleet_Fleet1, status='free')
|
||||
scanner.disable('rarity')
|
||||
|
||||
self.dock_sort_method_dsc_set()
|
||||
|
||||
ships = scanner.scan(self.device.image)
|
||||
if ships:
|
||||
# Don't need to change current
|
||||
return ships
|
||||
|
||||
scanner.set_limitation(fleet=0)
|
||||
return scanner.scan(self.device.image, output=False)
|
||||
|
||||
candidates = self.find_candidates(self.get_templates(self.config.GemsFarming_CommonDD), scanner)
|
||||
|
||||
if candidates:
|
||||
return candidates
|
||||
else:
|
||||
logger.info('No specific DD was found, try reversed order.')
|
||||
return candidates
|
||||
|
||||
def find_candidates(self, template, scanner):
|
||||
"""
|
||||
Find candidates based on template matching using a scanner.
|
||||
|
||||
"""
|
||||
candidates = []
|
||||
for item in template:
|
||||
candidates = [ship for ship in scanner.scan(self.device.image, output=False)
|
||||
if item.match(self.image_crop(ship.button), similarity=SIM_VALUE)]
|
||||
if candidates:
|
||||
break
|
||||
return candidates
|
||||
|
||||
@staticmethod
|
||||
def get_templates(common_dd):
|
||||
"""
|
||||
Returns the corresponding template list based on CommonDD
|
||||
"""
|
||||
if common_dd == 'any':
|
||||
return [
|
||||
TEMPLATE_CASSIN_1, TEMPLATE_CASSIN_2,
|
||||
TEMPLATE_DOWNES_1, TEMPLATE_DOWNES_2,
|
||||
TEMPLATE_AULICK,
|
||||
TEMPLATE_FOOTE
|
||||
]
|
||||
elif common_dd == 'aulick_or_foote':
|
||||
return [
|
||||
TEMPLATE_AULICK,
|
||||
TEMPLATE_FOOTE
|
||||
]
|
||||
elif common_dd == 'cassin_or_downes':
|
||||
return [
|
||||
TEMPLATE_CASSIN_1, TEMPLATE_CASSIN_2,
|
||||
TEMPLATE_DOWNES_1, TEMPLATE_DOWNES_2
|
||||
]
|
||||
else:
|
||||
logger.error(f'Invalid CommonDD setting: {common_dd}')
|
||||
raise ScriptError(f'Invalid CommonDD setting: {common_dd}')
|
||||
|
||||
def solve_hard_flagship_black(self):
|
||||
if self.hard_mode:
|
||||
|
||||
@@ -116,7 +116,8 @@
|
||||
"aScreenCap_nc",
|
||||
"DroidCast",
|
||||
"DroidCast_raw",
|
||||
"scrcpy"
|
||||
"scrcpy",
|
||||
"nemu_ipc"
|
||||
]
|
||||
},
|
||||
"ControlMethod": {
|
||||
@@ -127,7 +128,8 @@
|
||||
"uiautomator2",
|
||||
"minitouch",
|
||||
"Hermit",
|
||||
"MaaTouch"
|
||||
"MaaTouch",
|
||||
"nemu_ipc"
|
||||
]
|
||||
},
|
||||
"ScreenshotDedithering": {
|
||||
@@ -1606,6 +1608,17 @@
|
||||
"ship_equip"
|
||||
]
|
||||
},
|
||||
"CommonCV": {
|
||||
"type": "select",
|
||||
"value": "any",
|
||||
"option": [
|
||||
"any",
|
||||
"langley",
|
||||
"bogue",
|
||||
"ranger",
|
||||
"hermes"
|
||||
]
|
||||
},
|
||||
"ChangeVanguard": {
|
||||
"type": "select",
|
||||
"value": "ship",
|
||||
@@ -1615,6 +1628,15 @@
|
||||
"ship_equip"
|
||||
]
|
||||
},
|
||||
"CommonDD": {
|
||||
"type": "select",
|
||||
"value": "any",
|
||||
"option": [
|
||||
"any",
|
||||
"aulick_or_foote",
|
||||
"cassin_or_downes"
|
||||
]
|
||||
},
|
||||
"ALLowLowVanguardLevel": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
@@ -1632,17 +1654,6 @@
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
},
|
||||
"CommonCV": {
|
||||
"type": "select",
|
||||
"value": "any",
|
||||
"option": [
|
||||
"any",
|
||||
"langley",
|
||||
"bogue",
|
||||
"ranger",
|
||||
"hermes"
|
||||
]
|
||||
},
|
||||
"CommissionLimit": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
@@ -1891,13 +1902,13 @@
|
||||
],
|
||||
"display": "hide",
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -2224,13 +2235,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -2672,13 +2683,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -4514,13 +4525,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -4979,13 +4990,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -5444,13 +5455,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -5909,13 +5920,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -6364,13 +6375,13 @@
|
||||
"event_20240229_cn"
|
||||
],
|
||||
"option_bold": [
|
||||
"event_20210422_cn",
|
||||
"event_20220324_cn"
|
||||
"event_20211111_cn",
|
||||
"event_20220224_cn"
|
||||
],
|
||||
"cn": "event_20220324_cn",
|
||||
"en": "event_20220324_cn",
|
||||
"jp": "event_20220324_cn",
|
||||
"tw": "event_20210422_cn"
|
||||
"cn": "event_20220224_cn",
|
||||
"en": "event_20220224_cn",
|
||||
"jp": "event_20220224_cn",
|
||||
"tw": "event_20211111_cn"
|
||||
},
|
||||
"Mode": {
|
||||
"type": "select",
|
||||
@@ -9835,11 +9846,9 @@
|
||||
"value": "emulator",
|
||||
"option": [
|
||||
"emulator",
|
||||
"emulator_android_12",
|
||||
"plone_cloud_with_adb",
|
||||
"phone_cloud_without_adb",
|
||||
"android_phone",
|
||||
"android_phone_12",
|
||||
"android_phone_vmos"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -32,10 +32,28 @@ Emulator:
|
||||
option: [ disabled, ]
|
||||
ScreenshotMethod:
|
||||
value: auto
|
||||
option: [ auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, scrcpy ]
|
||||
option: [
|
||||
auto,
|
||||
ADB,
|
||||
ADB_nc,
|
||||
uiautomator2,
|
||||
aScreenCap,
|
||||
aScreenCap_nc,
|
||||
DroidCast,
|
||||
DroidCast_raw,
|
||||
scrcpy,
|
||||
nemu_ipc,
|
||||
]
|
||||
ControlMethod:
|
||||
value: minitouch
|
||||
option: [ ADB, uiautomator2, minitouch, Hermit, MaaTouch ]
|
||||
option: [
|
||||
ADB,
|
||||
uiautomator2,
|
||||
minitouch,
|
||||
Hermit,
|
||||
MaaTouch,
|
||||
nemu_ipc,
|
||||
]
|
||||
ScreenshotDedithering: false
|
||||
AdbRestart: false
|
||||
EmulatorInfo:
|
||||
@@ -251,17 +269,20 @@ GemsFarming:
|
||||
ChangeFlagship:
|
||||
value: ship
|
||||
option: [ ship, ship_equip ]
|
||||
CommonCV:
|
||||
value: any
|
||||
option: [ any, langley, bogue, ranger, hermes ]
|
||||
ChangeVanguard:
|
||||
value: ship
|
||||
option: [ disabled, ship, ship_equip ]
|
||||
CommonDD:
|
||||
value: any
|
||||
option: [ any, aulick_or_foote , cassin_or_downes ]
|
||||
ALLowLowVanguardLevel: true
|
||||
FleetNumberInHardMode:
|
||||
value: 0
|
||||
option: [ 0, 1, 2 ]
|
||||
StopIFAutoNotEnsured: true
|
||||
CommonCV:
|
||||
value: any
|
||||
option: [ any, langley, bogue, ranger, hermes ]
|
||||
CommissionLimit: true
|
||||
FlagshipFilter:
|
||||
Sort:
|
||||
@@ -732,9 +753,11 @@ Benchmark:
|
||||
DeviceType:
|
||||
value: emulator
|
||||
option: [
|
||||
emulator, emulator_android_12,
|
||||
plone_cloud_with_adb, phone_cloud_without_adb,
|
||||
android_phone, android_phone_12, android_phone_vmos
|
||||
emulator,
|
||||
plone_cloud_with_adb,
|
||||
phone_cloud_without_adb,
|
||||
android_phone,
|
||||
android_phone_vmos,
|
||||
]
|
||||
TestScene:
|
||||
value: screenshot_click
|
||||
|
||||
@@ -21,8 +21,8 @@ class GeneratedConfig:
|
||||
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.nearme.gamecenter, com.bilibili.blhx.vivo, com.bilibili.blhx.mz, com.bilibili.blhx.dl, com.bilibili.blhx.lenovo, com.bilibili.blhx.uc, com.bilibili.blhx.mzw, com.yiwu.blhx.yx15, com.bilibili.blhx.m4399, com.bilibili.blhx.bilibiliMove, 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_android-22, cn_android-23, 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, cn_channel-4, en-0, en-1, en-2, en-3, en-4, en-5, jp-0, jp-1, jp-2, jp-3, jp-4, jp-5, jp-6, jp-7, jp-8, jp-9, jp-10, jp-11, jp-12, jp-13, jp-14, jp-15, jp-16, jp-17
|
||||
Emulator_ScreenshotMethod = 'auto' # auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, scrcpy
|
||||
Emulator_ControlMethod = 'minitouch' # ADB, uiautomator2, minitouch, Hermit, MaaTouch
|
||||
Emulator_ScreenshotMethod = 'auto' # auto, ADB, ADB_nc, uiautomator2, aScreenCap, aScreenCap_nc, DroidCast, DroidCast_raw, scrcpy, nemu_ipc
|
||||
Emulator_ControlMethod = 'minitouch' # ADB, uiautomator2, minitouch, Hermit, MaaTouch, nemu_ipc
|
||||
Emulator_ScreenshotDedithering = False
|
||||
Emulator_AdbRestart = False
|
||||
|
||||
@@ -154,6 +154,7 @@ class GeneratedConfig:
|
||||
GemsFarming_FleetNumberInHardMode = 0 # 0, 1, 2
|
||||
GemsFarming_StopIFAutoNotEnsured = True
|
||||
GemsFarming_CommonCV = 'any' # any, langley, bogue, ranger, hermes
|
||||
GemsFarming_CommonDD = 'any' # any, aulick_or_foote, cassin_or_downes
|
||||
GemsFarming_CommissionLimit = True
|
||||
|
||||
# Group `FlagshipFilter`
|
||||
@@ -448,7 +449,7 @@ class GeneratedConfig:
|
||||
OpsiDaemon_SelectEnemy = True
|
||||
|
||||
# Group `Benchmark`
|
||||
Benchmark_DeviceType = 'emulator' # emulator, emulator_android_12, plone_cloud_with_adb, phone_cloud_without_adb, android_phone, android_phone_12, android_phone_vmos
|
||||
Benchmark_DeviceType = 'emulator' # emulator, plone_cloud_with_adb, phone_cloud_without_adb, android_phone, android_phone_vmos
|
||||
Benchmark_TestScene = 'screenshot_click' # screenshot_click, screenshot, click
|
||||
|
||||
# Group `AzurLaneUncensored`
|
||||
|
||||
@@ -755,6 +755,11 @@ class ConfigUpdater:
|
||||
key = key.split(".")
|
||||
key[-1] = key[-1].replace("Value", "Record")
|
||||
yield ".".join(key), datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
# Oh no, dynamic dropdown update can only be used on pywebio > 1.8.0
|
||||
# elif key == 'Alas.Emulator.ScreenshotMethod' and value == 'nemu_ipc':
|
||||
# yield 'Alas.Emulator.ControlMethod', 'nemu_ipc'
|
||||
# elif key == 'Alas.Emulator.ControlMethod' and value == 'nemu_ipc':
|
||||
# yield 'Alas.Emulator.ScreenshotMethod', 'nemu_ipc'
|
||||
|
||||
def read_file(self, config_name, is_template=False):
|
||||
"""
|
||||
|
||||
@@ -417,7 +417,8 @@
|
||||
"aScreenCap_nc": "aScreenCap_nc",
|
||||
"DroidCast": "DroidCast",
|
||||
"DroidCast_raw": "DroidCast_raw",
|
||||
"scrcpy": "scrcpy"
|
||||
"scrcpy": "scrcpy",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ControlMethod": {
|
||||
"name": "Control Method",
|
||||
@@ -426,7 +427,8 @@
|
||||
"uiautomator2": "uiautomator2",
|
||||
"minitouch": "minitouch",
|
||||
"Hermit": "Hermit",
|
||||
"MaaTouch": "MaaTouch"
|
||||
"MaaTouch": "MaaTouch",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ScreenshotDedithering": {
|
||||
"name": "Image Color De-dithering",
|
||||
@@ -709,7 +711,7 @@
|
||||
"event_20211125_cn": "World-spanning Arclight Rerun",
|
||||
"event_20211229_cn": "Tower of Transcendence Rerun",
|
||||
"event_20220210_cn": "Northern Overture Rerun",
|
||||
"event_20220224_cn": "Abyssal Refrain",
|
||||
"event_20220224_cn": "Abyssal Refrain Rerun",
|
||||
"event_20220310_tw": "復刻斯圖爾特的硝煙",
|
||||
"event_20220324_cn": "Virtual Tower Rerun",
|
||||
"event_20220407_tw": "蒼紅的迴響(復刻)",
|
||||
@@ -1140,6 +1142,15 @@
|
||||
"ship": "Change Ship",
|
||||
"ship_equip": "Change Ship + Gears"
|
||||
},
|
||||
"CommonCV": {
|
||||
"name": "Flagship Common CV/CVL Preference",
|
||||
"help": "",
|
||||
"any": "any",
|
||||
"langley": "langley",
|
||||
"bogue": "bogue",
|
||||
"ranger": "ranger",
|
||||
"hermes": "hermes"
|
||||
},
|
||||
"ChangeVanguard": {
|
||||
"name": "Change Vanguard",
|
||||
"help": "Change vanguard if flagship or vanguard are emotion exhausted.If you choose not to change, your fleet will ignore the low emotion warning and continue combat.\nSwitch out to new level 100(70) common vanguard after current flagship has reached level 32+ (Only CN players'0 limit break ship can reach level 100)\n\nThe vanguard's equipment is replaced when being switched out by first recording the current setup. Only populated equipment slots will be replaced.",
|
||||
@@ -1162,14 +1173,12 @@
|
||||
"name": "GemsFarming.StopIFAutoNotEnsured.name",
|
||||
"help": "GemsFarming.StopIFAutoNotEnsured.help"
|
||||
},
|
||||
"CommonCV": {
|
||||
"name": "Flagship Common CV/CVL Preference",
|
||||
"CommonDD": {
|
||||
"name": "Flagship Common DD Preference",
|
||||
"help": "",
|
||||
"any": "any",
|
||||
"langley": "langley",
|
||||
"bogue": "bogue",
|
||||
"ranger": "ranger",
|
||||
"hermes": "hermes"
|
||||
"aulick_or_foote": "aulick or foote",
|
||||
"cassin_or_downes": "cassin or downes"
|
||||
},
|
||||
"CommissionLimit": {
|
||||
"name": "Prevent Too Many Urgent Commissions",
|
||||
@@ -2629,13 +2638,11 @@
|
||||
"DeviceType": {
|
||||
"name": "Device Type",
|
||||
"help": "",
|
||||
"emulator": "Emulator (Android <= 9)",
|
||||
"emulator_android_12": "Emulator (Android > 9)",
|
||||
"plone_cloud_with_adb": "Phone cloud with public network ADB",
|
||||
"phone_cloud_without_adb": "Phone cloud without public network ADB",
|
||||
"android_phone": "Android Phone (Android <= 9)",
|
||||
"android_phone_12": "Android Phone (Android > 9)",
|
||||
"android_phone_vmos": "Android Phone (VMOS emulator)"
|
||||
"emulator": "Emulators",
|
||||
"plone_cloud_with_adb": "Phone clouds with public network ADB",
|
||||
"phone_cloud_without_adb": "Phone clouds without public network ADB",
|
||||
"android_phone": "Android Phones",
|
||||
"android_phone_vmos": "Android Phones (VMOS emulator)"
|
||||
},
|
||||
"TestScene": {
|
||||
"name": "Test Scene",
|
||||
|
||||
@@ -417,7 +417,8 @@
|
||||
"aScreenCap_nc": "aScreenCap_nc",
|
||||
"DroidCast": "DroidCast",
|
||||
"DroidCast_raw": "DroidCast_raw",
|
||||
"scrcpy": "scrcpy"
|
||||
"scrcpy": "scrcpy",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ControlMethod": {
|
||||
"name": "Emulator.ControlMethod.name",
|
||||
@@ -426,7 +427,8 @@
|
||||
"uiautomator2": "uiautomator2",
|
||||
"minitouch": "minitouch",
|
||||
"Hermit": "Hermit",
|
||||
"MaaTouch": "MaaTouch"
|
||||
"MaaTouch": "MaaTouch",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ScreenshotDedithering": {
|
||||
"name": "Emulator.ScreenshotDedithering.name",
|
||||
@@ -709,7 +711,7 @@
|
||||
"event_20211125_cn": "弧光は交わる世界にて(復刻)",
|
||||
"event_20211229_cn": "遡望せし虹彩の塔(復刻)",
|
||||
"event_20220210_cn": "凍絶の北海(復刻)",
|
||||
"event_20220224_cn": "鳴動せし星霜の淵",
|
||||
"event_20220224_cn": "鳴動せし星霜の淵(復刻)",
|
||||
"event_20220310_tw": "復刻斯圖爾特的硝煙",
|
||||
"event_20220324_cn": "幻像の塔(復刻)",
|
||||
"event_20220407_tw": "蒼紅的迴響(復刻)",
|
||||
@@ -1140,13 +1142,6 @@
|
||||
"ship": "ship",
|
||||
"ship_equip": "ship_equip"
|
||||
},
|
||||
"ChangeVanguard": {
|
||||
"name": "GemsFarming.ChangeVanguard.name",
|
||||
"help": "GemsFarming.ChangeVanguard.help",
|
||||
"disabled": "disabled",
|
||||
"ship": "ship",
|
||||
"ship_equip": "ship_equip"
|
||||
},
|
||||
"ALLowLowVanguardLevel": {
|
||||
"name": "GemsFarming.ALLowLowVanguardLevel.name",
|
||||
"help": "GemsFarming.ALLowLowVanguardLevel.help"
|
||||
@@ -1171,6 +1166,20 @@
|
||||
"ranger": "ranger",
|
||||
"hermes": "hermes"
|
||||
},
|
||||
"ChangeVanguard": {
|
||||
"name": "GemsFarming.ChangeVanguard.name",
|
||||
"help": "GemsFarming.ChangeVanguard.help",
|
||||
"disabled": "disabled",
|
||||
"ship": "ship",
|
||||
"ship_equip": "ship_equip"
|
||||
},
|
||||
"CommonDD": {
|
||||
"name": "GemsFarming.CommonDD.name",
|
||||
"help": "GemsFarming.CommonDD.help",
|
||||
"any": "any",
|
||||
"aulick_or_foote": "aulick or foote",
|
||||
"cassin_or_downes": "cassin or downes"
|
||||
},
|
||||
"CommissionLimit": {
|
||||
"name": "GemsFarming.CommissionLimit.name",
|
||||
"help": "GemsFarming.CommissionLimit.help"
|
||||
@@ -2630,11 +2639,9 @@
|
||||
"name": "Benchmark.DeviceType.name",
|
||||
"help": "Benchmark.DeviceType.help",
|
||||
"emulator": "emulator",
|
||||
"emulator_android_12": "emulator_android_12",
|
||||
"plone_cloud_with_adb": "plone_cloud_with_adb",
|
||||
"phone_cloud_without_adb": "phone_cloud_without_adb",
|
||||
"android_phone": "android_phone",
|
||||
"android_phone_12": "android_phone_12",
|
||||
"android_phone_vmos": "android_phone_vmos"
|
||||
},
|
||||
"TestScene": {
|
||||
|
||||
@@ -417,7 +417,8 @@
|
||||
"aScreenCap_nc": "aScreenCap_nc",
|
||||
"DroidCast": "DroidCast",
|
||||
"DroidCast_raw": "DroidCast_raw",
|
||||
"scrcpy": "scrcpy"
|
||||
"scrcpy": "scrcpy",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ControlMethod": {
|
||||
"name": "模拟器控制方案",
|
||||
@@ -426,7 +427,8 @@
|
||||
"uiautomator2": "uiautomator2",
|
||||
"minitouch": "minitouch",
|
||||
"Hermit": "Hermit",
|
||||
"MaaTouch": "MaaTouch"
|
||||
"MaaTouch": "MaaTouch",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ScreenshotDedithering": {
|
||||
"name": "去除图片色彩抖动",
|
||||
@@ -709,7 +711,7 @@
|
||||
"event_20211125_cn": "复刻交汇世界的弧光",
|
||||
"event_20211229_cn": "复刻逆转彩虹之塔",
|
||||
"event_20220210_cn": "复刻北境序曲",
|
||||
"event_20220224_cn": "深度回音",
|
||||
"event_20220224_cn": "复刻深度回音",
|
||||
"event_20220310_tw": "復刻斯圖爾特的硝煙",
|
||||
"event_20220324_cn": "复刻虚像构筑之塔",
|
||||
"event_20220407_tw": "蒼紅的迴響(復刻)",
|
||||
@@ -1140,6 +1142,15 @@
|
||||
"ship": "更换舰船",
|
||||
"ship_equip": "更换舰船 + 装备"
|
||||
},
|
||||
"CommonCV": {
|
||||
"name": "指定旗舰航母",
|
||||
"help": "",
|
||||
"any": "任意",
|
||||
"langley": "兰利",
|
||||
"bogue": "博格",
|
||||
"ranger": "突击者",
|
||||
"hermes": "竞技神"
|
||||
},
|
||||
"ChangeVanguard": {
|
||||
"name": "更换前排",
|
||||
"help": "当前排红脸时更换前排,选择不更换则会强制红脸出击\n换前排通过找一艘心情不低于16、等级100的白鹰白皮驱逐完成,所以尽量保证有足够多的驱逐。国服以外则为等级70的白鹰白船驱逐。\n\n换装备只会更换正在装备中的栏位,即使是白装也会更换。如果指定了旗舰,则会更换全部5个装备,未指定旗舰只会更换设备。",
|
||||
@@ -1162,14 +1173,12 @@
|
||||
"name": "无法设置职能时停止任务",
|
||||
"help": "无法设置舰队职能时,以以下方式停止任务以免跨队队伍出击,石油被大量消耗:\n若设置了错误推送则推送任务停止的消息并停止该任务。\n若没有设置错误推送,则直接停止Alas。"
|
||||
},
|
||||
"CommonCV": {
|
||||
"name": "指定旗舰航母",
|
||||
"CommonDD": {
|
||||
"name": "指定前排",
|
||||
"help": "",
|
||||
"any": "任意",
|
||||
"langley": "兰利",
|
||||
"bogue": "博格",
|
||||
"ranger": "突击者",
|
||||
"hermes": "竞技神"
|
||||
"aulick_or_foote": "奥利克或富特",
|
||||
"cassin_or_downes": "卡辛或唐斯"
|
||||
},
|
||||
"CommissionLimit": {
|
||||
"name": "防止紧急委托数量过多",
|
||||
@@ -2629,12 +2638,10 @@
|
||||
"DeviceType": {
|
||||
"name": "设备类型",
|
||||
"help": "",
|
||||
"emulator": "模拟器 安卓<=9",
|
||||
"emulator_android_12": "模拟器 安卓>9",
|
||||
"emulator": "模拟器",
|
||||
"plone_cloud_with_adb": "云手机 有公网ADB",
|
||||
"phone_cloud_without_adb": "云手机 无公网ADB",
|
||||
"android_phone": "安卓真机 安卓<=9",
|
||||
"android_phone_12": "安卓真机 安卓>9",
|
||||
"android_phone": "安卓真机",
|
||||
"android_phone_vmos": "安卓真机VMOS虚拟机"
|
||||
},
|
||||
"TestScene": {
|
||||
|
||||
@@ -417,7 +417,8 @@
|
||||
"aScreenCap_nc": "aScreenCap_nc",
|
||||
"DroidCast": "DroidCast",
|
||||
"DroidCast_raw": "DroidCast_raw",
|
||||
"scrcpy": "scrcpy"
|
||||
"scrcpy": "scrcpy",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ControlMethod": {
|
||||
"name": "模擬器控制方案",
|
||||
@@ -426,7 +427,8 @@
|
||||
"uiautomator2": "uiautomator2",
|
||||
"minitouch": "minitouch",
|
||||
"Hermit": "Hermit",
|
||||
"MaaTouch": "MaaTouch"
|
||||
"MaaTouch": "MaaTouch",
|
||||
"nemu_ipc": "nemu_ipc"
|
||||
},
|
||||
"ScreenshotDedithering": {
|
||||
"name": "去除圖片色彩抖動",
|
||||
@@ -705,7 +707,7 @@
|
||||
"event_20210916_cn": "碧海光粼",
|
||||
"event_20211028_cn": "復刻穹頂下的聖詠曲",
|
||||
"event_20211028_tw": "復刻光與影的鳶尾之華",
|
||||
"event_20211111_cn": "杰諾瓦的焰火",
|
||||
"event_20211111_cn": "復刻杰諾瓦的焰火",
|
||||
"event_20211125_cn": "復刻-交匯世界的弧光",
|
||||
"event_20211229_cn": "逆轉彩虹之塔",
|
||||
"event_20220210_cn": "復刻北境序曲",
|
||||
@@ -1140,6 +1142,15 @@
|
||||
"ship": "更換艦船",
|
||||
"ship_equip": "更換艦船 + 裝備"
|
||||
},
|
||||
"CommonCV": {
|
||||
"name": "指定旗艦航母",
|
||||
"help": "",
|
||||
"any": "任意",
|
||||
"langley": "蘭利",
|
||||
"bogue": "博格",
|
||||
"ranger": "突擊者",
|
||||
"hermes": "競技神"
|
||||
},
|
||||
"ChangeVanguard": {
|
||||
"name": "更換前排",
|
||||
"help": "當前排紅臉時更換前排,選擇不更換則會強制紅臉出擊\n換前排通過找一艘心情不低於16、等級70的白鷹白船驅逐完成,所以盡量保證有足夠多的驅逐。國服則為等級100的白鷹白船驅逐。\n\n換裝備只會更換正在裝備中的欄位,即使是白裝也會更換。如果指定了旗艦,則會更換全部5個裝備,未指定旗艦隻會更換設備。",
|
||||
@@ -1162,14 +1173,12 @@
|
||||
"name": "GemsFarming.StopIFAutoNotEnsured.name",
|
||||
"help": "GemsFarming.StopIFAutoNotEnsured.help"
|
||||
},
|
||||
"CommonCV": {
|
||||
"name": "指定旗艦航母",
|
||||
"CommonDD": {
|
||||
"name": "指定前排",
|
||||
"help": "",
|
||||
"any": "任意",
|
||||
"langley": "蘭利",
|
||||
"bogue": "博格",
|
||||
"ranger": "突擊者",
|
||||
"hermes": "競技神"
|
||||
"aulick_or_foote": "奧利克或富特",
|
||||
"cassin_or_downes": "卡辛或唐斯"
|
||||
},
|
||||
"CommissionLimit": {
|
||||
"name": "防止緊急委託數量過多",
|
||||
@@ -2629,12 +2638,10 @@
|
||||
"DeviceType": {
|
||||
"name": "設備類型",
|
||||
"help": "",
|
||||
"emulator": "模擬器 安卓<=9",
|
||||
"emulator_android_12": "模擬器 安卓>9",
|
||||
"emulator": "模擬器",
|
||||
"plone_cloud_with_adb": "雲手機 有公網ADB",
|
||||
"phone_cloud_without_adb": "雲手機 無公網ADB",
|
||||
"android_phone": "安卓真機 安卓<=9",
|
||||
"android_phone_12": "安卓真機 安卓>9",
|
||||
"android_phone": "安卓真機",
|
||||
"android_phone_vmos": "安卓真機VMOS虛擬機"
|
||||
},
|
||||
"TestScene": {
|
||||
|
||||
@@ -69,17 +69,19 @@ class Benchmark(DaemonBase, CampaignUI):
|
||||
if not isinstance(cost, (float, int)):
|
||||
return Text(cost, style="bold bright_red")
|
||||
|
||||
if cost < 0.10:
|
||||
if cost < 0.025:
|
||||
return Text('Insane Fast', style="bold bright_green")
|
||||
if cost < 0.100:
|
||||
return Text('Ultra Fast', style="bold bright_green")
|
||||
if cost < 0.20:
|
||||
if cost < 0.200:
|
||||
return Text('Very Fast', style="bright_green")
|
||||
if cost < 0.30:
|
||||
if cost < 0.300:
|
||||
return Text('Fast', style="green")
|
||||
if cost < 0.50:
|
||||
if cost < 0.500:
|
||||
return Text('Medium', style="yellow")
|
||||
if cost < 0.75:
|
||||
if cost < 0.750:
|
||||
return Text('Slow', style="red")
|
||||
if cost < 1.00:
|
||||
if cost < 1.000:
|
||||
return Text('Very Slow', style="bright_red")
|
||||
return Text('Ultra Slow', style="bold bright_red")
|
||||
|
||||
@@ -88,11 +90,11 @@ class Benchmark(DaemonBase, CampaignUI):
|
||||
if not isinstance(cost, (float, int)):
|
||||
return Text(cost, style="bold bright_red")
|
||||
|
||||
if cost < 0.1:
|
||||
if cost < 0.100:
|
||||
return Text('Fast', style="bright_green")
|
||||
if cost < 0.2:
|
||||
if cost < 0.200:
|
||||
return Text('Medium', style="yellow")
|
||||
if cost < 0.4:
|
||||
if cost < 0.400:
|
||||
return Text('Slow', style="red")
|
||||
return Text('Very Slow', style="bright_red")
|
||||
|
||||
@@ -178,7 +180,9 @@ class Benchmark(DaemonBase, CampaignUI):
|
||||
return [l for l in screenshot if l not in args]
|
||||
|
||||
# No ascreencap on Android > 9
|
||||
if device in ['emulator_android_12', 'android_phone_12']:
|
||||
sdk = self.device.sdk_ver
|
||||
logger.info(f'sdk_ver: {sdk}')
|
||||
if not (21 <= sdk <= 28):
|
||||
screenshot = remove('aScreenCap', 'aScreenCap_nc')
|
||||
# No nc loopback
|
||||
if device in ['plone_cloud_with_adb']:
|
||||
@@ -187,6 +191,8 @@ class Benchmark(DaemonBase, CampaignUI):
|
||||
if device == 'android_phone_vmos':
|
||||
screenshot = ['ADB', 'aScreenCap', 'DroidCast', 'DroidCast_raw']
|
||||
click = ['ADB', 'Hermit', 'MaaTouch']
|
||||
if self.device.nemu_ipc_available():
|
||||
screenshot.append('nemu_ipc')
|
||||
|
||||
scene = self.config.Benchmark_TestScene
|
||||
if 'screenshot' not in scene:
|
||||
@@ -223,6 +229,8 @@ class Benchmark(DaemonBase, CampaignUI):
|
||||
screenshot = remove('aScreenCap', 'aScreenCap_nc')
|
||||
if self.device.is_chinac_phone_cloud:
|
||||
screenshot = remove('ADB_nc', 'aScreenCap_nc')
|
||||
if self.device.nemu_ipc_available():
|
||||
screenshot.append('nemu_ipc')
|
||||
screenshot = tuple(screenshot)
|
||||
|
||||
self.TEST_TOTAL = 3
|
||||
|
||||
@@ -9,7 +9,7 @@ from module.logger import logger
|
||||
|
||||
class AppControl(Adb, WSA, Uiautomator2):
|
||||
hierarchy: etree._Element
|
||||
_app_u2_family = ['uiautomator2', 'minitouch', 'scrcpy', 'MaaTouch']
|
||||
_app_u2_family = ['uiautomator2', 'minitouch', 'scrcpy', 'MaaTouch', 'nemu_ipc']
|
||||
|
||||
def app_is_running(self) -> bool:
|
||||
method = self.config.Emulator_ControlMethod
|
||||
|
||||
@@ -11,7 +11,7 @@ import uiautomator2 as u2
|
||||
from adbutils import AdbClient, AdbDevice, AdbTimeout, ForwardItem, ReverseItem
|
||||
from adbutils.errors import AdbError
|
||||
|
||||
from module.base.decorator import Config, cached_property, del_cached_property
|
||||
from module.base.decorator import Config, cached_property, del_cached_property, run_once
|
||||
from module.base.utils import ensure_time
|
||||
from module.config.server import VALID_CHANNEL_PACKAGE, VALID_PACKAGE, set_server
|
||||
from module.device.connection_attr import ConnectionAttr
|
||||
@@ -266,15 +266,20 @@ class Connection(ConnectionAttr):
|
||||
return True
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def nemud_app_keep_alive(self) -> str:
|
||||
res = self.adb_getprop('nemud.app_keep_alive')
|
||||
logger.attr('nemud.app_keep_alive', res)
|
||||
return res
|
||||
|
||||
@retry
|
||||
def check_mumu_app_keep_alive(self):
|
||||
if not self.is_mumu_family:
|
||||
return False
|
||||
|
||||
res = self.adb_getprop('nemud.app_keep_alive')
|
||||
logger.attr('nemud.app_keep_alive', res)
|
||||
res = self.nemud_app_keep_alive
|
||||
if res == '':
|
||||
# Empry property, might not be a mumu emulator or might be an old mumu
|
||||
# Empty property, probably MuMu6 or MuMu12 version < 3.5.6
|
||||
return True
|
||||
elif res == 'false':
|
||||
# Disabled
|
||||
@@ -287,6 +292,15 @@ class Connection(ConnectionAttr):
|
||||
logger.warning(f'Invalid nemud.app_keep_alive value: {res}')
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def is_mumu_over_version_356(self) -> bool:
|
||||
"""
|
||||
Returns:
|
||||
bool: If MuMu12 version >= 3.5.6,
|
||||
which has nemud.app_keep_alive and always be a vertical device
|
||||
"""
|
||||
return self.nemud_app_keep_alive != ''
|
||||
|
||||
@cached_property
|
||||
def _nc_server_host_port(self):
|
||||
"""
|
||||
@@ -752,23 +766,42 @@ class Connection(ConnectionAttr):
|
||||
If serial=='auto' and only 1 device detected, use it
|
||||
"""
|
||||
logger.hr('Detect device')
|
||||
logger.info('Here are the available devices, '
|
||||
'copy to Alas.Emulator.Serial to use it or set Alas.Emulator.Serial="auto"')
|
||||
devices = self.list_device()
|
||||
available = SelectedGrids([])
|
||||
devices = SelectedGrids([])
|
||||
|
||||
# Show available devices
|
||||
available = devices.select(status='device')
|
||||
for device in available:
|
||||
logger.info(device.serial)
|
||||
if not len(available):
|
||||
logger.info('No available devices')
|
||||
@run_once
|
||||
def brute_force_connect():
|
||||
logger.info('Brute force connect')
|
||||
from deploy.Windows.emulator import EmulatorManager
|
||||
manager = EmulatorManager()
|
||||
manager.brute_force_connect()
|
||||
|
||||
# Show unavailable devices if having any
|
||||
unavailable = devices.delete(available)
|
||||
if len(unavailable):
|
||||
logger.info('Here are the devices detected but unavailable')
|
||||
for device in unavailable:
|
||||
logger.info(f'{device.serial} ({device.status})')
|
||||
for _ in range(2):
|
||||
logger.info('Here are the available devices, '
|
||||
'copy to Alas.Emulator.Serial to use it or set Alas.Emulator.Serial="auto"')
|
||||
devices = self.list_device()
|
||||
|
||||
# Show available devices
|
||||
available = devices.select(status='device')
|
||||
for device in available:
|
||||
logger.info(device.serial)
|
||||
if not len(available):
|
||||
logger.info('No available devices')
|
||||
|
||||
# Show unavailable devices if having any
|
||||
unavailable = devices.delete(available)
|
||||
if len(unavailable):
|
||||
logger.info('Here are the devices detected but unavailable')
|
||||
for device in unavailable:
|
||||
logger.info(f'{device.serial} ({device.status})')
|
||||
|
||||
# brute_force_connect
|
||||
if self.config.Emulator_Serial == 'auto' and available.count == 0:
|
||||
logger.warning(f'No available device found')
|
||||
brute_force_connect()
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
# Auto device detection
|
||||
if self.config.Emulator_Serial == 'auto':
|
||||
@@ -822,6 +855,36 @@ class Connection(ConnectionAttr):
|
||||
f'Using serial: {emu_serial}')
|
||||
self.serial = emu_serial
|
||||
|
||||
# Redirect MuMu12 from 127.0.0.1:7555 to 127.0.0.1:16xxx
|
||||
if self.serial == '127.0.0.1:7555':
|
||||
for _ in range(2):
|
||||
mumu12 = available.select(may_mumu12_family=True)
|
||||
if mumu12.count == 1:
|
||||
emu_serial = mumu12.first_or_none().serial
|
||||
logger.warning(f'Redirect MuMu12 {self.serial} to {emu_serial}')
|
||||
self.serial = emu_serial
|
||||
self.config.Emulator_Serial = emu_serial
|
||||
break
|
||||
elif mumu12.count >= 2:
|
||||
logger.warning(f'Multiple MuMu12 serial found, cannot redirect')
|
||||
break
|
||||
else:
|
||||
# Only 127.0.0.1:7555
|
||||
if self.is_mumu_over_version_356:
|
||||
logger.warning(f'Device {self.serial} is MuMu12 but corresponding port not found')
|
||||
brute_force_connect()
|
||||
devices = self.list_device()
|
||||
# Show available devices
|
||||
available = devices.select(status='device')
|
||||
for device in available:
|
||||
logger.info(device.serial)
|
||||
if not len(available):
|
||||
logger.info('No available devices')
|
||||
continue
|
||||
else:
|
||||
# MuMu6
|
||||
break
|
||||
|
||||
@retry
|
||||
def list_package(self, show_log=True):
|
||||
"""
|
||||
|
||||
@@ -146,7 +146,12 @@ class ConnectionAttr:
|
||||
def is_mumu_family(self):
|
||||
# 127.0.0.1:7555
|
||||
# 127.0.0.1:16384 + 32*n
|
||||
return self.serial == '127.0.0.1:7555' or self.serial.startswith('127.0.0.1:16')
|
||||
return self.serial == '127.0.0.1:7555' or self.is_mumu12_family
|
||||
|
||||
@cached_property
|
||||
def is_mumu12_family(self):
|
||||
# 127.0.0.1:16384 + 32*n
|
||||
return len(self.serial) == 15 and self.serial.startswith('127.0.0.1:16')
|
||||
|
||||
@cached_property
|
||||
def is_emulator(self):
|
||||
|
||||
@@ -5,11 +5,12 @@ from module.base.utils import *
|
||||
from module.device.method.hermit import Hermit
|
||||
from module.device.method.maatouch import MaaTouch
|
||||
from module.device.method.minitouch import Minitouch
|
||||
from module.device.method.nemu_ipc import NemuIpc
|
||||
from module.device.method.scrcpy import Scrcpy
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
||||
class Control(Hermit, Minitouch, Scrcpy, MaaTouch, NemuIpc):
|
||||
def handle_control_check(self, button):
|
||||
# Will be overridden in Device
|
||||
pass
|
||||
@@ -22,6 +23,7 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
||||
'minitouch': self.click_minitouch,
|
||||
'Hermit': self.click_hermit,
|
||||
'MaaTouch': self.click_maatouch,
|
||||
'nemu_ipc': self.click_nemu_ipc,
|
||||
}
|
||||
|
||||
def click(self, button, control_check=True):
|
||||
@@ -78,6 +80,8 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
||||
self.long_click_scrcpy(x, y, duration)
|
||||
elif method == 'MaaTouch':
|
||||
self.long_click_maatouch(x, y, duration)
|
||||
elif method == 'nemu_ipc':
|
||||
self.long_click_nemu_ipc(x, y, duration)
|
||||
else:
|
||||
self.swipe_adb((x, y), (x, y), duration)
|
||||
|
||||
@@ -86,13 +90,9 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
||||
p1, p2 = ensure_int(p1, p2)
|
||||
duration = ensure_time(duration)
|
||||
method = self.config.Emulator_ControlMethod
|
||||
if method == 'minitouch':
|
||||
logger.info('Swipe %s -> %s' % (point2str(*p1), point2str(*p2)))
|
||||
elif method == 'uiautomator2':
|
||||
if method == 'uiautomator2':
|
||||
logger.info('Swipe %s -> %s, %s' % (point2str(*p1), point2str(*p2), duration))
|
||||
elif method == 'scrcpy':
|
||||
logger.info('Swipe %s -> %s' % (point2str(*p1), point2str(*p2)))
|
||||
elif method == 'MaaTouch':
|
||||
elif method in ['minitouch', 'MaaTouch', 'scrcpy', 'nemu_ipc']:
|
||||
logger.info('Swipe %s -> %s' % (point2str(*p1), point2str(*p2)))
|
||||
else:
|
||||
# ADB needs to be slow, or swipe doesn't work
|
||||
@@ -114,6 +114,8 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
||||
self.swipe_scrcpy(p1, p2)
|
||||
elif method == 'MaaTouch':
|
||||
self.swipe_maatouch(p1, p2)
|
||||
elif method == 'nemu_ipc':
|
||||
self.swipe_nemu_ipc(p1, p2)
|
||||
else:
|
||||
self.swipe_adb(p1, p2, duration=duration)
|
||||
|
||||
@@ -163,8 +165,10 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
||||
self.drag_scrcpy(p1, p2, point_random=point_random)
|
||||
elif method == 'MaaTouch':
|
||||
self.drag_maatouch(p1, p2, point_random=point_random)
|
||||
elif method == 'nemu_ipc':
|
||||
self.drag_nemu_ipc(p1, p2, point_random=point_random)
|
||||
else:
|
||||
logger.warning(f'Control method {method} does not support drag well, '
|
||||
f'falling back to ADB swipe may cause unexpected behaviour')
|
||||
self.swipe_adb(p1, p2, duration=ensure_time(swipe_duration * 2))
|
||||
self.click(Button(area=(), color=(), button=area_offset(point_random, p2), name=name ),False)
|
||||
self.click(Button(area=(), color=(), button=area_offset(point_random, p2), name=name), False)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import collections
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from module.base.timer import Timer
|
||||
@@ -17,11 +16,6 @@ from module.exception import (
|
||||
from module.handler.assets import GET_MISSION
|
||||
from module.logger import logger
|
||||
|
||||
if sys.platform == 'win32':
|
||||
from module.device.platform.platform_windows import PlatformWindows as Platform
|
||||
else:
|
||||
from module.device.platform.platform_base import PlatformBase as Platform
|
||||
|
||||
|
||||
def show_function_call():
|
||||
"""
|
||||
@@ -63,7 +57,7 @@ def show_function_call():
|
||||
logger.info('Function calls:' + ''.join(func_list))
|
||||
|
||||
|
||||
class Device(Screenshot, Control, AppControl, Platform):
|
||||
class Device(Screenshot, Control, AppControl):
|
||||
_screen_size_checked = False
|
||||
detect_record = set()
|
||||
click_record = collections.deque(maxlen=15)
|
||||
@@ -87,12 +81,13 @@ class Device(Screenshot, Control, AppControl, Platform):
|
||||
)
|
||||
raise
|
||||
|
||||
self.screenshot_interval_set()
|
||||
# Auto-fill emulator info
|
||||
if self.config.EmulatorInfo_Emulator == 'auto':
|
||||
_ = self.emulator_instance
|
||||
|
||||
self.screenshot_interval_set()
|
||||
self.method_check()
|
||||
|
||||
# Temp fix for MuMu 12 before DroidCast updated
|
||||
if self.is_mumu_family:
|
||||
logger.info('Patching screenshot method for mumu')
|
||||
self.config.override(Emulator_ScreenshotMethod='ADB_nc')
|
||||
# Auto-select the fastest screenshot method
|
||||
if not self.config.is_template_config and self.config.Emulator_ScreenshotMethod == 'auto':
|
||||
self.run_simple_screenshot_benchmark()
|
||||
@@ -110,7 +105,22 @@ class Device(Screenshot, Control, AppControl, Platform):
|
||||
bench = Benchmark(config=self.config, device=self)
|
||||
method = bench.run_simple_screenshot_benchmark()
|
||||
# Set
|
||||
self.config.Emulator_ScreenshotMethod = method
|
||||
with self.config.multi_set():
|
||||
self.config.Emulator_ScreenshotMethod = method
|
||||
if method == 'nemu_ipc':
|
||||
self.config.Emulator_ControlMethod = 'nemu_ipc'
|
||||
|
||||
def method_check(self):
|
||||
"""
|
||||
Check combinations of screenshot method and control methods
|
||||
"""
|
||||
# nemu_ipc should be together
|
||||
if self.config.Emulator_ScreenshotMethod == 'nemu_ipc' and self.config.Emulator_ControlMethod != 'nemu_ipc':
|
||||
logger.warning('When using nemu_ipc, both screenshot and control should use nemu_ipc')
|
||||
self.config.Emulator_ControlMethod = 'nemu_ipc'
|
||||
if self.config.Emulator_ScreenshotMethod != 'nemu_ipc' and self.config.Emulator_ControlMethod == 'nemu_ipc':
|
||||
logger.warning('When not using nemu_ipc, both screenshot and control should not use nemu_ipc')
|
||||
self.config.Emulator_ControlMethod = 'minitouch'
|
||||
|
||||
def handle_night_commission(self, daily_trigger='21:00', threshold=30):
|
||||
"""
|
||||
@@ -161,6 +171,8 @@ class Device(Screenshot, Control, AppControl, Platform):
|
||||
# stop it during wait
|
||||
if self.config.Emulator_ScreenshotMethod == 'scrcpy':
|
||||
self._scrcpy_server_stop()
|
||||
if self.config.Emulator_ScreenshotMethod == 'nemu_ipc':
|
||||
self.nemu_ipc_release()
|
||||
|
||||
def stuck_record_add(self, button):
|
||||
self.detect_record.add(str(button))
|
||||
|
||||
@@ -1,325 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
import winreg
|
||||
import subprocess
|
||||
|
||||
from adbutils.errors import AdbError
|
||||
|
||||
from deploy.Windows.emulator import VirtualBoxEmulator
|
||||
from module.base.decorator import cached_property
|
||||
from module.device.connection import Connection
|
||||
from module.device.method.utils import get_serial_pair
|
||||
from module.exception import RequestHumanTakeover, EmulatorNotRunningError
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
class EmulatorInstance(VirtualBoxEmulator):
|
||||
|
||||
def __init__(self, name, root_path, emu_path,
|
||||
vbox_path=None, vbox_name=None, kill_para=None, multi_para=None):
|
||||
"""
|
||||
Args:
|
||||
name (str): Emulator name in windows uninstall list.
|
||||
root_path (str): Relative path from uninstall.exe to emulator installation folder.
|
||||
emu_path (str): Relative path to executable simulator file.
|
||||
vbox_path (str): Relative path to virtual box folder.
|
||||
vbox_name (str): Regular Expression to match the name of .vbox file.
|
||||
kill_para (str): Parameters required by kill emulator.
|
||||
multi_para (str): Parameters required by start multi open emulator,
|
||||
#id will be replaced with the real ID.
|
||||
"""
|
||||
super().__init__(
|
||||
name=name,
|
||||
root_path=root_path,
|
||||
adb_path=None,
|
||||
vbox_path=vbox_path,
|
||||
vbox_name=vbox_name,
|
||||
)
|
||||
self.emu_path = emu_path
|
||||
self.kill_para = kill_para
|
||||
self.multi_para = multi_para
|
||||
|
||||
@cached_property
|
||||
def id_and_serial(self):
|
||||
"""
|
||||
Returns:
|
||||
list[str, str]: List of multi_id and serial.
|
||||
"""
|
||||
vbox = []
|
||||
for path, folders, files in os.walk(os.path.join(self.root, self.vbox_path)):
|
||||
for file in files:
|
||||
if re.match(self.vbox_name, file):
|
||||
file = os.path.join(path, file)
|
||||
vbox.append(file)
|
||||
|
||||
serial = []
|
||||
for file in vbox:
|
||||
with open(file, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
for line in f.readlines():
|
||||
# <Forwarding name="port2" proto="1" hostip="127.0.0.1" hostport="62026" guestport="5555"/>
|
||||
res = re.search('<*?hostport="(.*?)".*?guestport="5555"/>', line)
|
||||
if res:
|
||||
serial.append([os.path.basename(file).split(".")[0], f'127.0.0.1:{res.group(1)}'])
|
||||
|
||||
return serial
|
||||
|
||||
|
||||
class Bluestacks5Instance(EmulatorInstance):
|
||||
@cached_property
|
||||
def root(self):
|
||||
try:
|
||||
return super().root
|
||||
except FileNotFoundError:
|
||||
self.name = 'BlueStacks_nxt_cn'
|
||||
return super().root
|
||||
|
||||
@cached_property
|
||||
def id_and_serial(self):
|
||||
try:
|
||||
reg = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\BlueStacks_nxt")
|
||||
except FileNotFoundError:
|
||||
reg = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\BlueStacks_nxt_cn")
|
||||
directory = winreg.QueryValueEx(reg, 'UserDefinedDir')[0]
|
||||
|
||||
with open(os.path.join(directory, 'bluestacks.conf'), encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
emulators = re.findall(r'bst.instance.(\w+).status.adb_port="(\d+)"', content)
|
||||
serial = []
|
||||
for emulator in emulators:
|
||||
serial.append([emulator[0], f'127.0.0.1:{emulator[1]}'])
|
||||
return serial
|
||||
|
||||
|
||||
class EmulatorManager(Connection):
|
||||
pid = None
|
||||
SUPPORTED_EMULATORS = {
|
||||
'nox_player': EmulatorInstance(
|
||||
name="Nox",
|
||||
root_path=".",
|
||||
emu_path="./Nox.exe",
|
||||
vbox_path="./BignoxVMS",
|
||||
vbox_name='.*.vbox$',
|
||||
kill_para='-quit',
|
||||
multi_para='-clone:#id',
|
||||
),
|
||||
'mumu_player': EmulatorInstance(
|
||||
name="Nemu",
|
||||
root_path=".",
|
||||
emu_path="./EmulatorShell/NemuPlayer.exe",
|
||||
vbox_path="./vms",
|
||||
vbox_name='.*.nemu$',
|
||||
),
|
||||
'bluestacks_5': Bluestacks5Instance(
|
||||
name='BlueStacks_nxt',
|
||||
root_path='.',
|
||||
emu_path='./HD-Player.exe',
|
||||
multi_para='--instance #id',
|
||||
),
|
||||
}
|
||||
|
||||
def detect_emulator(self, serial, emulator=None):
|
||||
"""
|
||||
Args:
|
||||
serial (str):
|
||||
emulator (EmulatorInstance):
|
||||
|
||||
Returns:
|
||||
list[EmulatorInstance, str]:Emulator and multi_id
|
||||
"""
|
||||
if emulator is None:
|
||||
logger.info('Detect emulator from all emulators installed')
|
||||
emulators = []
|
||||
for emulator in self.SUPPORTED_EMULATORS.values():
|
||||
try:
|
||||
serials = emulator.id_and_serial
|
||||
for cur_serial in serials:
|
||||
if cur_serial[1] == serial:
|
||||
emulators.append([emulator, cur_serial[0]])
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
logger.info('Detected emulators:')
|
||||
for emulator in emulators:
|
||||
logger.info(f'Name: {emulator[0].name}, Multi_id: {emulator[1]}')
|
||||
|
||||
if len(emulators) == 1 or \
|
||||
(len(emulators) > 0 and emulators[0][0] == self.SUPPORTED_EMULATORS['mumu_player']):
|
||||
logger.info('Find the only emulator, using it')
|
||||
return emulators[0][0], emulators[0][1]
|
||||
elif len(emulators) == 0:
|
||||
logger.warning('The emulator corresponding to serial is not found, '
|
||||
'please check the setting or use custom command')
|
||||
else:
|
||||
logger.warning('Multiple emulators with the same serial have been found, '
|
||||
'please select one manually or use custom command')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
else:
|
||||
try:
|
||||
logger.info(f'Detect emulator from {emulator.name}')
|
||||
serials = emulator.id_and_serial
|
||||
for cur_serial in serials:
|
||||
if cur_serial[1] == serial:
|
||||
logger.info('Find the only emulator, using it')
|
||||
return emulator, cur_serial[0]
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
logger.warning('The emulator corresponding to serial is not found, '
|
||||
'please check the setting or use custom command')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
@staticmethod
|
||||
def execute(command):
|
||||
"""
|
||||
Args:
|
||||
command (str):
|
||||
|
||||
Returns:
|
||||
subprocess.Popen:
|
||||
"""
|
||||
command = command.replace(r"\\", "/").replace("\\", "/").replace('"', '"')
|
||||
logger.info(f'Execute: {command}')
|
||||
return subprocess.Popen(command, close_fds=True) # only work on Windows
|
||||
|
||||
@staticmethod
|
||||
def task_kill(pid=None, name=None):
|
||||
"""
|
||||
Args:
|
||||
pid (list, int):
|
||||
name (list, str):
|
||||
|
||||
Returns:
|
||||
subprocess.Popen:
|
||||
"""
|
||||
command = 'taskkill '
|
||||
if pid is not None:
|
||||
if isinstance(pid, list):
|
||||
for p in pid:
|
||||
command += f'/pid {p} '
|
||||
else:
|
||||
command += f'/pid {pid} '
|
||||
elif name is not None:
|
||||
if isinstance(name, list):
|
||||
for n in name:
|
||||
command += f'/im {n} '
|
||||
else:
|
||||
command += f'/im {name} '
|
||||
else:
|
||||
raise RequestHumanTakeover
|
||||
command += '/t /f'
|
||||
|
||||
return EmulatorManager.execute(command)
|
||||
|
||||
def adb_connect(self, serial):
|
||||
try:
|
||||
return super(EmulatorManager, self).adb_connect(serial)
|
||||
except EmulatorNotRunningError:
|
||||
raise RequestHumanTakeover
|
||||
|
||||
def detect_emulator_status(self, serial):
|
||||
devices = self.list_device()
|
||||
for device in devices:
|
||||
if device.serial == serial:
|
||||
return device.status
|
||||
return 'offline'
|
||||
|
||||
def emulator_start(self, serial, emulator=None, multi_id=None, command=None):
|
||||
"""
|
||||
Args:
|
||||
serial (str): Expected serial after simulator starts successfully.
|
||||
emulator (EmulatorInstance): Emulator to start.
|
||||
multi_id (str): Emulator ID used by multi open emulator.
|
||||
command (str): Customized path and parameters of the simulator to start.
|
||||
|
||||
Return:
|
||||
bool: If start successful.
|
||||
"""
|
||||
if command is None:
|
||||
command = '\"' + os.path.abspath(os.path.join(emulator.root, emulator.emu_path)) + '\"'
|
||||
if emulator.multi_para is not None and multi_id is not None:
|
||||
command += " " + emulator.multi_para.replace("#id", multi_id)
|
||||
|
||||
logger.info('Start emulator')
|
||||
pipe = self.execute(command)
|
||||
self.pid = pipe.pid
|
||||
self.sleep(10)
|
||||
|
||||
for _ in range(20):
|
||||
if pipe.poll() is not None:
|
||||
break
|
||||
try:
|
||||
if super().adb_connect(serial):
|
||||
# Wait until emulator start completely
|
||||
self.sleep(10)
|
||||
return True
|
||||
except EmulatorNotRunningError:
|
||||
pass
|
||||
self.sleep(5)
|
||||
return False
|
||||
|
||||
def emulator_kill(self, serial, emulator=None, multi_id=None, command=None):
|
||||
"""
|
||||
Args:
|
||||
serial (str): Expected serial after simulator starts successfully.
|
||||
emulator (EmulatorInstance): Emulator to start.
|
||||
multi_id (str): Emulator ID used by multi open emulator.
|
||||
command (str): Customized path and parameters of the simulator to start.
|
||||
|
||||
Return:
|
||||
bool: If kill successful.
|
||||
"""
|
||||
if command is None and emulator.kill_para is not None:
|
||||
command = '\"' + os.path.abspath(os.path.join(emulator.root, emulator.emu_path)) + '\"'
|
||||
if emulator.multi_para is not None and multi_id is not None:
|
||||
command += " " + emulator.multi_para.replace("#id", multi_id)
|
||||
command += " " + emulator.kill_para
|
||||
|
||||
logger.info('Kill emulator')
|
||||
if emulator == self.SUPPORTED_EMULATORS['bluestacks_5']:
|
||||
try:
|
||||
self.adb_command(['reboot', '-p'], timeout=20)
|
||||
if self.detect_emulator_status(serial) == 'offline':
|
||||
self.pid = None
|
||||
return True
|
||||
except AdbError:
|
||||
return False
|
||||
|
||||
if emulator == self.SUPPORTED_EMULATORS['mumu_player']:
|
||||
self.task_kill(pid=None, name=['NemuHeadless.exe', 'NemuPlayer.exe', 'NemuSvc.exe'])
|
||||
elif command is not None:
|
||||
self.execute(command)
|
||||
else:
|
||||
self.task_kill(pid=self.pid, name=os.path.basename(emulator.emu_path))
|
||||
self.sleep(5)
|
||||
|
||||
for _ in range(10):
|
||||
if self.detect_emulator_status(serial) == 'offline':
|
||||
self.pid = None
|
||||
return True
|
||||
self.sleep(2)
|
||||
return False
|
||||
|
||||
def emulator_restart(self):
|
||||
serial, _ = get_serial_pair(self.serial)
|
||||
if serial is None:
|
||||
serial = self.serial
|
||||
|
||||
if os.name != 'nt':
|
||||
logger.warning('Restart simulator only works under Windows platform')
|
||||
return False
|
||||
|
||||
logger.hr('Emulator restart')
|
||||
if self.config.RestartEmulator_EmulatorType == 'auto':
|
||||
emulator, multi_id = self.detect_emulator(serial)
|
||||
else:
|
||||
emulator = self.SUPPORTED_EMULATORS[self.config.RestartEmulator_EmulatorType]
|
||||
emulator, multi_id = self.detect_emulator(serial, emulator=emulator)
|
||||
|
||||
for _ in range(3):
|
||||
if not self.emulator_kill(serial, emulator, multi_id):
|
||||
continue
|
||||
if self.emulator_start(serial, emulator, multi_id):
|
||||
return True
|
||||
|
||||
logger.warning('Restart emulator failed for 3 times, please check your settings')
|
||||
raise RequestHumanTakeover
|
||||
|
||||
@@ -146,7 +146,7 @@ class Adb(Connection):
|
||||
if image is None:
|
||||
raise ImageTruncated('Empty image after cv2.imdecode')
|
||||
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||
cv2.cvtColor(image, cv2.COLOR_BGR2RGB, dst=image)
|
||||
if image is None:
|
||||
raise ImageTruncated('Empty image after cv2.cvtColor')
|
||||
|
||||
|
||||
@@ -165,11 +165,11 @@ class AScreenCap(Connection):
|
||||
# ValueError: cannot reshape array of size 0 into shape (720,1280,4)
|
||||
raise ImageTruncated(str(e))
|
||||
|
||||
image = cv2.flip(image, 0)
|
||||
cv2.flip(image, 0, dst=image)
|
||||
if image is None:
|
||||
raise ImageTruncated('Empty image after cv2.flip')
|
||||
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||
cv2.cvtColor(image, cv2.COLOR_BGR2RGB, dst=image)
|
||||
if image is None:
|
||||
raise ImageTruncated('Empty image after cv2.cvtColor')
|
||||
|
||||
|
||||