mirror of
https://github.com/TheFunny/ArisuAutoSweeper
synced 2026-06-23 22:44:51 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
61fa6ad28b
|
|||
|
0551207714
|
|||
|
826a6b2348
|
|||
|
a05c4e8f2f
|
|||
|
a20411071c
|
|||
|
d53e280bfc
|
|||
|
0b2487487b
|
|||
|
bea794386c
|
|||
|
57c0ed8531
|
|||
|
75e6417620
|
|||
|
96b5f1db85
|
|||
|
51305f7c0b
|
|||
|
22647a5e36
|
|||
|
080c4c130c
|
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
@@ -43,7 +43,8 @@
|
||||
"Cafe": {
|
||||
"Reward": true,
|
||||
"Touch": true,
|
||||
"AutoAdjust": true
|
||||
"AutoAdjust": true,
|
||||
"SecondCafe": true
|
||||
}
|
||||
},
|
||||
"Mail": {
|
||||
|
||||
@@ -65,9 +65,6 @@ class ConfigModel:
|
||||
AppAsarUpdate: bool = True
|
||||
NoSandbox: bool = True
|
||||
|
||||
# Dynamic
|
||||
GitOverCdn: bool = False
|
||||
|
||||
|
||||
class DeployConfig(ConfigModel):
|
||||
def __init__(self, file=DEPLOY_CONFIG):
|
||||
@@ -82,8 +79,9 @@ class DeployConfig(ConfigModel):
|
||||
|
||||
# Bypass webui.config.DeployConfig.__setattr__()
|
||||
# Don't write these into deploy.yaml
|
||||
super().__setattr__('GitOverCdn', self.Repository in ['cn'])
|
||||
if self.Repository in ['global', 'cn']:
|
||||
if self.Repository == 'cn':
|
||||
super().__setattr__('Repository', 'https://git.yoursfunny.top/YoursFunny/ArisuAutoSweeper.git')
|
||||
if self.Repository == 'global':
|
||||
super().__setattr__('Repository', 'https://github.com/TheFunny/ArisuAutoSweeper')
|
||||
|
||||
self.write()
|
||||
|
||||
@@ -4,7 +4,6 @@ import os
|
||||
from deploy.Windows.config import DeployConfig
|
||||
from deploy.Windows.logger import Progress, logger
|
||||
from deploy.Windows.utils import cached_property
|
||||
# from deploy.git_over_cdn.client import GitOverCdnClient
|
||||
|
||||
|
||||
class GitConfigParser(configparser.ConfigParser):
|
||||
@@ -17,25 +16,6 @@ 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):
|
||||
@@ -128,18 +108,6 @@ class GitManager(DeployConfig):
|
||||
self.execute(f'"{self.git}" --no-pager log --no-merges -1')
|
||||
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):
|
||||
logger.hr('Update Alas', 0)
|
||||
|
||||
@@ -148,10 +116,6 @@ class GitManager(DeployConfig):
|
||||
Progress.GitShowVersion()
|
||||
return
|
||||
|
||||
# if self.GitOverCdn:
|
||||
# if self.goc_client.update(keep_changes=self.KeepLocalChanges):
|
||||
# return
|
||||
|
||||
self.git_repository_init(
|
||||
repo=self.Repository,
|
||||
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
|
||||
@@ -128,6 +128,14 @@ class ModuleBase:
|
||||
self.device.click(button)
|
||||
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)):
|
||||
"""
|
||||
A terrible method, don't rely too much on it.
|
||||
|
||||
@@ -194,6 +194,10 @@
|
||||
"AutoAdjust": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
},
|
||||
"SecondCafe": {
|
||||
"type": "checkbox",
|
||||
"value": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -79,6 +79,7 @@ Cafe:
|
||||
Reward: true
|
||||
Touch: true
|
||||
AutoAdjust: true
|
||||
SecondCafe: true
|
||||
|
||||
TacticalChallenge:
|
||||
PlayerSelect:
|
||||
|
||||
@@ -43,6 +43,7 @@ class GeneratedConfig:
|
||||
Cafe_Reward = True
|
||||
Cafe_Touch = True
|
||||
Cafe_AutoAdjust = True
|
||||
Cafe_SecondCafe = True
|
||||
|
||||
# Group `TacticalChallenge`
|
||||
TacticalChallenge_PlayerSelect = 0 # 0, 1, 2, 3
|
||||
|
||||
@@ -201,6 +201,10 @@
|
||||
"AutoAdjust": {
|
||||
"name": "Cafe.AutoAdjust.name",
|
||||
"help": "Cafe.AutoAdjust.help"
|
||||
},
|
||||
"SecondCafe": {
|
||||
"name": "Cafe.SecondCafe.name",
|
||||
"help": "Cafe.SecondCafe.help"
|
||||
}
|
||||
},
|
||||
"TacticalChallenge": {
|
||||
|
||||
@@ -201,6 +201,10 @@
|
||||
"AutoAdjust": {
|
||||
"name": "自动调整界面",
|
||||
"help": "在进行学生互动点击前对咖啡馆界面进行缩放和位置调整,以增加互动成功率"
|
||||
},
|
||||
"SecondCafe": {
|
||||
"name": "第二咖啡厅",
|
||||
"help": "自动切换第二咖啡厅进行互动点击"
|
||||
}
|
||||
},
|
||||
"TacticalChallenge": {
|
||||
|
||||
+18
-22
@@ -5,7 +5,7 @@ from tasks.base.assets.assets_base_page import LOADING_CHECK
|
||||
|
||||
|
||||
class PopupHandler(ModuleBase):
|
||||
def handle_loading(self, interval=5) -> bool:
|
||||
def handle_loading(self) -> bool:
|
||||
"""
|
||||
Args:
|
||||
interval:
|
||||
@@ -13,7 +13,7 @@ class PopupHandler(ModuleBase):
|
||||
Returns:
|
||||
If handled.
|
||||
"""
|
||||
if self.appear(LOADING_CHECK, interval=interval):
|
||||
if self.appear(LOADING_CHECK):
|
||||
timer = Timer(0.5).start()
|
||||
while 1:
|
||||
if timer.reached_and_reset():
|
||||
@@ -27,7 +27,7 @@ class PopupHandler(ModuleBase):
|
||||
|
||||
return False
|
||||
|
||||
def handle_reward(self, interval=5) -> bool:
|
||||
def handle_reward(self) -> bool:
|
||||
"""
|
||||
Args:
|
||||
interval:
|
||||
@@ -35,15 +35,13 @@ class PopupHandler(ModuleBase):
|
||||
Returns:
|
||||
If handled.
|
||||
"""
|
||||
if self.appear_then_click(GET_REWARD, interval=interval):
|
||||
timer = Timer(0.2).start()
|
||||
if self.appear(GET_REWARD) or self.match_color(GET_REWARD, threshold=30):
|
||||
while 1:
|
||||
if timer.reached_and_reset():
|
||||
self.device.screenshot()
|
||||
if self.appear(GET_REWARD):
|
||||
self.device.click(GET_REWARD)
|
||||
else:
|
||||
break
|
||||
self.device.screenshot()
|
||||
if self.appear(GET_REWARD) or self.match_color(GET_REWARD, threshold=30):
|
||||
self.click_with_interval(GET_REWARD, interval=0.5)
|
||||
else:
|
||||
break
|
||||
return True
|
||||
|
||||
return False
|
||||
@@ -52,13 +50,13 @@ class PopupHandler(ModuleBase):
|
||||
if self.appear_then_click(GET_REWARD_SKIP, interval=interval):
|
||||
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):
|
||||
return True
|
||||
|
||||
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):
|
||||
return True
|
||||
|
||||
@@ -70,16 +68,14 @@ class PopupHandler(ModuleBase):
|
||||
|
||||
return False
|
||||
|
||||
def handle_affection_level_up(self, interval=5) -> bool:
|
||||
if self.appear_then_click(AFFECTION_LEVEL_UP, interval=interval):
|
||||
timer = Timer(0.2).start()
|
||||
def handle_affection_level_up(self) -> bool:
|
||||
if self.appear_then_click(AFFECTION_LEVEL_UP):
|
||||
while 1:
|
||||
if timer.reached_and_reset():
|
||||
self.device.screenshot()
|
||||
if self.appear(AFFECTION_LEVEL_UP):
|
||||
self.device.click(AFFECTION_LEVEL_UP)
|
||||
else:
|
||||
break
|
||||
self.device.screenshot()
|
||||
if self.appear(AFFECTION_LEVEL_UP):
|
||||
self.click_with_interval(AFFECTION_LEVEL_UP, interval=1)
|
||||
else:
|
||||
break
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
+4
-2
@@ -49,6 +49,7 @@ class UI(MainPage):
|
||||
self.device.get_orientation()
|
||||
|
||||
timeout = Timer(10, count=20).start()
|
||||
back_timer = Timer(0.5, count=2)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
@@ -76,8 +77,9 @@ class UI(MainPage):
|
||||
logger.info("Additional ui page handled")
|
||||
timeout.reset()
|
||||
continue
|
||||
logger.info("May be in standby main page")
|
||||
self.device.click(BACK)
|
||||
if back_timer.reached_and_reset():
|
||||
logger.info("Unknown page, try to back")
|
||||
self.device.click(BACK)
|
||||
|
||||
app_check()
|
||||
minicap_check()
|
||||
|
||||
@@ -13,6 +13,46 @@ BOX_CAFE = ButtonWrapper(
|
||||
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(
|
||||
name='CHECK_REWARD',
|
||||
jp=Button(
|
||||
@@ -47,20 +87,20 @@ GET_REWARD_CLOSE = ButtonWrapper(
|
||||
name='GET_REWARD_CLOSE',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/GET_REWARD_CLOSE.png',
|
||||
area=(891, 144, 917, 170),
|
||||
search=(871, 124, 937, 190),
|
||||
color=(173, 179, 189),
|
||||
button=(891, 144, 917, 170),
|
||||
area=(970, 134, 996, 160),
|
||||
search=(950, 114, 1016, 180),
|
||||
color=(172, 179, 188),
|
||||
button=(970, 134, 996, 160),
|
||||
),
|
||||
)
|
||||
GOT_REWARD = ButtonWrapper(
|
||||
name='GOT_REWARD',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/GOT_REWARD.png',
|
||||
area=(609, 507, 672, 535),
|
||||
search=(589, 487, 692, 555),
|
||||
color=(174, 175, 174),
|
||||
button=(609, 507, 672, 535),
|
||||
area=(561, 501, 718, 556),
|
||||
search=(541, 481, 738, 576),
|
||||
color=(209, 210, 209),
|
||||
button=(561, 501, 718, 556),
|
||||
),
|
||||
)
|
||||
OCR_CAFE = ButtonWrapper(
|
||||
|
||||
+60
-19
@@ -7,11 +7,21 @@ from module.base.timer import Timer
|
||||
from module.base.button import ClickButton
|
||||
from module.base.utils.utils import area_offset
|
||||
from module.ocr.ocr import Digit
|
||||
from module.ui.switch import Switch
|
||||
from tasks.base.page import page_cafe
|
||||
from tasks.base.ui import UI
|
||||
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):
|
||||
STUDENT_LIST = 0
|
||||
OCR = 1
|
||||
@@ -44,14 +54,14 @@ class Cafe(UI):
|
||||
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
|
||||
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
|
||||
# set color range
|
||||
lower_hsv = np.array([17, 200, 220])
|
||||
upper_hsv = np.array([28, 255, 255])
|
||||
lower_hsv = np.array([18, 200, 220])
|
||||
upper_hsv = np.array([30, 255, 255])
|
||||
# get mask
|
||||
mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
|
||||
# generate result
|
||||
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)
|
||||
template = self.btn.matched_button.image
|
||||
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
|
||||
@@ -60,8 +70,8 @@ class Cafe(UI):
|
||||
loc = np.where(res >= threshold)
|
||||
return [point for point in zip(*loc[::-1])]
|
||||
|
||||
def _get_clickable_buttons(self, threshold=0.9, offset=(0, 0)):
|
||||
image = cv2.copyMakeBorder(self.device.image, 20, 20, 10, 60, cv2.BORDER_CONSTANT, value=(0, 0, 0))
|
||||
def _get_clickable_buttons(self, threshold=0.8, offset=(0, 0)):
|
||||
image = cv2.copyMakeBorder(self.device.image, 20, 20, 10, 80, cv2.BORDER_CONSTANT, value=(0, 0, 0))
|
||||
image = self._extract_clickable_from_image(image)
|
||||
points = self._match_clickable_points(image, threshold)
|
||||
points = self.merge_points(points)
|
||||
@@ -98,6 +108,8 @@ class Cafe(UI):
|
||||
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)
|
||||
# solve too much swipe causing restart
|
||||
self.device.click_record_clear()
|
||||
|
||||
def _get_reward_num(self):
|
||||
ocr = Digit(OCR_CAFE)
|
||||
@@ -121,24 +133,26 @@ class Cafe(UI):
|
||||
if self.appear_then_click(CHECK_REWARD):
|
||||
return 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):
|
||||
self.device.click(GET_REWARD_CLOSE)
|
||||
return CafeStatus.GOT
|
||||
if not self.appear(GET_REWARD):
|
||||
return CafeStatus.OCR
|
||||
if self.match_color(GET_REWARD):
|
||||
self.device.click(GET_REWARD)
|
||||
self.click_with_interval(GET_REWARD)
|
||||
case CafeStatus.GOT:
|
||||
logger.info('Cafe reward have been got')
|
||||
self.appear_then_click(GET_REWARD_CLOSE)
|
||||
return CafeStatus.CLICK
|
||||
if not self.appear(GET_REWARD_CLOSE):
|
||||
return CafeStatus.CLICK
|
||||
case CafeStatus.CLICK:
|
||||
buttons = self._get_clickable_buttons(offset=(45, 10))
|
||||
self.click = len(buttons)
|
||||
logger.attr('Clickable', self.click)
|
||||
if not buttons:
|
||||
return CafeStatus.CHECK
|
||||
self.device.click(buttons[0])
|
||||
self.click_with_interval(buttons[0], interval=1)
|
||||
case CafeStatus.CHECK:
|
||||
buttons = self._get_clickable_buttons()
|
||||
if not self.is_adjust_on:
|
||||
@@ -174,18 +188,22 @@ class Cafe(UI):
|
||||
is_reward_on = self.config.Cafe_Reward
|
||||
is_touch_on = self.config.Cafe_Touch
|
||||
self.is_adjust_on = self.config.Cafe_AutoAdjust
|
||||
is_second_cafe_on = self.config.Cafe_SecondCafe
|
||||
|
||||
self.ui_ensure(page_cafe)
|
||||
|
||||
status = CafeStatus.STUDENT_LIST
|
||||
loading_timer = Timer(2).start()
|
||||
action_timer = Timer(1.5, count=1) # cant be too fast
|
||||
check_timer = Timer(1, count=1)
|
||||
action_timer = Timer(1, count=1) # cant be too fast
|
||||
is_list = False
|
||||
is_reset = False
|
||||
is_second = False
|
||||
is_enable = is_reward_on or is_touch_on
|
||||
|
||||
while is_enable:
|
||||
while 1:
|
||||
if not is_enable:
|
||||
break
|
||||
|
||||
self.device.screenshot()
|
||||
|
||||
if self.ui_additional():
|
||||
@@ -196,7 +214,7 @@ class Cafe(UI):
|
||||
|
||||
if not is_list and status == CafeStatus.STUDENT_LIST and self.appear(STUDENT_LIST):
|
||||
is_list = True
|
||||
loading_timer = Timer(5).start()
|
||||
loading_timer = Timer(3).start()
|
||||
continue
|
||||
|
||||
if not is_reward_on and status == CafeStatus.OCR:
|
||||
@@ -214,14 +232,37 @@ class Cafe(UI):
|
||||
is_reset = True
|
||||
continue
|
||||
|
||||
if status == CafeStatus.CHECK and not check_timer.reached_and_reset():
|
||||
continue
|
||||
if is_second_cafe_on and not is_second and status == CafeStatus.FINISHED:
|
||||
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():
|
||||
status = self._handle_cafe(status)
|
||||
logger.attr('Status', status)
|
||||
status = self._handle_cafe(status)
|
||||
|
||||
if status is CafeStatus.FINISHED:
|
||||
break
|
||||
if not is_second_cafe_on:
|
||||
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)
|
||||
|
||||
@@ -47,8 +47,8 @@ class Circle(UI):
|
||||
status = CircleStatus.GOT
|
||||
|
||||
if action_timer.reached_and_reset():
|
||||
status = self._handle_circle(status)
|
||||
logger.attr('Status', status)
|
||||
status = self._handle_circle(status)
|
||||
|
||||
if status is CircleStatus.FINISHED:
|
||||
break
|
||||
|
||||
@@ -146,8 +146,8 @@ class TacticalChallenge(UI):
|
||||
if not ui_timer.reached():
|
||||
continue
|
||||
if action_timer.reached_and_reset():
|
||||
status = self._handle_challenge(status)
|
||||
logger.attr('Status', status.name)
|
||||
status = self._handle_challenge(status)
|
||||
if status in (TCStatus.FINAL, TCStatus.FINISHED):
|
||||
break
|
||||
|
||||
|
||||
Reference in New Issue
Block a user