Compare commits
38 Commits
v0.1.0
...
9e5fd34b79
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e5fd34b79 | |||
| 5487338dc6 | |||
| e5a914e80f | |||
| f21a97e08d | |||
| b4c47e2de2 | |||
| 34208763aa | |||
|
c3354cf4f5
|
|||
|
81abba0270
|
|||
|
acea188931
|
|||
|
b0621b48e6
|
|||
|
1b83b7077f
|
|||
|
f1e3cd9810
|
|||
|
f91fc2c55d
|
|||
|
d82e206463
|
|||
|
db813c9efb
|
|||
|
9d3b5ceff8
|
|||
|
b83db6bc35
|
|||
|
2e4a1f144b
|
|||
|
f7444e29dc
|
|||
|
1113094cf5
|
|||
|
60e6710181
|
|||
|
9708ec05d7
|
|||
|
77f0ded95f
|
|||
|
937a7c63e8
|
|||
|
61fa6ad28b
|
|||
|
0551207714
|
|||
|
826a6b2348
|
|||
|
a05c4e8f2f
|
|||
|
a20411071c
|
|||
|
d53e280bfc
|
|||
|
0b2487487b
|
|||
|
bea794386c
|
|||
|
57c0ed8531
|
|||
|
75e6417620
|
|||
|
96b5f1db85
|
|||
|
51305f7c0b
|
|||
|
22647a5e36
|
|||
|
080c4c130c
|
@@ -0,0 +1,40 @@
|
|||||||
|
<img width="150" height="150" align="left" style="float: left; margin: 0 10px 0 0;" alt="AAS icon" src="docs/resources/aas_icon.svg"/>
|
||||||
|
|
||||||
|
# ArisuAutoSweeper
|
||||||
|
|
||||||
|
**Blue Archive Automation Script**
|
||||||
|
|
||||||
|
**| English | [简体中文](README.md) |**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
The script is still under active development. The following features have been implemented:
|
||||||
|
|
||||||
|
- [x] **Cafe** Claim rewards / Interact / Second cafe
|
||||||
|
- [x] **Circle** Claim AP
|
||||||
|
- [x] **Mailbox** Claim rewards
|
||||||
|
- [x] **Tactical Challenge** Claim rewards / Auto battle
|
||||||
|
|
||||||
|
_Currently only supports JP server._
|
||||||
|
|
||||||
|
## Relative projects
|
||||||
|
|
||||||
|
- [AzurLaneAutoScript](https://github.com/LmeSzinc/AzurLaneAutoScript): Azur Lane auto script
|
||||||
|
- [StarRailCopilot](https://github.com/LmeSzinc/StarRailCopilot): A bot for Honkai: Star Rail, based on the next
|
||||||
|
generation of ALAS framework
|
||||||
|
|
||||||
|
Some Blue Archive auto scripts:
|
||||||
|
|
||||||
|
- [BAAuto](https://github.com/RedDeadDepresso/BAAuto): Blue Archive Automation Script
|
||||||
|
- [BlueArchiveAutoScript](https://github.com/pur1fying/blue_archive_auto_script): BAAS, used to implement Blue Archive
|
||||||
|
automation
|
||||||
|
- [MBA](https://github.com/MaaAssistantArknights/MBA): BA assistant based on the new architecture of MAA
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
Thanks to [6bir](https://github.com/6bir) for the icon design.
|
||||||
|
|
||||||
|
Thanks to [Alas](https://github.com/LmeSzinc/AzurLaneAutoScript) and [SRC](https://github.com/LmeSzinc/StarRailCopilot)
|
||||||
|
for the development framework.
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<img width="150" height="150" align="left" style="float: left; margin: 0 10px 0 0;" alt="AAS icon" src="docs/resources/aas_icon.svg"/>
|
||||||
|
|
||||||
|
# ArisuAutoSweeper
|
||||||
|
|
||||||
|
**蔚蓝档案自动化脚本**
|
||||||
|
|
||||||
|
**| [English](README.en.md) | 简体中文 |**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
当前脚本还在活跃开发中,已经实现的功能有:
|
||||||
|
|
||||||
|
- [x] **咖啡厅** 领取奖励 / 互动 / 第二咖啡厅
|
||||||
|
- [x] **公会** 领取体力
|
||||||
|
- [x] **邮箱** 领取奖励
|
||||||
|
- [x] **战术对抗赛** 领取奖励 / 自动战斗
|
||||||
|
|
||||||
|
_目前仅支持日服。_
|
||||||
|
|
||||||
|
## 相关项目
|
||||||
|
|
||||||
|
- [AzurLaneAutoScript](https://github.com/LmeSzinc/AzurLaneAutoScript): 碧蓝航线自动化脚本
|
||||||
|
- [StarRailCopilot](https://github.com/LmeSzinc/StarRailCopilot): 崩坏:星穹铁道脚本,基于下一代Alas框架
|
||||||
|
|
||||||
|
一些蔚蓝档案脚本:
|
||||||
|
|
||||||
|
- [BAAuto](https://github.com/RedDeadDepresso/BAAuto): 蔚蓝档案自动脚本
|
||||||
|
- [BlueArchiveAutoScript](https://github.com/pur1fying/blue_archive_auto_script): BAAS,用于实现蔚蓝档案自动化
|
||||||
|
- [MBA](https://github.com/MaaAssistantArknights/MBA): 基于 MAA 全新架构的 BA 小助手
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
|
||||||
|
感谢 [6bir](https://github.com/6bir) 为本项目设计的图标。
|
||||||
|
|
||||||
|
感谢 [Alas](https://github.com/LmeSzinc/AzurLaneAutoScript) 以及 [SRC](https://github.com/LmeSzinc/StarRailCopilot)
|
||||||
|
提供的开发框架。
|
||||||
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
@@ -43,7 +43,8 @@
|
|||||||
"Cafe": {
|
"Cafe": {
|
||||||
"Reward": true,
|
"Reward": true,
|
||||||
"Touch": true,
|
"Touch": true,
|
||||||
"AutoAdjust": true
|
"AutoAdjust": true,
|
||||||
|
"SecondCafe": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Mail": {
|
"Mail": {
|
||||||
|
|||||||
@@ -65,9 +65,6 @@ class ConfigModel:
|
|||||||
AppAsarUpdate: bool = True
|
AppAsarUpdate: bool = True
|
||||||
NoSandbox: bool = True
|
NoSandbox: bool = True
|
||||||
|
|
||||||
# Dynamic
|
|
||||||
GitOverCdn: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
class DeployConfig(ConfigModel):
|
class DeployConfig(ConfigModel):
|
||||||
def __init__(self, file=DEPLOY_CONFIG):
|
def __init__(self, file=DEPLOY_CONFIG):
|
||||||
@@ -82,8 +79,9 @@ class DeployConfig(ConfigModel):
|
|||||||
|
|
||||||
# Bypass webui.config.DeployConfig.__setattr__()
|
# Bypass webui.config.DeployConfig.__setattr__()
|
||||||
# Don't write these into deploy.yaml
|
# Don't write these into deploy.yaml
|
||||||
super().__setattr__('GitOverCdn', self.Repository in ['cn'])
|
if self.Repository == 'cn':
|
||||||
if self.Repository in ['global', 'cn']:
|
super().__setattr__('Repository', 'https://git.yoursfunny.top/YoursFunny/ArisuAutoSweeper.git')
|
||||||
|
if self.Repository == 'global':
|
||||||
super().__setattr__('Repository', 'https://github.com/TheFunny/ArisuAutoSweeper')
|
super().__setattr__('Repository', 'https://github.com/TheFunny/ArisuAutoSweeper')
|
||||||
|
|
||||||
self.write()
|
self.write()
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import os
|
|||||||
from deploy.Windows.config import DeployConfig
|
from deploy.Windows.config import DeployConfig
|
||||||
from deploy.Windows.logger import Progress, logger
|
from deploy.Windows.logger import Progress, logger
|
||||||
from deploy.Windows.utils import cached_property
|
from deploy.Windows.utils import cached_property
|
||||||
# from deploy.git_over_cdn.client import GitOverCdnClient
|
|
||||||
|
|
||||||
|
|
||||||
class GitConfigParser(configparser.ConfigParser):
|
class GitConfigParser(configparser.ConfigParser):
|
||||||
@@ -17,25 +16,6 @@ class GitConfigParser(configparser.ConfigParser):
|
|||||||
return False
|
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):
|
class GitManager(DeployConfig):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def remove(file):
|
def remove(file):
|
||||||
@@ -128,18 +108,6 @@ class GitManager(DeployConfig):
|
|||||||
self.execute(f'"{self.git}" --no-pager log --no-merges -1')
|
self.execute(f'"{self.git}" --no-pager log --no-merges -1')
|
||||||
Progress.GitShowVersion()
|
Progress.GitShowVersion()
|
||||||
|
|
||||||
# @property
|
|
||||||
# def goc_client(self):
|
|
||||||
# client = GitOverCdnClient(
|
|
||||||
# url='https://vip.123pan.cn/1815343254/pack/LmeSzinc_StarRailCopilot_master',
|
|
||||||
# folder=self.root_filepath,
|
|
||||||
# source='origin',
|
|
||||||
# branch='master',
|
|
||||||
# git=self.git,
|
|
||||||
# )
|
|
||||||
# client.logger = logger
|
|
||||||
# return client
|
|
||||||
|
|
||||||
def git_install(self):
|
def git_install(self):
|
||||||
logger.hr('Update Alas', 0)
|
logger.hr('Update Alas', 0)
|
||||||
|
|
||||||
@@ -148,10 +116,6 @@ class GitManager(DeployConfig):
|
|||||||
Progress.GitShowVersion()
|
Progress.GitShowVersion()
|
||||||
return
|
return
|
||||||
|
|
||||||
# if self.GitOverCdn:
|
|
||||||
# if self.goc_client.update(keep_changes=self.KeepLocalChanges):
|
|
||||||
# return
|
|
||||||
|
|
||||||
self.git_repository_init(
|
self.git_repository_init(
|
||||||
repo=self.Repository,
|
repo=self.Repository,
|
||||||
source='origin',
|
source='origin',
|
||||||
|
|||||||
@@ -1,266 +0,0 @@
|
|||||||
import io
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import zipfile
|
|
||||||
from typing import Callable, Generic, TypeVar
|
|
||||||
|
|
||||||
import requests
|
|
||||||
from requests.adapters import HTTPAdapter
|
|
||||||
|
|
||||||
T = TypeVar("T")
|
|
||||||
|
|
||||||
TEMPLATE_FILE = './config/template.yaml'
|
|
||||||
|
|
||||||
|
|
||||||
class cached_property(Generic[T]):
|
|
||||||
"""
|
|
||||||
cached-property from https://github.com/pydanny/cached-property
|
|
||||||
Add typing support
|
|
||||||
|
|
||||||
A property that is only computed once per instance and then replaces itself
|
|
||||||
with an ordinary attribute. Deleting the attribute resets the property.
|
|
||||||
Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, func: Callable[..., T]):
|
|
||||||
self.func = func
|
|
||||||
|
|
||||||
def __get__(self, obj, cls) -> T:
|
|
||||||
if obj is None:
|
|
||||||
return self
|
|
||||||
|
|
||||||
value = obj.__dict__[self.func.__name__] = self.func(obj)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class PrintLogger:
|
|
||||||
info = print
|
|
||||||
warning = print
|
|
||||||
error = print
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def attr(name, text):
|
|
||||||
print(f'[{name}] {text}')
|
|
||||||
|
|
||||||
|
|
||||||
class GitOverCdnClient:
|
|
||||||
logger = PrintLogger()
|
|
||||||
|
|
||||||
def __init__(self, url, folder, source='origin', branch='master', git='git'):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
url: http://127.0.0.1:22251/pack/LmeSzinc_AzurLaneAutoScript_master/
|
|
||||||
folder: D:/AzurLaneAutoScript
|
|
||||||
"""
|
|
||||||
self.url = url.strip('/')
|
|
||||||
self.folder = folder.replace('\\', '/')
|
|
||||||
self.source = source
|
|
||||||
self.branch = branch
|
|
||||||
self.git = git
|
|
||||||
|
|
||||||
def filepath(self, path):
|
|
||||||
path = os.path.join(self.folder, '.git', path)
|
|
||||||
return os.path.abspath(path).replace('\\', '/')
|
|
||||||
|
|
||||||
def urlpath(self, path):
|
|
||||||
return f'{self.url}{path}'
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def current_commit(self) -> str:
|
|
||||||
for file in [
|
|
||||||
f'./refs/remotes/{self.source}/{self.branch}',
|
|
||||||
f'./refs/heads/{self.branch}',
|
|
||||||
'ORIG_HEAD',
|
|
||||||
]:
|
|
||||||
file = self.filepath(file)
|
|
||||||
try:
|
|
||||||
with open(file, 'r', encoding='utf-8') as f:
|
|
||||||
commit = f.read()
|
|
||||||
res = re.search(r'([0-9a-f]{40})', commit)
|
|
||||||
if res:
|
|
||||||
commit = res.group(1)
|
|
||||||
self.logger.attr('CurrentCommit', commit)
|
|
||||||
return commit
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
self.logger.error(f'Failed to get local commit: {e}')
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f'Failed to get local commit: {e}')
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@property
|
|
||||||
def session(self):
|
|
||||||
session = requests.Session()
|
|
||||||
session.trust_env = False
|
|
||||||
session.mount('http://', HTTPAdapter(max_retries=3))
|
|
||||||
session.mount('https://', HTTPAdapter(max_retries=3))
|
|
||||||
return session
|
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def latest_commit(self) -> str:
|
|
||||||
try:
|
|
||||||
url = self.urlpath('/latest.json')
|
|
||||||
self.logger.info(f'Fetch url: {url}')
|
|
||||||
resp = self.session.get(url, timeout=3)
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f'Failed to get remote commit: {e}')
|
|
||||||
return ''
|
|
||||||
|
|
||||||
if resp.status_code == 200:
|
|
||||||
try:
|
|
||||||
info = json.loads(resp.text)
|
|
||||||
commit = info['commit']
|
|
||||||
self.logger.attr('LatestCommit', commit)
|
|
||||||
return commit
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
self.logger.error(f'Failed to get remote commit, response is not a json: {resp.text}')
|
|
||||||
return ''
|
|
||||||
except KeyError:
|
|
||||||
self.logger.error(f'Failed to get remote commit, key "commit" is not found: {resp.text}')
|
|
||||||
return ''
|
|
||||||
else:
|
|
||||||
self.logger.error(f'Failed to get remote commit, status={resp.status_code}, text={resp.text}')
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def download_pack(self):
|
|
||||||
try:
|
|
||||||
url = self.urlpath(f'/{self.latest_commit}/{self.current_commit}.zip')
|
|
||||||
self.logger.info(f'Fetch url: {url}')
|
|
||||||
resp = self.session.get(url, timeout=20)
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f'Failed to download pack: {e}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
if resp.status_code == 200:
|
|
||||||
try:
|
|
||||||
zipped = zipfile.ZipFile(io.BytesIO(resp.content))
|
|
||||||
for file in [f'pack-{self.latest_commit}.pack', f'pack-{self.latest_commit}.idx']:
|
|
||||||
self.logger.info(f'Unzip {file}')
|
|
||||||
member = zipped.getinfo(file)
|
|
||||||
tmp = self.filepath(f'./objects/pack/{file}.tmp')
|
|
||||||
out = self.filepath(f'./objects/pack/{file}')
|
|
||||||
with zipped.open(member) as source, open(tmp, "wb") as target:
|
|
||||||
shutil.copyfileobj(source, target)
|
|
||||||
os.replace(tmp, out)
|
|
||||||
return True
|
|
||||||
except zipfile.BadZipFile as e:
|
|
||||||
# File is not a zip file
|
|
||||||
self.logger.error(e)
|
|
||||||
return False
|
|
||||||
except KeyError as e:
|
|
||||||
# There is no item named 'xxx.idx' in the archive
|
|
||||||
self.logger.error(e)
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(e)
|
|
||||||
return False
|
|
||||||
elif resp.status_code == 404:
|
|
||||||
self.logger.error(f'Failed to download pack, status={resp.status_code}, no such pack files provided')
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
self.logger.error(f'Failed to download pack, status={resp.status_code}, text={resp.text}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
def update_refs(self):
|
|
||||||
file = self.filepath(f'./refs/remotes/{self.source}/{self.branch}')
|
|
||||||
text = f'{self.latest_commit}\n'
|
|
||||||
self.logger.info(f'Update refs: {file}')
|
|
||||||
os.makedirs(os.path.dirname(file), exist_ok=True)
|
|
||||||
try:
|
|
||||||
with open(file, 'w', encoding='utf-8', newline='') as f:
|
|
||||||
f.write(text)
|
|
||||||
return True
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
self.logger.error(f'Failed to get local commit: {e}')
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f'Failed to get local commit: {e}')
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def git_command(self, *args, timeout=300):
|
|
||||||
"""
|
|
||||||
Execute ADB commands in a subprocess,
|
|
||||||
usually to be used when pulling or pushing large files.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
timeout (int):
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str:
|
|
||||||
"""
|
|
||||||
os.chdir(self.folder)
|
|
||||||
cmd = list(map(str, args))
|
|
||||||
cmd = [self.git] + cmd
|
|
||||||
self.logger.info(f'Execute: {cmd}')
|
|
||||||
|
|
||||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=False)
|
|
||||||
try:
|
|
||||||
stdout, stderr = process.communicate(timeout=timeout)
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
process.kill()
|
|
||||||
stdout, stderr = process.communicate()
|
|
||||||
self.logger.warning(f'TimeoutExpired when calling {cmd}, stdout={stdout}, stderr={stderr}')
|
|
||||||
return stdout.decode()
|
|
||||||
|
|
||||||
def git_reset(self, keep_changes=False):
|
|
||||||
"""
|
|
||||||
git reset --hard <commit>
|
|
||||||
"""
|
|
||||||
if keep_changes:
|
|
||||||
self.git_command('stash')
|
|
||||||
self.git_command('reset', '--hard', f'{self.source}/{self.branch}')
|
|
||||||
self.git_command('stash', 'pop')
|
|
||||||
else:
|
|
||||||
self.git_command('reset', '--hard', f'{self.source}/{self.branch}')
|
|
||||||
|
|
||||||
def get_status(self):
|
|
||||||
"""
|
|
||||||
Returns:
|
|
||||||
str: 'uptodate' if repo is up-to-date
|
|
||||||
'behind' if repos is not up-to-date
|
|
||||||
'failed' if failed
|
|
||||||
"""
|
|
||||||
_ = self.current_commit
|
|
||||||
_ = self.latest_commit
|
|
||||||
if not self.current_commit:
|
|
||||||
self.logger.error('Failed to get current commit')
|
|
||||||
return 'failed'
|
|
||||||
if not self.latest_commit:
|
|
||||||
self.logger.error('Failed to get latest commit')
|
|
||||||
return 'failed'
|
|
||||||
if self.current_commit == self.latest_commit:
|
|
||||||
self.logger.info('Already up to date')
|
|
||||||
return 'uptodate'
|
|
||||||
self.logger.info('Current repo is behind remote')
|
|
||||||
return 'behind'
|
|
||||||
|
|
||||||
def update(self, keep_changes=False):
|
|
||||||
"""
|
|
||||||
Args:
|
|
||||||
keep_changes:
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: If repo is up-to-date
|
|
||||||
"""
|
|
||||||
_ = self.current_commit
|
|
||||||
_ = self.latest_commit
|
|
||||||
if not self.current_commit:
|
|
||||||
self.logger.error('Failed to get current commit')
|
|
||||||
return False
|
|
||||||
if not self.latest_commit:
|
|
||||||
self.logger.error('Failed to get latest commit')
|
|
||||||
return False
|
|
||||||
if self.current_commit == self.latest_commit:
|
|
||||||
self.logger.info('Already up to date')
|
|
||||||
self.git_reset(keep_changes=keep_changes)
|
|
||||||
return True
|
|
||||||
|
|
||||||
if not self.download_pack():
|
|
||||||
return False
|
|
||||||
if not self.update_refs():
|
|
||||||
return False
|
|
||||||
self.git_reset(keep_changes=keep_changes)
|
|
||||||
self.logger.info('Update success')
|
|
||||||
return True
|
|
||||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 199 KiB |
|
After Width: | Height: | Size: 215 KiB |
@@ -128,6 +128,14 @@ class ModuleBase:
|
|||||||
self.device.click(button)
|
self.device.click(button)
|
||||||
return appear
|
return appear
|
||||||
|
|
||||||
|
def click_with_interval(self, button, interval=5):
|
||||||
|
if interval and not self.interval_is_reached(button, interval=interval):
|
||||||
|
return False
|
||||||
|
self.device.click(button)
|
||||||
|
if interval:
|
||||||
|
self.interval_reset(button, interval=interval)
|
||||||
|
return True
|
||||||
|
|
||||||
def wait_until_stable(self, button, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
|
def wait_until_stable(self, button, timer=Timer(0.3, count=1), timeout=Timer(5, count=10)):
|
||||||
"""
|
"""
|
||||||
A terrible method, don't rely too much on it.
|
A terrible method, don't rely too much on it.
|
||||||
|
|||||||
@@ -194,6 +194,10 @@
|
|||||||
"AutoAdjust": {
|
"AutoAdjust": {
|
||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
"value": true
|
"value": true
|
||||||
|
},
|
||||||
|
"SecondCafe": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"value": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ Cafe:
|
|||||||
Reward: true
|
Reward: true
|
||||||
Touch: true
|
Touch: true
|
||||||
AutoAdjust: true
|
AutoAdjust: true
|
||||||
|
SecondCafe: true
|
||||||
|
|
||||||
TacticalChallenge:
|
TacticalChallenge:
|
||||||
PlayerSelect:
|
PlayerSelect:
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class GeneratedConfig:
|
|||||||
Cafe_Reward = True
|
Cafe_Reward = True
|
||||||
Cafe_Touch = True
|
Cafe_Touch = True
|
||||||
Cafe_AutoAdjust = True
|
Cafe_AutoAdjust = True
|
||||||
|
Cafe_SecondCafe = True
|
||||||
|
|
||||||
# Group `TacticalChallenge`
|
# Group `TacticalChallenge`
|
||||||
TacticalChallenge_PlayerSelect = 0 # 0, 1, 2, 3
|
TacticalChallenge_PlayerSelect = 0 # 0, 1, 2, 3
|
||||||
|
|||||||
@@ -1,94 +1,94 @@
|
|||||||
{
|
{
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Alas": {
|
"Alas": {
|
||||||
"name": "Menu.Alas.name",
|
"name": "AAS",
|
||||||
"help": "Menu.Alas.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Daily": {
|
"Daily": {
|
||||||
"name": "Menu.Daily.name",
|
"name": "Daily",
|
||||||
"help": "Menu.Daily.help"
|
"help": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Task": {
|
"Task": {
|
||||||
"Alas": {
|
"Alas": {
|
||||||
"name": "Task.Alas.name",
|
"name": "AAS Settings",
|
||||||
"help": "Task.Alas.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Restart": {
|
"Restart": {
|
||||||
"name": "Task.Restart.name",
|
"name": "Error Handling",
|
||||||
"help": "Task.Restart.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Cafe": {
|
"Cafe": {
|
||||||
"name": "Task.Cafe.name",
|
"name": "Cafe",
|
||||||
"help": "Task.Cafe.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Mail": {
|
"Mail": {
|
||||||
"name": "Task.Mail.name",
|
"name": "Mailbox",
|
||||||
"help": "Task.Mail.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Circle": {
|
"Circle": {
|
||||||
"name": "Task.Circle.name",
|
"name": "Club",
|
||||||
"help": "Task.Circle.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"TacticalChallenge": {
|
"TacticalChallenge": {
|
||||||
"name": "Task.TacticalChallenge.name",
|
"name": "Tactical Challenge",
|
||||||
"help": "Task.TacticalChallenge.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"DataUpdate": {
|
"DataUpdate": {
|
||||||
"name": "Task.DataUpdate.name",
|
"name": "Dashboard Upd",
|
||||||
"help": "Task.DataUpdate.help"
|
"help": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Scheduler": {
|
"Scheduler": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "Scheduler._info.name",
|
"name": "Scheduler",
|
||||||
"help": "Scheduler._info.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Enable": {
|
"Enable": {
|
||||||
"name": "Scheduler.Enable.name",
|
"name": "Enable Task",
|
||||||
"help": "Scheduler.Enable.help",
|
"help": "Join this task to scheduler.",
|
||||||
"True": "True",
|
"True": "Enabled",
|
||||||
"False": "False"
|
"False": "False"
|
||||||
},
|
},
|
||||||
"NextRun": {
|
"NextRun": {
|
||||||
"name": "Scheduler.NextRun.name",
|
"name": "Next Run",
|
||||||
"help": "Scheduler.NextRun.help"
|
"help": "Updated automatically after completing the task to set next scheduled run, typically not manually modified\nHowever you can force immediate scheduling if you clear this text field"
|
||||||
},
|
},
|
||||||
"Command": {
|
"Command": {
|
||||||
"name": "Scheduler.Command.name",
|
"name": "Command",
|
||||||
"help": "Scheduler.Command.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"ServerUpdate": {
|
"ServerUpdate": {
|
||||||
"name": "Scheduler.ServerUpdate.name",
|
"name": "Server Update",
|
||||||
"help": "Scheduler.ServerUpdate.help"
|
"help": "Series of server refresh time(s) as to when this task will next run, this is automatically converted to respective time zone, generally do not need to modify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Emulator": {
|
"Emulator": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "Emulator._info.name",
|
"name": "Emulator Settings",
|
||||||
"help": "Emulator._info.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Serial": {
|
"Serial": {
|
||||||
"name": "Emulator.Serial.name",
|
"name": "Serial",
|
||||||
"help": "Emulator.Serial.help"
|
"help": "Common emulator Serial can be queried in the list below\nUse \"auto\" to auto-detect emulators, but if multiple emulators are running or use emulators that do not support auto-detect, \"auto\" cannot be used and serial must be filled in manually\nDefault serial for select emulators:\n- BlueStacks 127.0.0.1:5555\n- BlueStacks4 Hyper-V use \"bluestacks4-hyperv\", \"bluestacks4-hyperv-2\" for multi instance, and so on\n- BlueStacks5 Hyper-V use \"bluestacks5-hyperv\", \"bluestacks5-hyperv-1\" for multi instance, and so on\n- NoxPlayer 127.0.0.1:62001\n- NoxPlayer64bit 127.0.0.1:59865\n- MuMuPlayer/MuMuPlayer X 127.0.0.1:7555\n- MuMuPlayer12 127.0.0.1:16384\n- MemuPlayer 127.0.0.1:21503\n- LDPlayer emulator-5554 or 127.0.0.1:5555\n- WSA use \"wsa-0\" to make the game run in the background, which needs to be controlled or closed by third-party software\nIf there are multiple emulator instances running, the default is reserved for one of them and the others will use different serials to avoid conflicts\nOpen console.bat and run `adb devices` to find them or follow the emulator's official tutorial"
|
||||||
},
|
},
|
||||||
"PackageName": {
|
"PackageName": {
|
||||||
"name": "Emulator.PackageName.name",
|
"name": "Game Server",
|
||||||
"help": "Emulator.PackageName.help",
|
"help": "Can't distinguish different regions of oversea servers, please select the server manually.",
|
||||||
"auto": "auto",
|
"auto": "Auto-detect",
|
||||||
"JP-Official": "JP-Official"
|
"JP-Official": "[JP]-Official"
|
||||||
},
|
},
|
||||||
"GameLanguage": {
|
"GameLanguage": {
|
||||||
"name": "Emulator.GameLanguage.name",
|
"name": "In-game Text Language",
|
||||||
"help": "Emulator.GameLanguage.help",
|
"help": "Currently, only Simplified Chinese and English are supported. Please set the text language in game to one of them.",
|
||||||
"auto": "auto",
|
"auto": "Auto-detect",
|
||||||
"jp": "jp"
|
"jp": "Japanese"
|
||||||
},
|
},
|
||||||
"ScreenshotMethod": {
|
"ScreenshotMethod": {
|
||||||
"name": "Emulator.ScreenshotMethod.name",
|
"name": "Screenshot Method",
|
||||||
"help": "Emulator.ScreenshotMethod.help",
|
"help": "When using auto-select, a benchmark will be performed and automatically changed to the fastest screenshot method.\nGeneral speed: DroidCast_raw >> aScreenCap_nc > ADB_nc >>> aScreenCap > uiautomator2 ~= ADB.\nRun Tools - Performance Test to find the fastest method.",
|
||||||
"auto": "auto",
|
"auto": "Auto-select the fastest",
|
||||||
"ADB": "ADB",
|
"ADB": "ADB ",
|
||||||
"ADB_nc": "ADB_nc",
|
"ADB_nc": "ADB_nc",
|
||||||
"uiautomator2": "uiautomator2",
|
"uiautomator2": "uiautomator2",
|
||||||
"aScreenCap": "aScreenCap",
|
"aScreenCap": "aScreenCap",
|
||||||
@@ -98,123 +98,127 @@
|
|||||||
"scrcpy": "scrcpy"
|
"scrcpy": "scrcpy"
|
||||||
},
|
},
|
||||||
"ControlMethod": {
|
"ControlMethod": {
|
||||||
"name": "Emulator.ControlMethod.name",
|
"name": "Control Method",
|
||||||
"help": "Emulator.ControlMethod.help",
|
"help": "Speed: MaaTouch = minitouch >>> uiautomator2 ~= ADB\nMaaTouch is recommended",
|
||||||
"minitouch": "minitouch",
|
"minitouch": "minitouch",
|
||||||
"MaaTouch": "MaaTouch"
|
"MaaTouch": "MaaTouch"
|
||||||
},
|
},
|
||||||
"AdbRestart": {
|
"AdbRestart": {
|
||||||
"name": "Emulator.AdbRestart.name",
|
"name": "Try to restart adb when no device found",
|
||||||
"help": "Emulator.AdbRestart.help"
|
"help": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EmulatorInfo": {
|
"EmulatorInfo": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "EmulatorInfo._info.name",
|
"name": "Emulator Settings",
|
||||||
"help": "EmulatorInfo._info.help"
|
"help": "The following values are auto-filled according to \"Serial\", if you don’t understand, please don't modify them"
|
||||||
},
|
},
|
||||||
"Emulator": {
|
"Emulator": {
|
||||||
"name": "EmulatorInfo.Emulator.name",
|
"name": "Emulator Type",
|
||||||
"help": "EmulatorInfo.Emulator.help",
|
"help": "",
|
||||||
"auto": "auto",
|
"auto": "Auto-detect",
|
||||||
"NoxPlayer": "NoxPlayer",
|
"NoxPlayer": "Nox Player",
|
||||||
"NoxPlayer64": "NoxPlayer64",
|
"NoxPlayer64": "Nox Player 64bit",
|
||||||
"BlueStacks4": "BlueStacks4",
|
"BlueStacks4": "BlueStacks 4",
|
||||||
"BlueStacks5": "BlueStacks5",
|
"BlueStacks5": "BlueStacks 5",
|
||||||
"BlueStacks4HyperV": "BlueStacks4HyperV",
|
"BlueStacks4HyperV": "BlueStacks 4 Hyper-V",
|
||||||
"BlueStacks5HyperV": "BlueStacks5HyperV",
|
"BlueStacks5HyperV": "BlueStacks 5 Hyper-V",
|
||||||
"LDPlayer3": "LDPlayer3",
|
"LDPlayer3": "LD Player 3",
|
||||||
"LDPlayer4": "LDPlayer4",
|
"LDPlayer4": "LD Player 4",
|
||||||
"LDPlayer9": "LDPlayer9",
|
"LDPlayer9": "LD Player 9",
|
||||||
"MuMuPlayer": "MuMuPlayer",
|
"MuMuPlayer": "MuMu Player",
|
||||||
"MuMuPlayerX": "MuMuPlayerX",
|
"MuMuPlayerX": "MuMu Player X",
|
||||||
"MuMuPlayer12": "MuMuPlayer12",
|
"MuMuPlayer12": "MuMu Player 12",
|
||||||
"MEmuPlayer": "MEmuPlayer"
|
"MEmuPlayer": "MEmu Player"
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "EmulatorInfo.name.name",
|
"name": "Emulator Instance Name",
|
||||||
"help": "EmulatorInfo.name.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"path": {
|
"path": {
|
||||||
"name": "EmulatorInfo.path.name",
|
"name": "Emulator Installation Path",
|
||||||
"help": "EmulatorInfo.path.help"
|
"help": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Error": {
|
"Error": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "Error._info.name",
|
"name": "Debug Settings",
|
||||||
"help": "Error._info.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Restart": {
|
"Restart": {
|
||||||
"name": "Error.Restart.name",
|
"name": "Restart Game on Error",
|
||||||
"help": "Error.Restart.help",
|
"help": "",
|
||||||
"game": "game",
|
"game": "Restart game",
|
||||||
"game_emulator": "game_emulator"
|
"game_emulator": "Restart emulator and game"
|
||||||
},
|
},
|
||||||
"SaveError": {
|
"SaveError": {
|
||||||
"name": "Error.SaveError.name",
|
"name": "Record Exception",
|
||||||
"help": "Error.SaveError.help"
|
"help": "Records exception and log into directory for review or sharing"
|
||||||
},
|
},
|
||||||
"ScreenshotLength": {
|
"ScreenshotLength": {
|
||||||
"name": "Error.ScreenshotLength.name",
|
"name": "Record Screenshot(s)",
|
||||||
"help": "Error.ScreenshotLength.help"
|
"help": "Number of screenshots saved when exception occurs"
|
||||||
},
|
},
|
||||||
"OnePushConfig": {
|
"OnePushConfig": {
|
||||||
"name": "Error.OnePushConfig.name",
|
"name": "Error notify config",
|
||||||
"help": "Error.OnePushConfig.help"
|
"help": "When AAS cannot handle exception, send a message through Onepush. Configuration document: \nhttps://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BEN%5D"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Optimization": {
|
"Optimization": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "Optimization._info.name",
|
"name": "Optimization Settings",
|
||||||
"help": "Optimization._info.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"ScreenshotInterval": {
|
"ScreenshotInterval": {
|
||||||
"name": "Optimization.ScreenshotInterval.name",
|
"name": "Take Screenshots Every X Second(s)",
|
||||||
"help": "Optimization.ScreenshotInterval.help"
|
"help": "Minimum interval between 2 screenshots, limited in 0.1 ~ 0.3, can help reduce CPU on high-end PCs"
|
||||||
},
|
},
|
||||||
"CombatScreenshotInterval": {
|
"CombatScreenshotInterval": {
|
||||||
"name": "Optimization.CombatScreenshotInterval.name",
|
"name": "Take Screenshots Every X Second(s) In Combat",
|
||||||
"help": "Optimization.CombatScreenshotInterval.help"
|
"help": "Minimum interval between 2 screenshots, limited in 0.1 ~ 1.0, can help reduce CPU during battle"
|
||||||
},
|
},
|
||||||
"WhenTaskQueueEmpty": {
|
"WhenTaskQueueEmpty": {
|
||||||
"name": "Optimization.WhenTaskQueueEmpty.name",
|
"name": "When Task Queue is Empty",
|
||||||
"help": "Optimization.WhenTaskQueueEmpty.help",
|
"help": "Close AL when there are no pending tasks, can help reduce CPU",
|
||||||
"stay_there": "stay_there",
|
"stay_there": "Stay There",
|
||||||
"goto_main": "goto_main",
|
"goto_main": "Goto Main Page",
|
||||||
"close_game": "close_game"
|
"close_game": "Close Game"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Cafe": {
|
"Cafe": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "Cafe._info.name",
|
"name": "Cafe Settings",
|
||||||
"help": "Cafe._info.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Reward": {
|
"Reward": {
|
||||||
"name": "Cafe.Reward.name",
|
"name": "Claim Reward",
|
||||||
"help": "Cafe.Reward.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Touch": {
|
"Touch": {
|
||||||
"name": "Cafe.Touch.name",
|
"name": "Student Interaction",
|
||||||
"help": "Cafe.Touch.help"
|
"help": "Auto detect intractable student and tap"
|
||||||
},
|
},
|
||||||
"AutoAdjust": {
|
"AutoAdjust": {
|
||||||
"name": "Cafe.AutoAdjust.name",
|
"name": "Interface Auto Adjustment",
|
||||||
"help": "Cafe.AutoAdjust.help"
|
"help": "Auto adjust cafe interface for better student interaction"
|
||||||
|
},
|
||||||
|
"SecondCafe": {
|
||||||
|
"name": "Second Cafe",
|
||||||
|
"help": "Enable auto switch to second cafe and perform interaction"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TacticalChallenge": {
|
"TacticalChallenge": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "TacticalChallenge._info.name",
|
"name": "Tactical Challenge Settings",
|
||||||
"help": "TacticalChallenge._info.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"PlayerSelect": {
|
"PlayerSelect": {
|
||||||
"name": "TacticalChallenge.PlayerSelect.name",
|
"name": "Select Player",
|
||||||
"help": "TacticalChallenge.PlayerSelect.help",
|
"help": "",
|
||||||
"0": "0",
|
"0": "Random",
|
||||||
"1": "1",
|
"1": "First",
|
||||||
"2": "2",
|
"2": "Second",
|
||||||
"3": "3"
|
"3": "Third"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ItemStorage": {
|
"ItemStorage": {
|
||||||
@@ -223,118 +227,118 @@
|
|||||||
"help": "ItemStorage._info.help"
|
"help": "ItemStorage._info.help"
|
||||||
},
|
},
|
||||||
"AP": {
|
"AP": {
|
||||||
"name": "ItemStorage.AP.name",
|
"name": "AP",
|
||||||
"help": "ItemStorage.AP.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Credit": {
|
"Credit": {
|
||||||
"name": "ItemStorage.Credit.name",
|
"name": "Credit",
|
||||||
"help": "ItemStorage.Credit.help"
|
"help": ""
|
||||||
},
|
},
|
||||||
"Pyroxene": {
|
"Pyroxene": {
|
||||||
"name": "ItemStorage.Pyroxene.name",
|
"name": "Pyroxene",
|
||||||
"help": "ItemStorage.Pyroxene.help"
|
"help": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Gui": {
|
"Gui": {
|
||||||
"Aside": {
|
"Aside": {
|
||||||
"Install": "Gui.Aside.Install",
|
"Install": "Install",
|
||||||
"Home": "Gui.Aside.Home",
|
"Home": "Home",
|
||||||
"Develop": "Gui.Aside.Develop",
|
"Develop": "Develop",
|
||||||
"Performance": "Gui.Aside.Performance",
|
"Performance": "Perf.",
|
||||||
"Setting": "Gui.Aside.Setting",
|
"Setting": "Settings",
|
||||||
"AddAlas": "Gui.Aside.AddAlas"
|
"AddAlas": "Add"
|
||||||
},
|
},
|
||||||
"Button": {
|
"Button": {
|
||||||
"Start": "Gui.Button.Start",
|
"Start": "Start",
|
||||||
"Stop": "Gui.Button.Stop",
|
"Stop": "Stop",
|
||||||
"ScrollON": "Gui.Button.ScrollON",
|
"ScrollON": "Auto Scroll ON",
|
||||||
"ScrollOFF": "Gui.Button.ScrollOFF",
|
"ScrollOFF": "Auto Scroll OFF",
|
||||||
"ClearLog": "Gui.Button.ClearLog",
|
"ClearLog": "Clear Log",
|
||||||
"Setting": "Gui.Button.Setting",
|
"Setting": "Setting",
|
||||||
"CheckUpdate": "Gui.Button.CheckUpdate",
|
"CheckUpdate": "Check update",
|
||||||
"ClickToUpdate": "Gui.Button.ClickToUpdate",
|
"ClickToUpdate": "Click to update",
|
||||||
"RetryUpdate": "Gui.Button.RetryUpdate",
|
"RetryUpdate": "Retry update",
|
||||||
"CancelUpdate": "Gui.Button.CancelUpdate"
|
"CancelUpdate": "Cancel update"
|
||||||
},
|
},
|
||||||
"Toast": {
|
"Toast": {
|
||||||
"DisableTranslateMode": "Gui.Toast.DisableTranslateMode",
|
"DisableTranslateMode": "Click here to disable translate mode",
|
||||||
"ConfigSaved": "Gui.Toast.ConfigSaved",
|
"ConfigSaved": "Config saved",
|
||||||
"AlasIsRunning": "Gui.Toast.AlasIsRunning",
|
"AlasIsRunning": "Scheduler is already running",
|
||||||
"ClickToUpdate": "Gui.Toast.ClickToUpdate"
|
"ClickToUpdate": "New update available, click here to update"
|
||||||
},
|
},
|
||||||
"Status": {
|
"Status": {
|
||||||
"Running": "Gui.Status.Running",
|
"Running": "Running",
|
||||||
"Inactive": "Gui.Status.Inactive",
|
"Inactive": "Inactive",
|
||||||
"Warning": "Gui.Status.Warning",
|
"Warning": "Warning",
|
||||||
"Updating": "Gui.Status.Updating"
|
"Updating": "Waiting Update"
|
||||||
},
|
},
|
||||||
"MenuAlas": {
|
"MenuAlas": {
|
||||||
"Overview": "Gui.MenuAlas.Overview",
|
"Overview": "Overview",
|
||||||
"Log": "Gui.MenuAlas.Log"
|
"Log": "Logs"
|
||||||
},
|
},
|
||||||
"MenuDevelop": {
|
"MenuDevelop": {
|
||||||
"HomePage": "Gui.MenuDevelop.HomePage",
|
"HomePage": "Home",
|
||||||
"Translate": "Gui.MenuDevelop.Translate",
|
"Translate": "Translate",
|
||||||
"Update": "Gui.MenuDevelop.Update",
|
"Update": "Updater",
|
||||||
"Remote": "Gui.MenuDevelop.Remote",
|
"Remote": "Remote access",
|
||||||
"Utils": "Gui.MenuDevelop.Utils"
|
"Utils": "Utils"
|
||||||
},
|
},
|
||||||
"Overview": {
|
"Overview": {
|
||||||
"Scheduler": "Gui.Overview.Scheduler",
|
"Scheduler": "Scheduler",
|
||||||
"Log": "Gui.Overview.Log",
|
"Log": "Log",
|
||||||
"Running": "Gui.Overview.Running",
|
"Running": "Running",
|
||||||
"Pending": "Gui.Overview.Pending",
|
"Pending": "Pending",
|
||||||
"Waiting": "Gui.Overview.Waiting",
|
"Waiting": "Waiting",
|
||||||
"NoTask": "Gui.Overview.NoTask"
|
"NoTask": "No Task"
|
||||||
},
|
},
|
||||||
"Dashboard": {
|
"Dashboard": {
|
||||||
"NoData": "Gui.Dashboard.NoData",
|
"NoData": "no data",
|
||||||
"TimeError": "Gui.Dashboard.TimeError",
|
"TimeError": "time error",
|
||||||
"JustNow": "Gui.Dashboard.JustNow",
|
"JustNow": "just now",
|
||||||
"MinutesAgo": "Gui.Dashboard.MinutesAgo",
|
"MinutesAgo": "{time}min ago",
|
||||||
"HoursAgo": "Gui.Dashboard.HoursAgo",
|
"HoursAgo": "{time}h ago",
|
||||||
"DaysAgo": "Gui.Dashboard.DaysAgo",
|
"DaysAgo": "{time}d ago",
|
||||||
"LongTimeAgo": "Gui.Dashboard.LongTimeAgo"
|
"LongTimeAgo": "long time ago"
|
||||||
},
|
},
|
||||||
"AddAlas": {
|
"AddAlas": {
|
||||||
"PopupTitle": "Gui.AddAlas.PopupTitle",
|
"PopupTitle": "Add new config",
|
||||||
"NewName": "Gui.AddAlas.NewName",
|
"NewName": "New name",
|
||||||
"CopyFrom": "Gui.AddAlas.CopyFrom",
|
"CopyFrom": "Copy from existing config",
|
||||||
"Confirm": "Gui.AddAlas.Confirm",
|
"Confirm": "Add",
|
||||||
"FileExist": "Gui.AddAlas.FileExist",
|
"FileExist": "A config with the same name exists, please choose another one",
|
||||||
"InvalidChar": "Gui.AddAlas.InvalidChar",
|
"InvalidChar": "Config name cannot contain any of the following characters: .\\/:*?\"<>|",
|
||||||
"InvalidPrefixTemplate": "Gui.AddAlas.InvalidPrefixTemplate"
|
"InvalidPrefixTemplate": "Config name cannot start with 'template'"
|
||||||
},
|
},
|
||||||
"Update": {
|
"Update": {
|
||||||
"UpToDate": "Gui.Update.UpToDate",
|
"UpToDate": "Latest version",
|
||||||
"HaveUpdate": "Gui.Update.HaveUpdate",
|
"HaveUpdate": "A new version is available",
|
||||||
"UpdateStart": "Gui.Update.UpdateStart",
|
"UpdateStart": "Start update",
|
||||||
"UpdateWait": "Gui.Update.UpdateWait",
|
"UpdateWait": "Waiting for all AAS complete current task",
|
||||||
"UpdateRun": "Gui.Update.UpdateRun",
|
"UpdateRun": "Updating",
|
||||||
"UpdateSuccess": "Gui.Update.UpdateSuccess",
|
"UpdateSuccess": "Update succeeded, restarting",
|
||||||
"UpdateFailed": "Gui.Update.UpdateFailed",
|
"UpdateFailed": "Update failed. Logs can be found in ./log/*_gui.txt",
|
||||||
"UpdateChecking": "Gui.Update.UpdateChecking",
|
"UpdateChecking": "Checking for updates",
|
||||||
"UpdateCancel": "Gui.Update.UpdateCancel",
|
"UpdateCancel": "Update canceled, restarting AAS",
|
||||||
"UpdateFinish": "Gui.Update.UpdateFinish",
|
"UpdateFinish": "Update succeeded, please restart manually",
|
||||||
"Local": "Gui.Update.Local",
|
"Local": "Local",
|
||||||
"Upstream": "Gui.Update.Upstream",
|
"Upstream": "Upstream",
|
||||||
"Author": "Gui.Update.Author",
|
"Author": "Author",
|
||||||
"Time": "Gui.Update.Time",
|
"Time": "Commit time",
|
||||||
"Message": "Gui.Update.Message",
|
"Message": "Commit message",
|
||||||
"DisabledWarn": "Gui.Update.DisabledWarn",
|
"DisabledWarn": "Updater module is disabled. You need to manually restart AAS to update",
|
||||||
"DetailedHistory": "Gui.Update.DetailedHistory"
|
"DetailedHistory": "Detailed Commit History"
|
||||||
},
|
},
|
||||||
"Remote": {
|
"Remote": {
|
||||||
"Running": "Gui.Remote.Running",
|
"Running": "Remote access on",
|
||||||
"NotRunning": "Gui.Remote.NotRunning",
|
"NotRunning": "Not running, server disconnected or offline",
|
||||||
"NotEnable": "Gui.Remote.NotEnable",
|
"NotEnable": "Disabled, set webui password in deploy.yaml and enable remote access",
|
||||||
"EntryPoint": "Gui.Remote.EntryPoint",
|
"EntryPoint": "Entry point:",
|
||||||
"ConfigureHint": "Gui.Remote.ConfigureHint",
|
"ConfigureHint": "Configuration tutorial:",
|
||||||
"SSHNotInstall": "Gui.Remote.SSHNotInstall"
|
"SSHNotInstall": "No SSH command in your system. Please refer to the tutorial to download or install one"
|
||||||
},
|
},
|
||||||
"Text": {
|
"Text": {
|
||||||
"InvalidFeedBack": "Gui.Text.InvalidFeedBack",
|
"InvalidFeedBack": "Invalid format. Example: {0}",
|
||||||
"Clear": "Gui.Text.Clear"
|
"Clear": "Clear"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,6 +201,10 @@
|
|||||||
"AutoAdjust": {
|
"AutoAdjust": {
|
||||||
"name": "自动调整界面",
|
"name": "自动调整界面",
|
||||||
"help": "在进行学生互动点击前对咖啡馆界面进行缩放和位置调整,以增加互动成功率"
|
"help": "在进行学生互动点击前对咖啡馆界面进行缩放和位置调整,以增加互动成功率"
|
||||||
|
},
|
||||||
|
"SecondCafe": {
|
||||||
|
"name": "第二咖啡厅",
|
||||||
|
"help": "自动切换第二咖啡厅进行互动点击"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TacticalChallenge": {
|
"TacticalChallenge": {
|
||||||
@@ -309,19 +313,19 @@
|
|||||||
"UpToDate": "已是最新版本",
|
"UpToDate": "已是最新版本",
|
||||||
"HaveUpdate": "有新版本可用",
|
"HaveUpdate": "有新版本可用",
|
||||||
"UpdateStart": "开始更新",
|
"UpdateStart": "开始更新",
|
||||||
"UpdateWait": "等待所有 Alas 完成当前任务",
|
"UpdateWait": "等待所有 AAS 完成当前任务",
|
||||||
"UpdateRun": "更新中",
|
"UpdateRun": "更新中",
|
||||||
"UpdateSuccess": "更新成功,正在重启",
|
"UpdateSuccess": "更新成功,正在重启",
|
||||||
"UpdateFailed": "更新失败,可在./log/*_gui.txt中找到错误日志",
|
"UpdateFailed": "更新失败,可在./log/*_gui.txt中找到错误日志",
|
||||||
"UpdateChecking": "检查更新中",
|
"UpdateChecking": "检查更新中",
|
||||||
"UpdateCancel": "取消更新,重启 Alas 中",
|
"UpdateCancel": "取消更新,重启 AAS 中",
|
||||||
"UpdateFinish": "更新成功,请手动重启",
|
"UpdateFinish": "更新成功,请手动重启",
|
||||||
"Local": "本地",
|
"Local": "本地",
|
||||||
"Upstream": "上游仓库",
|
"Upstream": "上游仓库",
|
||||||
"Author": "作者",
|
"Author": "作者",
|
||||||
"Time": "提交时间",
|
"Time": "提交时间",
|
||||||
"Message": "提交信息",
|
"Message": "提交信息",
|
||||||
"DisabledWarn": "更新模块未启用,你需要手动重启 Alas 进行更新",
|
"DisabledWarn": "更新模块未启用,你需要手动重启 AAS 进行更新",
|
||||||
"DetailedHistory": "详细提交历史"
|
"DetailedHistory": "详细提交历史"
|
||||||
},
|
},
|
||||||
"Remote": {
|
"Remote": {
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
|||||||
self.click(ClickButton(button=area_offset(point_random, p2), name=name))
|
self.click(ClickButton(button=area_offset(point_random, p2), name=name))
|
||||||
|
|
||||||
# just used in cafe
|
# just used in cafe
|
||||||
def pinch(self, box=(33, 130, 1247, 569), name='PINCH'):
|
def pinch(self, box=(35, 130, 1250, 560), name='PINCH'):
|
||||||
self.handle_control_check(name)
|
self.handle_control_check(name)
|
||||||
middle_point = (box[0] + box[2]) // 2, (box[1] + box[3]) // 2
|
middle_point = (box[0] + box[2]) // 2, (box[1] + box[3]) // 2
|
||||||
width = box[2] - middle_point[0]
|
width = box[2] - middle_point[0]
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from module.base.base import ModuleBase
|
||||||
|
from module.base.button import ButtonWrapper, ClickButton
|
||||||
|
from module.base.timer import Timer
|
||||||
|
from module.base.utils import area_pad, area_size, area_offset, random_rectangle_vector_opted
|
||||||
|
from module.logger import logger
|
||||||
|
from module.ocr.ocr import Ocr
|
||||||
|
|
||||||
|
|
||||||
|
class StageList:
|
||||||
|
drag_vector_range = (0.65, 0.85)
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
area_stage: ButtonWrapper,
|
||||||
|
area_index: ButtonWrapper,
|
||||||
|
area_item: ButtonWrapper,
|
||||||
|
button_enter: ButtonWrapper,
|
||||||
|
drag_direction: str = "down"
|
||||||
|
):
|
||||||
|
self.name = name
|
||||||
|
self.stage = area_stage
|
||||||
|
self.index_ocr = Ocr(area_index, lang='en')
|
||||||
|
self.stage_item = area_item.button
|
||||||
|
self.enter = button_enter
|
||||||
|
self.drag_direction = drag_direction
|
||||||
|
|
||||||
|
self.current_index_min = 1
|
||||||
|
self.current_index_max = 1
|
||||||
|
self.current_indexes = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'StageList({self.name})'
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return str(self) == str(other)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.name)
|
||||||
|
|
||||||
|
def _get_indexes(self) -> list[int]:
|
||||||
|
return list(map(lambda x: int(x.ocr_text), self.current_indexes))
|
||||||
|
|
||||||
|
def load_stage_indexes(self, main: ModuleBase):
|
||||||
|
self.current_indexes = list(
|
||||||
|
filter(lambda x: x.ocr_text.isdigit(), self.index_ocr.detect_and_ocr(main.device.image))
|
||||||
|
)
|
||||||
|
if not self.current_indexes:
|
||||||
|
logger.warning(f'No valid index in {self.index_ocr.name}')
|
||||||
|
return
|
||||||
|
indexes = self._get_indexes()
|
||||||
|
|
||||||
|
self.current_index_min = min(indexes)
|
||||||
|
self.current_index_max = max(indexes)
|
||||||
|
logger.attr(self.index_ocr.name, f'Index range: {self.current_index_min} - {self.current_index_max}')
|
||||||
|
|
||||||
|
def drag_page(self, direction: str, main: ModuleBase, vector_range=None, reverse=False):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
direction: up, down
|
||||||
|
main:
|
||||||
|
vector_range (tuple[float, float]):
|
||||||
|
reverse (bool):
|
||||||
|
"""
|
||||||
|
if vector_range is None:
|
||||||
|
vector_range = self.drag_vector_range
|
||||||
|
vector = np.random.uniform(*vector_range)
|
||||||
|
width, height = area_size(self.stage.button)
|
||||||
|
if direction == 'up':
|
||||||
|
vector = (0, vector * height)
|
||||||
|
elif direction == 'down':
|
||||||
|
vector = (0, -vector * height)
|
||||||
|
else:
|
||||||
|
logger.warning(f'Unknown drag direction: {direction}')
|
||||||
|
return
|
||||||
|
|
||||||
|
if reverse:
|
||||||
|
vector = (-vector[0], -vector[1])
|
||||||
|
p1, p2 = random_rectangle_vector_opted(vector, box=self.stage.button)
|
||||||
|
main.device.drag(p1, p2, name=f'{self.name}_DRAG')
|
||||||
|
|
||||||
|
def insight_index(self, index: int, main: ModuleBase, skip_first_screenshot=True) -> bool:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
index:
|
||||||
|
main:
|
||||||
|
skip_first_screenshot:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
If success
|
||||||
|
"""
|
||||||
|
logger.info(f'Insight index: {index}')
|
||||||
|
last_indexes: set[int] = set()
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
main.device.screenshot()
|
||||||
|
|
||||||
|
self.load_stage_indexes(main=main)
|
||||||
|
|
||||||
|
if self.current_index_min <= index <= self.current_index_max:
|
||||||
|
break
|
||||||
|
|
||||||
|
if index < self.current_index_min:
|
||||||
|
self.drag_page(self.drag_direction, main, reverse=True)
|
||||||
|
elif index > self.current_index_max:
|
||||||
|
self.drag_page(self.drag_direction, main)
|
||||||
|
|
||||||
|
main.wait_until_stable(
|
||||||
|
self.stage.button,
|
||||||
|
timer=Timer(0, 0),
|
||||||
|
timeout=Timer(1.5, 5)
|
||||||
|
)
|
||||||
|
|
||||||
|
indexes = self._get_indexes()
|
||||||
|
if indexes and last_indexes == set(indexes):
|
||||||
|
logger.warning(f'No more index {index}')
|
||||||
|
return False
|
||||||
|
last_indexes = set(indexes)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _match_clickable_points(image, template, threshold=0.85):
|
||||||
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||||
|
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
|
||||||
|
loc = np.where(res >= threshold)
|
||||||
|
return [point for point in zip(*loc[::-1])]
|
||||||
|
|
||||||
|
def select_index_enter(
|
||||||
|
self,
|
||||||
|
index: int,
|
||||||
|
main: ModuleBase,
|
||||||
|
insight: bool = True,
|
||||||
|
skip_first_screenshot: bool = True,
|
||||||
|
interval: int = 5
|
||||||
|
) -> bool:
|
||||||
|
if insight and not self.insight_index(index, main, skip_first_screenshot):
|
||||||
|
return False
|
||||||
|
logger.info(f'Select index: {index}')
|
||||||
|
click_interval = Timer(interval)
|
||||||
|
load_index_interval = Timer(1)
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
main.device.screenshot()
|
||||||
|
|
||||||
|
if load_index_interval.reached_and_reset():
|
||||||
|
self.load_stage_indexes(main=main)
|
||||||
|
|
||||||
|
index_box = next(filter(lambda x: int(x.ocr_text) == index, self.current_indexes), None)
|
||||||
|
|
||||||
|
if index_box is None:
|
||||||
|
logger.warning(f'No index {index} in {self.index_ocr.name}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
stage_item_box = area_pad((0, 0, *area_size(self.stage_item)))
|
||||||
|
search_box = area_offset(stage_item_box, index_box.box[:2])
|
||||||
|
search_image = main.image_crop(search_box)
|
||||||
|
points = self._match_clickable_points(search_image, self.enter.matched_button.image)
|
||||||
|
|
||||||
|
if not points:
|
||||||
|
logger.warning(f'No clickable {self.enter.name}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
point = area_offset((0, 0, *area_size(self.enter.button)), points[0])
|
||||||
|
click_button = ClickButton(area_offset(point, search_box[:2]), name=self.enter.name)
|
||||||
|
|
||||||
|
if click_interval.reached_and_reset():
|
||||||
|
main.device.click(click_button)
|
||||||
|
return True
|
||||||
@@ -376,7 +376,7 @@ def add_css(filepath):
|
|||||||
|
|
||||||
|
|
||||||
def _read(path):
|
def _read(path):
|
||||||
with open(path, "r") as f:
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ AFFECTION_LEVEL_UP = ButtonWrapper(
|
|||||||
button=(882, 244, 1176, 476),
|
button=(882, 244, 1176, 476),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
AP_EXCEED = ButtonWrapper(
|
||||||
|
name='AP_EXCEED',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/base/popup/AP_EXCEED.png',
|
||||||
|
area=(610, 124, 669, 153),
|
||||||
|
search=(590, 104, 689, 173),
|
||||||
|
color=(139, 153, 168),
|
||||||
|
button=(535, 494, 746, 565),
|
||||||
|
),
|
||||||
|
)
|
||||||
DAILY_NEWS = ButtonWrapper(
|
DAILY_NEWS = ButtonWrapper(
|
||||||
name='DAILY_NEWS',
|
name='DAILY_NEWS',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
@@ -27,9 +37,9 @@ DAILY_REWARD = ButtonWrapper(
|
|||||||
name='DAILY_REWARD',
|
name='DAILY_REWARD',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
file='./assets/jp/base/popup/DAILY_REWARD.png',
|
file='./assets/jp/base/popup/DAILY_REWARD.png',
|
||||||
area=(854, 117, 1008, 165),
|
area=(416, 165, 434, 216),
|
||||||
search=(834, 97, 1028, 185),
|
search=(396, 145, 454, 236),
|
||||||
color=(178, 167, 112),
|
color=(203, 227, 237),
|
||||||
button=(920, 632, 1140, 712),
|
button=(920, 632, 1140, 712),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -63,6 +73,16 @@ GET_REWARD_SKIP = ButtonWrapper(
|
|||||||
button=(1137, 34, 1243, 65),
|
button=(1137, 34, 1243, 65),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
ITEM_EXPIRED = ButtonWrapper(
|
||||||
|
name='ITEM_EXPIRED',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/base/popup/ITEM_EXPIRED.png',
|
||||||
|
area=(612, 147, 668, 175),
|
||||||
|
search=(592, 127, 688, 195),
|
||||||
|
color=(131, 145, 162),
|
||||||
|
button=(537, 487, 742, 553),
|
||||||
|
),
|
||||||
|
)
|
||||||
NETWORK_RECONNECT = ButtonWrapper(
|
NETWORK_RECONNECT = ButtonWrapper(
|
||||||
name='NETWORK_RECONNECT',
|
name='NETWORK_RECONNECT',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
@@ -73,3 +93,13 @@ NETWORK_RECONNECT = ButtonWrapper(
|
|||||||
button=(663, 467, 870, 537),
|
button=(663, 467, 870, 537),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
NETWORK_RECONNECT_OK = ButtonWrapper(
|
||||||
|
name='NETWORK_RECONNECT_OK',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/base/popup/NETWORK_RECONNECT_OK.png',
|
||||||
|
area=(744, 487, 791, 515),
|
||||||
|
search=(724, 467, 811, 535),
|
||||||
|
color=(91, 165, 196),
|
||||||
|
button=(665, 468, 870, 536),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from tasks.base.assets.assets_base_page import LOADING_CHECK
|
|||||||
|
|
||||||
|
|
||||||
class PopupHandler(ModuleBase):
|
class PopupHandler(ModuleBase):
|
||||||
def handle_loading(self, interval=5) -> bool:
|
def handle_loading(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
interval:
|
interval:
|
||||||
@@ -13,7 +13,7 @@ class PopupHandler(ModuleBase):
|
|||||||
Returns:
|
Returns:
|
||||||
If handled.
|
If handled.
|
||||||
"""
|
"""
|
||||||
if self.appear(LOADING_CHECK, interval=interval):
|
if self.appear(LOADING_CHECK):
|
||||||
timer = Timer(0.5).start()
|
timer = Timer(0.5).start()
|
||||||
while 1:
|
while 1:
|
||||||
if timer.reached_and_reset():
|
if timer.reached_and_reset():
|
||||||
@@ -27,7 +27,7 @@ class PopupHandler(ModuleBase):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_reward(self, interval=5) -> bool:
|
def handle_reward(self) -> bool:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
interval:
|
interval:
|
||||||
@@ -35,15 +35,13 @@ class PopupHandler(ModuleBase):
|
|||||||
Returns:
|
Returns:
|
||||||
If handled.
|
If handled.
|
||||||
"""
|
"""
|
||||||
if self.appear_then_click(GET_REWARD, interval=interval):
|
if self.appear(GET_REWARD) or self.match_color(GET_REWARD, threshold=30):
|
||||||
timer = Timer(0.2).start()
|
|
||||||
while 1:
|
while 1:
|
||||||
if timer.reached_and_reset():
|
self.device.screenshot()
|
||||||
self.device.screenshot()
|
if self.appear(GET_REWARD) or self.match_color(GET_REWARD, threshold=30):
|
||||||
if self.appear(GET_REWARD):
|
self.click_with_interval(GET_REWARD, interval=0.5)
|
||||||
self.device.click(GET_REWARD)
|
else:
|
||||||
else:
|
break
|
||||||
break
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -52,13 +50,13 @@ class PopupHandler(ModuleBase):
|
|||||||
if self.appear_then_click(GET_REWARD_SKIP, interval=interval):
|
if self.appear_then_click(GET_REWARD_SKIP, interval=interval):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle_daily_news(self, interval=5) -> bool:
|
def handle_daily_news(self, interval=2) -> bool:
|
||||||
if self.appear_then_click(DAILY_NEWS, interval=interval):
|
if self.appear_then_click(DAILY_NEWS, interval=interval):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_daily_reward(self, interval=5) -> bool:
|
def handle_daily_reward(self, interval=2) -> bool:
|
||||||
if self.appear_then_click(DAILY_REWARD, interval=interval):
|
if self.appear_then_click(DAILY_REWARD, interval=interval):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -67,19 +65,19 @@ class PopupHandler(ModuleBase):
|
|||||||
def handle_network_reconnect(self, interval=5) -> bool:
|
def handle_network_reconnect(self, interval=5) -> bool:
|
||||||
if self.appear_then_click(NETWORK_RECONNECT, interval=interval):
|
if self.appear_then_click(NETWORK_RECONNECT, interval=interval):
|
||||||
return True
|
return True
|
||||||
|
if self.appear_then_click(NETWORK_RECONNECT_OK, interval=interval):
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_affection_level_up(self, interval=5) -> bool:
|
def handle_affection_level_up(self) -> bool:
|
||||||
if self.appear_then_click(AFFECTION_LEVEL_UP, interval=interval):
|
if self.appear_then_click(AFFECTION_LEVEL_UP):
|
||||||
timer = Timer(0.2).start()
|
|
||||||
while 1:
|
while 1:
|
||||||
if timer.reached_and_reset():
|
self.device.screenshot()
|
||||||
self.device.screenshot()
|
if self.appear(AFFECTION_LEVEL_UP):
|
||||||
if self.appear(AFFECTION_LEVEL_UP):
|
self.click_with_interval(AFFECTION_LEVEL_UP, interval=1)
|
||||||
self.device.click(AFFECTION_LEVEL_UP)
|
else:
|
||||||
else:
|
break
|
||||||
break
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -89,3 +87,15 @@ class PopupHandler(ModuleBase):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def handle_ap_exceed(self, interval=5) -> bool:
|
||||||
|
if self.appear_then_click(AP_EXCEED, interval=interval):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_item_expired(self, interval=5) -> bool:
|
||||||
|
if self.appear_then_click(ITEM_EXPIRED, interval=interval):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class UI(MainPage):
|
|||||||
self.device.get_orientation()
|
self.device.get_orientation()
|
||||||
|
|
||||||
timeout = Timer(10, count=20).start()
|
timeout = Timer(10, count=20).start()
|
||||||
|
back_timer = Timer(0.5, count=2)
|
||||||
while 1:
|
while 1:
|
||||||
if skip_first_screenshot:
|
if skip_first_screenshot:
|
||||||
skip_first_screenshot = False
|
skip_first_screenshot = False
|
||||||
@@ -76,8 +77,9 @@ class UI(MainPage):
|
|||||||
logger.info("Additional ui page handled")
|
logger.info("Additional ui page handled")
|
||||||
timeout.reset()
|
timeout.reset()
|
||||||
continue
|
continue
|
||||||
logger.info("May be in standby main page")
|
if back_timer.reached_and_reset():
|
||||||
self.device.click(BACK)
|
logger.info("Unknown page, try to back")
|
||||||
|
self.device.click(BACK)
|
||||||
|
|
||||||
app_check()
|
app_check()
|
||||||
minicap_check()
|
minicap_check()
|
||||||
@@ -341,6 +343,10 @@ class UI(MainPage):
|
|||||||
return True
|
return True
|
||||||
if self.handle_new_student():
|
if self.handle_new_student():
|
||||||
return True
|
return True
|
||||||
|
if self.handle_ap_exceed():
|
||||||
|
return True
|
||||||
|
if self.handle_item_expired():
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,46 @@ BOX_CAFE = ButtonWrapper(
|
|||||||
button=(33, 130, 1247, 569),
|
button=(33, 130, 1247, 569),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
CAFE_FIRST = ButtonWrapper(
|
||||||
|
name='CAFE_FIRST',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/cafe/CAFE_FIRST.png',
|
||||||
|
area=(82, 152, 136, 175),
|
||||||
|
search=(62, 132, 156, 195),
|
||||||
|
color=(111, 127, 147),
|
||||||
|
button=(82, 152, 136, 175),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CAFE_SECOND = ButtonWrapper(
|
||||||
|
name='CAFE_SECOND',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/cafe/CAFE_SECOND.png',
|
||||||
|
area=(219, 152, 279, 175),
|
||||||
|
search=(199, 132, 299, 195),
|
||||||
|
color=(110, 126, 146),
|
||||||
|
button=(219, 152, 279, 175),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHANGE_CAFE_NOT_SELECTED = ButtonWrapper(
|
||||||
|
name='CHANGE_CAFE_NOT_SELECTED',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/cafe/CHANGE_CAFE_NOT_SELECTED.png',
|
||||||
|
area=(84, 89, 178, 109),
|
||||||
|
search=(64, 69, 198, 129),
|
||||||
|
color=(185, 193, 203),
|
||||||
|
button=(84, 89, 178, 109),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHANGE_CAFE_SELECTED = ButtonWrapper(
|
||||||
|
name='CHANGE_CAFE_SELECTED',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/cafe/CHANGE_CAFE_SELECTED.png',
|
||||||
|
area=(40, 87, 191, 112),
|
||||||
|
search=(20, 67, 211, 132),
|
||||||
|
color=(82, 105, 130),
|
||||||
|
button=(40, 87, 191, 112),
|
||||||
|
),
|
||||||
|
)
|
||||||
CHECK_REWARD = ButtonWrapper(
|
CHECK_REWARD = ButtonWrapper(
|
||||||
name='CHECK_REWARD',
|
name='CHECK_REWARD',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
@@ -27,10 +67,10 @@ CLICKABLE_TEMPLATE = ButtonWrapper(
|
|||||||
name='CLICKABLE_TEMPLATE',
|
name='CLICKABLE_TEMPLATE',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
file='./assets/jp/cafe/CLICKABLE_TEMPLATE.png',
|
file='./assets/jp/cafe/CLICKABLE_TEMPLATE.png',
|
||||||
area=(0, 0, 42, 56),
|
area=(619, 332, 660, 387),
|
||||||
search=(0, 0, 62, 76),
|
search=(599, 312, 680, 407),
|
||||||
color=(77, 63, 1),
|
color=(79, 65, 1),
|
||||||
button=(0, 0, 42, 56),
|
button=(619, 332, 660, 387),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
GET_REWARD = ButtonWrapper(
|
GET_REWARD = ButtonWrapper(
|
||||||
@@ -47,20 +87,40 @@ GET_REWARD_CLOSE = ButtonWrapper(
|
|||||||
name='GET_REWARD_CLOSE',
|
name='GET_REWARD_CLOSE',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
file='./assets/jp/cafe/GET_REWARD_CLOSE.png',
|
file='./assets/jp/cafe/GET_REWARD_CLOSE.png',
|
||||||
area=(891, 144, 917, 170),
|
area=(970, 134, 996, 160),
|
||||||
search=(871, 124, 937, 190),
|
search=(950, 114, 1016, 180),
|
||||||
color=(173, 179, 189),
|
color=(172, 179, 188),
|
||||||
button=(891, 144, 917, 170),
|
button=(970, 134, 996, 160),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
GOT_REWARD = ButtonWrapper(
|
GOT_REWARD = ButtonWrapper(
|
||||||
name='GOT_REWARD',
|
name='GOT_REWARD',
|
||||||
jp=Button(
|
jp=Button(
|
||||||
file='./assets/jp/cafe/GOT_REWARD.png',
|
file='./assets/jp/cafe/GOT_REWARD.png',
|
||||||
area=(609, 507, 672, 535),
|
area=(561, 501, 718, 556),
|
||||||
search=(589, 487, 692, 555),
|
search=(541, 481, 738, 576),
|
||||||
color=(174, 175, 174),
|
color=(209, 210, 209),
|
||||||
button=(609, 507, 672, 535),
|
button=(561, 501, 718, 556),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
INVENTORY = ButtonWrapper(
|
||||||
|
name='INVENTORY',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/cafe/INVENTORY.png',
|
||||||
|
area=(553, 94, 725, 122),
|
||||||
|
search=(533, 74, 745, 142),
|
||||||
|
color=(198, 205, 213),
|
||||||
|
button=(1130, 94, 1156, 120),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
MOMOTALK_CLOSE = ButtonWrapper(
|
||||||
|
name='MOMOTALK_CLOSE',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/cafe/MOMOTALK_CLOSE.png',
|
||||||
|
area=(824, 82, 850, 108),
|
||||||
|
search=(804, 62, 870, 128),
|
||||||
|
color=(252, 182, 194),
|
||||||
|
button=(824, 82, 850, 108),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
OCR_CAFE = ButtonWrapper(
|
OCR_CAFE = ButtonWrapper(
|
||||||
|
|||||||
@@ -7,11 +7,21 @@ from module.base.timer import Timer
|
|||||||
from module.base.button import ClickButton
|
from module.base.button import ClickButton
|
||||||
from module.base.utils.utils import area_offset
|
from module.base.utils.utils import area_offset
|
||||||
from module.ocr.ocr import Digit
|
from module.ocr.ocr import Digit
|
||||||
|
from module.ui.switch import Switch
|
||||||
from tasks.base.page import page_cafe
|
from tasks.base.page import page_cafe
|
||||||
from tasks.base.ui import UI
|
from tasks.base.ui import UI
|
||||||
from tasks.cafe.assets.assets_cafe import *
|
from tasks.cafe.assets.assets_cafe import *
|
||||||
|
|
||||||
|
|
||||||
|
SWITCH_CAFE = Switch('Cafe_switch')
|
||||||
|
SWITCH_CAFE.add_state('off', CHANGE_CAFE_NOT_SELECTED)
|
||||||
|
SWITCH_CAFE.add_state('on', CHANGE_CAFE_SELECTED)
|
||||||
|
|
||||||
|
SWITCH_CAFE_SELECT = Switch('Cafe_switch_select')
|
||||||
|
SWITCH_CAFE_SELECT.add_state('1', CAFE_FIRST)
|
||||||
|
SWITCH_CAFE_SELECT.add_state('2', CAFE_SECOND)
|
||||||
|
|
||||||
|
|
||||||
class CafeStatus(Enum):
|
class CafeStatus(Enum):
|
||||||
STUDENT_LIST = 0
|
STUDENT_LIST = 0
|
||||||
OCR = 1
|
OCR = 1
|
||||||
@@ -44,24 +54,25 @@ class Cafe(UI):
|
|||||||
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
||||||
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||||
# set color range
|
# set color range
|
||||||
lower_hsv = np.array([17, 200, 220])
|
lower_hsv = np.array([18, 200, 220])
|
||||||
upper_hsv = np.array([28, 255, 255])
|
upper_hsv = np.array([30, 255, 255])
|
||||||
# get mask
|
# get mask
|
||||||
mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
|
mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
|
||||||
# generate result
|
# generate result
|
||||||
return cv2.bitwise_and(image, image, mask=mask)
|
return cv2.bitwise_and(image, image, mask=mask)
|
||||||
|
|
||||||
def _match_clickable_points(self, image, threshold=0.9):
|
def _match_clickable_points(self, image, threshold=0.8):
|
||||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||||
template = self.btn.matched_button.image
|
template = cv2.cvtColor(self.btn.matched_button.image, cv2.COLOR_BGR2GRAY)
|
||||||
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
|
|
||||||
|
|
||||||
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
|
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
|
||||||
loc = np.where(res >= threshold)
|
loc = np.where(res >= threshold)
|
||||||
return [point for point in zip(*loc[::-1])]
|
return [point for point in zip(*loc[::-1])]
|
||||||
|
|
||||||
def _get_clickable_buttons(self, threshold=0.9, offset=(0, 0)):
|
def _get_clickable_buttons(self, threshold=0.8, offset=(0, 0)):
|
||||||
image = cv2.copyMakeBorder(self.device.image, 20, 20, 10, 60, cv2.BORDER_CONSTANT, value=(0, 0, 0))
|
image = self.device.image
|
||||||
|
h, w = image.shape[:2]
|
||||||
|
image = cv2.rectangle(image, (0, 10), (w - 25, h - 10), (0, 0, 0), 50)
|
||||||
image = self._extract_clickable_from_image(image)
|
image = self._extract_clickable_from_image(image)
|
||||||
points = self._match_clickable_points(image, threshold)
|
points = self._match_clickable_points(image, threshold)
|
||||||
points = self.merge_points(points)
|
points = self.merge_points(points)
|
||||||
@@ -98,6 +109,8 @@ class Cafe(UI):
|
|||||||
case 'right':
|
case 'right':
|
||||||
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
|
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
|
||||||
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
|
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
|
||||||
|
# solve too much swipe causing restart
|
||||||
|
self.device.click_record_clear()
|
||||||
|
|
||||||
def _get_reward_num(self):
|
def _get_reward_num(self):
|
||||||
ocr = Digit(OCR_CAFE)
|
ocr = Digit(OCR_CAFE)
|
||||||
@@ -108,6 +121,13 @@ class Cafe(UI):
|
|||||||
logger.attr('Reward', num)
|
logger.attr('Reward', num)
|
||||||
return num
|
return num
|
||||||
|
|
||||||
|
def _cafe_additional(self) -> bool:
|
||||||
|
if self.appear_then_click(INVENTORY):
|
||||||
|
return True
|
||||||
|
if self.appear_then_click(MOMOTALK_CLOSE):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def _handle_cafe(self, status):
|
def _handle_cafe(self, status):
|
||||||
match status:
|
match status:
|
||||||
case CafeStatus.STUDENT_LIST:
|
case CafeStatus.STUDENT_LIST:
|
||||||
@@ -121,24 +141,26 @@ class Cafe(UI):
|
|||||||
if self.appear_then_click(CHECK_REWARD):
|
if self.appear_then_click(CHECK_REWARD):
|
||||||
return CafeStatus.REWARD
|
return CafeStatus.REWARD
|
||||||
case CafeStatus.REWARD:
|
case CafeStatus.REWARD:
|
||||||
|
if not self.appear(GET_REWARD_CLOSE):
|
||||||
|
self.click_with_interval(CHECK_REWARD)
|
||||||
|
return status
|
||||||
if self.match_color(GOT_REWARD):
|
if self.match_color(GOT_REWARD):
|
||||||
self.device.click(GET_REWARD_CLOSE)
|
self.device.click(GET_REWARD_CLOSE)
|
||||||
return CafeStatus.GOT
|
return CafeStatus.GOT
|
||||||
if not self.appear(GET_REWARD):
|
|
||||||
return CafeStatus.OCR
|
|
||||||
if self.match_color(GET_REWARD):
|
if self.match_color(GET_REWARD):
|
||||||
self.device.click(GET_REWARD)
|
self.click_with_interval(GET_REWARD)
|
||||||
case CafeStatus.GOT:
|
case CafeStatus.GOT:
|
||||||
logger.info('Cafe reward have been got')
|
logger.info('Cafe reward have been got')
|
||||||
self.appear_then_click(GET_REWARD_CLOSE)
|
self.appear_then_click(GET_REWARD_CLOSE)
|
||||||
return CafeStatus.CLICK
|
if not self.appear(GET_REWARD_CLOSE):
|
||||||
|
return CafeStatus.CLICK
|
||||||
case CafeStatus.CLICK:
|
case CafeStatus.CLICK:
|
||||||
buttons = self._get_clickable_buttons(offset=(45, 10))
|
buttons = self._get_clickable_buttons(offset=(45, 10))
|
||||||
self.click = len(buttons)
|
self.click = len(buttons)
|
||||||
logger.attr('Clickable', self.click)
|
logger.attr('Clickable', self.click)
|
||||||
if not buttons:
|
if not buttons:
|
||||||
return CafeStatus.CHECK
|
return CafeStatus.CHECK
|
||||||
self.device.click(buttons[0])
|
self.click_with_interval(buttons[0], interval=1)
|
||||||
case CafeStatus.CHECK:
|
case CafeStatus.CHECK:
|
||||||
buttons = self._get_clickable_buttons()
|
buttons = self._get_clickable_buttons()
|
||||||
if not self.is_adjust_on:
|
if not self.is_adjust_on:
|
||||||
@@ -174,21 +196,25 @@ class Cafe(UI):
|
|||||||
is_reward_on = self.config.Cafe_Reward
|
is_reward_on = self.config.Cafe_Reward
|
||||||
is_touch_on = self.config.Cafe_Touch
|
is_touch_on = self.config.Cafe_Touch
|
||||||
self.is_adjust_on = self.config.Cafe_AutoAdjust
|
self.is_adjust_on = self.config.Cafe_AutoAdjust
|
||||||
|
is_second_cafe_on = self.config.Cafe_SecondCafe
|
||||||
|
|
||||||
self.ui_ensure(page_cafe)
|
self.ui_ensure(page_cafe)
|
||||||
|
|
||||||
status = CafeStatus.STUDENT_LIST
|
status = CafeStatus.STUDENT_LIST
|
||||||
loading_timer = Timer(2).start()
|
loading_timer = Timer(2).start()
|
||||||
action_timer = Timer(1.5, count=1) # cant be too fast
|
action_timer = Timer(1, count=1) # cant be too fast
|
||||||
check_timer = Timer(1, count=1)
|
|
||||||
is_list = False
|
is_list = False
|
||||||
is_reset = False
|
is_reset = False
|
||||||
|
is_second = False
|
||||||
is_enable = is_reward_on or is_touch_on
|
is_enable = is_reward_on or is_touch_on
|
||||||
|
|
||||||
while is_enable:
|
while 1:
|
||||||
|
if not is_enable:
|
||||||
|
break
|
||||||
|
|
||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
|
|
||||||
if self.ui_additional():
|
if self.ui_additional() or self._cafe_additional():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not loading_timer.reached():
|
if not loading_timer.reached():
|
||||||
@@ -196,7 +222,7 @@ class Cafe(UI):
|
|||||||
|
|
||||||
if not is_list and status == CafeStatus.STUDENT_LIST and self.appear(STUDENT_LIST):
|
if not is_list and status == CafeStatus.STUDENT_LIST and self.appear(STUDENT_LIST):
|
||||||
is_list = True
|
is_list = True
|
||||||
loading_timer = Timer(5).start()
|
loading_timer = Timer(3).start()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not is_reward_on and status == CafeStatus.OCR:
|
if not is_reward_on and status == CafeStatus.OCR:
|
||||||
@@ -214,14 +240,37 @@ class Cafe(UI):
|
|||||||
is_reset = True
|
is_reset = True
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if status == CafeStatus.CHECK and not check_timer.reached_and_reset():
|
if is_second_cafe_on and not is_second and status == CafeStatus.FINISHED:
|
||||||
continue
|
if not SWITCH_CAFE.appear(main=self):
|
||||||
|
logger.warning('Cafe switch not found')
|
||||||
|
continue
|
||||||
|
if SWITCH_CAFE.get(main=self) == 'off':
|
||||||
|
SWITCH_CAFE.set('on', main=self)
|
||||||
|
logger.info('Switching to second cafe')
|
||||||
|
if not SWITCH_CAFE_SELECT.appear(main=self):
|
||||||
|
logger.info('Cafe switch select not found')
|
||||||
|
continue
|
||||||
|
match (SWITCH_CAFE_SELECT.get(main=self)):
|
||||||
|
case '1':
|
||||||
|
if self.click_with_interval(CAFE_SECOND):
|
||||||
|
continue
|
||||||
|
case '2':
|
||||||
|
logger.info('Cafe second arrived')
|
||||||
|
SWITCH_CAFE.set('off', main=self)
|
||||||
|
status = CafeStatus.STUDENT_LIST
|
||||||
|
is_list = False
|
||||||
|
is_second = True
|
||||||
|
self.check = 0
|
||||||
|
|
||||||
if action_timer.reached_and_reset():
|
if action_timer.reached_and_reset():
|
||||||
status = self._handle_cafe(status)
|
|
||||||
logger.attr('Status', status)
|
logger.attr('Status', status)
|
||||||
|
status = self._handle_cafe(status)
|
||||||
|
|
||||||
if status is CafeStatus.FINISHED:
|
if not is_second_cafe_on:
|
||||||
break
|
if status is CafeStatus.FINISHED:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if is_second and status is CafeStatus.FINISHED:
|
||||||
|
break
|
||||||
|
|
||||||
self.config.task_delay(server_update=True, minute=180)
|
self.config.task_delay(server_update=True, minute=180)
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ class Circle(UI):
|
|||||||
status = CircleStatus.GOT
|
status = CircleStatus.GOT
|
||||||
|
|
||||||
if action_timer.reached_and_reset():
|
if action_timer.reached_and_reset():
|
||||||
status = self._handle_circle(status)
|
|
||||||
logger.attr('Status', status)
|
logger.attr('Status', status)
|
||||||
|
status = self._handle_circle(status)
|
||||||
|
|
||||||
if status is CircleStatus.FINISHED:
|
if status is CircleStatus.FINISHED:
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -23,3 +23,13 @@ LOGIN_LOADING = ButtonWrapper(
|
|||||||
button=(34, 682, 60, 707),
|
button=(34, 682, 60, 707),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
UPDATE = ButtonWrapper(
|
||||||
|
name='UPDATE',
|
||||||
|
jp=Button(
|
||||||
|
file='./assets/jp/login/UPDATE.png',
|
||||||
|
area=(526, 87, 756, 117),
|
||||||
|
search=(506, 67, 776, 137),
|
||||||
|
color=(183, 192, 201),
|
||||||
|
button=(666, 527, 872, 595),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ from module.exception import GameNotRunningError
|
|||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from tasks.base.page import page_main
|
from tasks.base.page import page_main
|
||||||
from tasks.base.ui import UI
|
from tasks.base.ui import UI
|
||||||
# from tasks.login.assets.assets_login import LOGIN_CONFIRM, USER_AGREEMENT_ACCEPT, LOGIN_LOADING
|
from tasks.login.assets.assets_login import LOGIN_CONFIRM, LOGIN_LOADING, UPDATE
|
||||||
from tasks.login.assets.assets_login import LOGIN_CONFIRM, LOGIN_LOADING
|
|
||||||
|
|
||||||
|
|
||||||
class Login(UI):
|
class Login(UI):
|
||||||
@@ -77,6 +76,8 @@ class Login(UI):
|
|||||||
# continue
|
# continue
|
||||||
# if self.handle_popup_confirm():
|
# if self.handle_popup_confirm():
|
||||||
# continue
|
# continue
|
||||||
|
if self.appear_then_click(UPDATE):
|
||||||
|
continue
|
||||||
if self.ui_additional():
|
if self.ui_additional():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ class TacticalChallenge(UI):
|
|||||||
if self.appear_then_click(CHALLENGE_LOSE):
|
if self.appear_then_click(CHALLENGE_LOSE):
|
||||||
return TCStatus.LOSE
|
return TCStatus.LOSE
|
||||||
case TCStatus.WIN | TCStatus.LOSE:
|
case TCStatus.WIN | TCStatus.LOSE:
|
||||||
if self.appear(CHALLENGE_WIN) or self.appear(CHALLENGE_LOSE):
|
if self.appear_then_click(CHALLENGE_WIN) or self.appear_then_click(CHALLENGE_LOSE):
|
||||||
return TCStatus.RESULT
|
return status
|
||||||
is_valid, ticket = self._get_ticket()
|
is_valid, ticket = self._get_ticket()
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
return status
|
return status
|
||||||
@@ -146,8 +146,8 @@ class TacticalChallenge(UI):
|
|||||||
if not ui_timer.reached():
|
if not ui_timer.reached():
|
||||||
continue
|
continue
|
||||||
if action_timer.reached_and_reset():
|
if action_timer.reached_and_reset():
|
||||||
status = self._handle_challenge(status)
|
|
||||||
logger.attr('Status', status.name)
|
logger.attr('Status', status.name)
|
||||||
|
status = self._handle_challenge(status)
|
||||||
if status in (TCStatus.FINAL, TCStatus.FINISHED):
|
if status in (TCStatus.FINAL, TCStatus.FINISHED):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||