diff --git a/.gitignore b/.gitignore index 13b97bd3d..d2ec2f8c5 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ module/config/i18n/*.json !dev_tools/ViewWizard2/ViewWizard2.exe !dev_tools/ViewWizard3/ViewWizard.exe dev_tools/assets_test.py -hya +#hya deploy/launcher/oas-backend.bat deploy/launcher/oas-server.bat oas-backend.bat diff --git a/deploy/docker/.dockerignore b/deploy/docker/.dockerignore new file mode 100644 index 000000000..e826e6f8a --- /dev/null +++ b/deploy/docker/.dockerignore @@ -0,0 +1,3 @@ + +requirements_generator.py + diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile new file mode 100644 index 000000000..904f605aa --- /dev/null +++ b/deploy/docker/Dockerfile @@ -0,0 +1,37 @@ +# docker build -t qwerty/oas:latest . +# docker run -v ${PWD}:/app/OnmyojiAutoScript -p 22288:22288 --name oas -it --rm qwerty/oas + + +FROM python:3.10-slim-bookworm + +WORKDIR /app/OnmyojiAutoScript + +COPY requirements.txt /tmp/requirements.txt + +# python:3.10-slim is based on debian:12, apt source from https://developer.aliyun.com/mirror/debian +RUN echo "\ +deb https://mirrors.cloud.tencent.com/debian/ bookworm main non-free non-free-firmware contrib \n\ +deb-src https://mirrors.cloud.tencent.com/debian/ bookworm main non-free non-free-firmware contrib \n\ +deb https://mirrors.cloud.tencent.com/debian-security/ bookworm-security main \n\ +deb-src https://mirrors.cloud.tencent.com/debian-security/ bookworm-security main \n\ +deb https://mirrors.cloud.tencent.com/debian/ bookworm-updates main non-free non-free-firmware contrib \n\ +deb-src https://mirrors.cloud.tencent.com/debian/ bookworm-updates main non-free non-free-firmware contrib \n\ +deb https://mirrors.cloud.tencent.com/debian/ bookworm-backports main non-free non-free-firmware contrib \n\ +deb-src https://mirrors.cloud.tencent.com/debian/ bookworm-backports main non-free non-free-firmware contrib \ + "\ +> /etc/apt/sources.list\ + && apt update \ + && apt install -y git adb libgomp1 openssh-client \ + && git config --global --add safe.directory '*' \ + && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo 'Asia/Shanghai' > /etc/timezone \ + && pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple \ + && pip install -r /tmp/requirements.txt \ + && pip uninstall -y opencv-python\ + && pip uninstall -y opencv-python-headless\ + && pip install opencv-python-headless==4.7.0.72\ + && rm /tmp/requirements.txt \ + && rm -r ~/.cache/pip + +CMD python server.py +#CMD /bin/bash \ No newline at end of file diff --git a/deploy/docker/Dockerfile.cn b/deploy/docker/Dockerfile.cn new file mode 100644 index 000000000..b9d605b28 --- /dev/null +++ b/deploy/docker/Dockerfile.cn @@ -0,0 +1,32 @@ +# docker build -t qwerty/oas:latest . +# docker run -v ${PWD}:/app/OnmyojiAutoScript -p 22288:22288 --name oas -it --rm qwerty/oas + + +FROM python:3.10-slim-bullseye + +WORKDIR /app/OnmyojiAutoScript + +COPY requirements.txt /tmp/requirements.txt + +# python:3.10-slim is based on debian:11, apt source from https://developer.aliyun.com/mirror/debian +RUN echo "\ +deb https://mirrors.aliyun.com/debian/ bullseye main non-free contrib\n\ +deb-src https://mirrors.aliyun.com/debian/ bullseye main non-free contrib\n\ +deb https://mirrors.aliyun.com/debian-security/ bullseye-security main\n\ +deb-src https://mirrors.aliyun.com/debian-security/ bullseye-security main\n\ +deb https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib\n\ +deb-src https://mirrors.aliyun.com/debian/ bullseye-updates main non-free contrib\n\ +# deb https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib\n\ +# deb-src https://mirrors.aliyun.com/debian/ bullseye-backports main non-free contrib" \ +> /etc/apt/sources.list \ + && apt update \ + && apt install -y git adb libgomp1 openssh-client \ + && git config --global --add safe.directory '*' \ + && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo 'Asia/Shanghai' > /etc/timezone \ + && pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple \ + && pip install -r /tmp/requirements.txt \ + && rm /tmp/requirements.txt \ + && rm -r ~/.cache/pip + + CMD python --version \ No newline at end of file diff --git a/deploy/docker/requirements.txt b/deploy/docker/requirements.txt new file mode 100644 index 000000000..81a07f1ca --- /dev/null +++ b/deploy/docker/requirements.txt @@ -0,0 +1,172 @@ +# + +# This file is autogenerated by pip-compile with Python 3.10 + +# by the following command: + +# pip-compile --annotation-style=line --output-file=requirements.txt requirements-in.txt +adbutils==0.11.0 +# via -r requirements-in.txt, uiautomator2 +annotated-types==0.7.0 +# via pydantic +anyio==3.7.1 +# via fastapi, starlette +anytree==2.8.0 +# via -r requirements-in.txt +apkutils2==1.0.0 +# via adbutils +cached-property==1.5.2 +# via uiautomator2 +certifi==2023.11.17 +# via requests +cffi==1.16.0 +# via cryptography, gevent +charset-normalizer==3.3.2 +# via requests +cigam==0.0.3 +# via apkutils2 +click==8.1.7 +# via uvicorn +cn2an==0.5.23 +# via -r requirements-in.txt +colorama==0.4.6 +# via click, logzero, tqdm +coloredlogs==15.0.1 +# via onnxruntime +cryptography==42.0.8 +# via -r requirements-in.txt +decorator==5.1.1 +# via retry +deprecated==1.2.14 +# via uiautomator2 +deprecation==2.1.0 +# via adbutils +exceptiongroup==1.2.0 +# via anyio +fastapi==0.104.1 +# via -r requirements-in.txt +filelock==3.13.1 +# via uiautomator2 +flatbuffers==23.5.26 +# via onnxruntime +future==0.18.3 +# via zerorpc +gevent==23.9.1 +# via zerorpc +greenlet==3.0.3 +# via gevent +h11==0.14.0 +# via uvicorn +humanfriendly==10.0 +# via coloredlogs +idna==3.6 +# via anyio, requests +inflection==0.5.1 +# via -r requirements-in.txt +logzero==1.7.0 +# via uiautomator2 +lxml==5.0.0 +# via uiautomator2 +markdown-it-py==2.2.0 +# via rich +mdurl==0.1.2 +# via markdown-it-py +mpmath==1.3.0 +# via sympy +msgpack==1.0.7 +# via zerorpc +numpy==1.24.3 +# via -r requirements-in.txt, onnxruntime, opencv-python, ppocr-onnx, shapely +oashya==0.0.7 +# via -r requirements-in.txt +onepush==1.3.0 +# via -r requirements-in.txt +onnxruntime==1.16.3 +# via ppocr-onnx +opencv-python-headless==4.7.0.72 +packaging==20.9 +# via deprecation, onnxruntime, uiautomator2 +paho-mqtt==1.6.1 +# via -r requirements-in.txt +pillow==10.2.0 +# via ppocr-onnx, uiautomator2 +ppocr-onnx==0.0.3.9 +# via -r requirements-in.txt +proces==0.1.7 +# via cn2an +progress==1.6 +# via uiautomator2 +protobuf==4.25.1 +# via onnxruntime +psutil==6.1.1 +# via -r requirements-in.txt +py==1.11.0 +# via retry +pyclipper==1.3.0.post5 +# via ppocr-onnx +pycparser==2.21 +# via cffi +pycryptodome==3.21.0 +# via onepush +pydantic==2.10.0 +# via -r requirements-in.txt, fastapi +pydantic-core==2.27.0 +# via pydantic +pyelftools==0.30 +# via apkutils2 +pygments==2.17.2 +# via rich +pyparsing==3.1.1 +# via packaging +pyreadline3==3.4.1 +# via humanfriendly +pyyaml==6.0 +# via -r requirements-in.txt +pyzmq==25.1.2 +# via zerorpc +requests==2.31.0 +# via adbutils, onepush, ppocr-onnx, uiautomator2 +retry==0.9.2 +# via adbutils, uiautomator2 +rich==13.3.5 +# via -r requirements-in.txt +shapely==2.0.2 +# via ppocr-onnx +six==1.16.0 +# via adbutils, anytree, uiautomator2 +sniffio==1.3.0 +# via anyio +starlette==0.27.0 +# via fastapi +sympy==1.12 +# via onnxruntime +tqdm==4.65.0 +# via -r requirements-in.txt +typing-extensions==4.12.2 +# via fastapi, pydantic, pydantic-core, uvicorn +uiautomator2==2.16.17 +# via -r requirements-in.txt +uiautomator2cache==0.3.0.1 +# via -r requirements-in.txt +urllib3==2.1.0 +# via requests +uvicorn==0.23.2 +# via -r requirements-in.txt +websockets==11.0.3 +# via -r requirements-in.txt +whichcraft==0.6.1 +# via adbutils, uiautomator2 +wrapt==1.15.0 +# via -r requirements-in.txt, deprecated +xmltodict==0.13.0 +# via apkutils2 +zerorpc==0.6.3 +# via -r requirements-in.txt +zope-event==5.0 +# via gevent +zope-interface==6.1 +# via gevent + +# The following packages are considered to be unsafe in a requirements file: + +# setuptools \ No newline at end of file diff --git a/deploy/docker/requirements_generator.py b/deploy/docker/requirements_generator.py new file mode 100644 index 000000000..eb1037f30 --- /dev/null +++ b/deploy/docker/requirements_generator.py @@ -0,0 +1,62 @@ +import os + +from deploy.logger import logger + +BASE_FOLDER = os.path.dirname(os.path.abspath(__file__)) +logger.info(BASE_FOLDER) + + +def read_file(file): + out = {} + with open(file, 'r', encoding='utf-8') as f: + for line in f.readlines(): + if not line.strip(): + continue + res = [s.strip() for s in line.split('==')] + if len(res) > 1: + name, version = res + else: + name, version = res[0], None + out[name] = version + + return out + + +def write_file(file, data): + lines = [] + for name, version in data.items(): + if version: + lines.append(f'{name}=={version}') + else: + lines.append(str(name)) + + with open(file, 'w', encoding='utf-8', newline='') as f: + text = '\n'.join(lines) + text = text.replace('#', '\n#').strip() + f.write(text) + + +def docker_requirements_generate(requirements_in='requirements.txt'): + requirements = read_file(requirements_in) + + logger.info(f'Generate requirements for Docker image') + lock = {} + new = {} + logger.info(requirements) + for name, version in requirements.items(): + # alas-webapp is for windows only + if name == 'alas-webapp' or name == 'pywin32': + continue + if name == 'opencv-python': + name = 'opencv-python-headless' + version = '4.7.0.72' + if name in lock: + version = lock[name] if not isinstance(lock[name], dict) else lock[name]['version'] + name = name if not isinstance(lock[name], dict) else lock[name]['name'] + new[name] = version + + write_file(os.path.join(BASE_FOLDER, f'./requirements.txt'), data=new) + + +if __name__ == '__main__': + docker_requirements_generate() diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..d3cd8d275 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,13 @@ + +services: + OAS: + network_mode: host + volumes: + - '.:/app/OnmyojiAutoScript:rw' + - '/etc/localtime:/etc/localtime:ro' + container_name: 'oas-env' + image: 'oas-env' + build: + context: ./deploy/docker/ + dockerfile: ./Dockerfile + # dockerfile: ./Dockerfile \ No newline at end of file diff --git a/module/config/config_model.py b/module/config/config_model.py index 5c36c420c..d983cac7d 100644 --- a/module/config/config_model.py +++ b/module/config/config_model.py @@ -409,6 +409,35 @@ def script_set_arg(self, task: str, group: str, argument: str, value) -> bool: logger.error(e) return False + def copy_script_task(self, task_name: str, source_task: BaseModel) -> bool: + model_task_name = convert_to_underscore(task_name) + try: + setattr(self, model_task_name, source_task) + self.save() + logger.info(f'Copy task {model_task_name} success') + return True + except ValidationError as e: + logger.error(e) + return False + + def copy_task_group(self, task_name: str, group_name: str, source_task: BaseModel) -> bool: + model_task_name = convert_to_underscore(task_name) + model_group_name = convert_to_underscore(group_name) + task_object = getattr(self, model_task_name, None) + if not task_object: + return False + source_group_obj = getattr(source_task, model_group_name, None) + if not source_group_obj: + return False + try: + setattr(task_object, model_group_name, source_group_obj) + self.save() + logger.info(f'Copy task group {model_task_name}.{model_group_name} success') + return True + except ValidationError as e: + logger.error(e) + return False + def replace_next_run(self, d, dt: datetime): for k, v in d.items(): if isinstance(v, dict): diff --git a/module/device/control.py b/module/device/control.py index 122d7b531..20681f922 100644 --- a/module/device/control.py +++ b/module/device/control.py @@ -7,7 +7,7 @@ from module.device.method.minitouch import Minitouch from module.device.method.adb import Adb from module.device.method.scrcpy import Scrcpy -from module.device.method.window import Window +from module.device.method.windows import Window from module.logger import logger diff --git a/module/device/device.py b/module/device/device.py index f89f9394d..0ba0b4cde 100644 --- a/module/device/device.py +++ b/module/device/device.py @@ -22,7 +22,6 @@ from module.logger import logger - class Device(Platform, Screenshot, Control, AppControl): _screen_size_checked = False detect_record = set() diff --git a/module/device/method/windows.py b/module/device/method/windows.py new file mode 100644 index 000000000..bc9f3a441 --- /dev/null +++ b/module/device/method/windows.py @@ -0,0 +1,19 @@ + + +from module.device.env import IS_WINDOWS + + +if IS_WINDOWS: + from module.device.method.windows_impl import Window + print("dd") + +else: + class Window: + pass + + + + + + + diff --git a/module/device/method/window.py b/module/device/method/windows_impl.py similarity index 99% rename from module/device/method/window.py rename to module/device/method/windows_impl.py index 995808a54..ee7665cb1 100644 --- a/module/device/method/window.py +++ b/module/device/method/windows_impl.py @@ -21,6 +21,7 @@ from win32api import GetSystemMetrics, SendMessage, MAKELONG, PostMessage from win32con import SRCCOPY + from module.base.cBezier import BezierTrajectory from module.exception import RequestHumanTakeover, ScriptError from module.base.decorator import Config @@ -29,6 +30,8 @@ from module.device.handle import Handle, window_scale_rate, EmulatorFamily + + class Window(Handle): def __init__(self, *args, **kwargs): @@ -357,6 +360,7 @@ def scroll_window_message(self, x: int, y: int, delta: int=-120) -> None: + if __name__ == "__main__": w = Window(config='oas1') # img = w.screenshot_window_background() diff --git a/module/device/screenshot.py b/module/device/screenshot.py index ed56d9fbe..412167d27 100644 --- a/module/device/screenshot.py +++ b/module/device/screenshot.py @@ -12,7 +12,7 @@ from module.base.timer import Timer from module.base.utils import get_color, image_size, limit_in, save_image from module.device.method.adb import Adb -from module.device.method.window import Window +from module.device.method.windows import Window from module.device.method.droidcast import DroidCast from module.device.method.scrcpy import Scrcpy from module.device.method.nemu_ipc import NemuIpc @@ -272,4 +272,5 @@ def check_screen_black(self): if __name__ == "__main__": s = Screenshot(config="oas1") s.screenshot() + s.image_show() diff --git a/module/server/script_router.py b/module/server/script_router.py index 741db59ae..8b3ecaf58 100644 --- a/module/server/script_router.py +++ b/module/server/script_router.py @@ -7,6 +7,7 @@ from fastapi import WebSocket, WebSocketDisconnect from datetime import datetime from module.config.config import Config +from module.config.utils import convert_to_underscore from module.logger import logger from module.server.main_manager import MainManager @@ -81,6 +82,26 @@ async def config_delete(name: str = ''): return True +@script_app.put('/config/task/copy') +async def task_copy(task_name: str, dest_config_name: str, source_config_name: str): + if dest_config_name not in mm.script_process or source_config_name not in mm.script_process: + return False + source_task = getattr(mm.config_cache(source_config_name).model, convert_to_underscore(task_name), None) + if source_task is None: + return False + return mm.config_cache(dest_config_name).model.copy_script_task(task_name, source_task) + + +@script_app.put('/config/task/group/copy') +async def task_group_copy(task_name: str, group_name: str, dest_config_name: str, source_config_name: str): + if dest_config_name not in mm.script_process or source_config_name not in mm.script_process: + return False + source_task = getattr(mm.config_cache(source_config_name).model, convert_to_underscore(task_name), None) + if source_task is None: + return False + return mm.config_cache(dest_config_name).model.copy_task_group(task_name, group_name, source_task) + + # --------------------------------- 脚本实例管理 ---------------------------------- @script_app.get('/{script_name}/start') async def script_start(script_name: str): diff --git a/module/server/updater.py b/module/server/updater.py index d25d714ad..512bad22e 100644 --- a/module/server/updater.py +++ b/module/server/updater.py @@ -5,7 +5,6 @@ import requests from typing import Generator, List, Tuple - from deploy.config import ExecutionError from deploy.git import GitManager from deploy.pip import PipManager @@ -64,11 +63,8 @@ def get_commit(self, revision="", n=1, short_sha1=False) -> Tuple: return logs def current_branch(self) -> str: - log : str = subprocess.run( - 'git branch --show-current', capture_output=True, text=True, encoding="utf8", shell=True - ).stdout - log = log.replace('\n', '') - return log + branch = self.execute_output(f'{self.git} branch --show-current') + return branch.strip() def current_commit(self) -> str: return self.get_commit() diff --git a/script.py b/script.py index bc55529fd..9f0fb99b0 100644 --- a/script.py +++ b/script.py @@ -29,12 +29,13 @@ from module.config.config import Config from module.config.config_model import ConfigModel from module.device.device import Device +from module.device.env import IS_WINDOWS from module.base.utils import load_module from module.base.decorator import del_cached_property from module.logger import logger from module.exception import * from module.server.i18n import I18n -from module.device.platform2.platform_windows import minimize_by_name,show_window_by_name + _log_switch_lock = threading.Lock()#线程锁 @@ -442,7 +443,8 @@ def loop(self): self.config.model.running_task = '' # Update GUI 防呆, 读取设置并立刻显示后台模拟器到前台 - if not self.config.script.device.run_background_only: + if not self.config.script.device.run_background_only and IS_WINDOWS: + from module.device.platform2.platform_windows import minimize_by_name, show_window_by_name target_window_name = self.config.script.device.handle # 在这里输入你的具体窗口名称 if self.config.script.device.emulator_window_minimize: minimize_by_name(target_window_name) @@ -539,5 +541,5 @@ def start_loop(self) -> None: if __name__ == "__main__": - script = Script("oas2") + script = Script("oas1") script.loop() diff --git a/tasks/AbyssShadows/config.py b/tasks/AbyssShadows/config.py index f11796104..d7660eb26 100644 --- a/tasks/AbyssShadows/config.py +++ b/tasks/AbyssShadows/config.py @@ -5,8 +5,8 @@ # github https://github.com/roarhill/oas from pydantic import BaseModel, Field -from pygments.lexer import default -from scripts.regsetup import description +# from pygments.lexer import default +# from scripts.regsetup import description from sympy.testing.pytest import Failed from tasks.Component.GeneralBattle.config_general_battle import GeneralBattleConfig diff --git a/tasks/BondlingFairyland/config_battle.py b/tasks/BondlingFairyland/config_battle.py index 267668862..5f09d8e31 100644 --- a/tasks/BondlingFairyland/config_battle.py +++ b/tasks/BondlingFairyland/config_battle.py @@ -3,12 +3,9 @@ # github https://github.com/runhey from pydantic import BaseModel, Field -from tasks.Component.GeneralBattle.config_general_battle import GreenMarkType +from tasks.Component.GeneralBattle.config_general_battle import GreenMarkType, GeneralBattleConfig +from tasks.Component.config_base import dynamic_hide -class BattleConfig(BaseModel): - # 是否开启绿标 - green_enable: bool = Field(default=False, description='green_enable_help') - # 选哪一个绿标 - green_mark: GreenMarkType = Field(default=GreenMarkType.GREEN_LEFT1, description='green_mark_help') - # 是否启动战斗时随机点击或者随机滑动 - random_click_swipt_enable: bool = Field(default=False, description='random_click_swipt_enable_help') + +class BattleConfig(GeneralBattleConfig): + hide_fields = dynamic_hide('lock_team_enable', 'preset_enable', 'preset_group', 'preset_team') diff --git a/tasks/Component/GeneralRoom/general_room.py b/tasks/Component/GeneralRoom/general_room.py index 068fead95..110ee6605 100644 --- a/tasks/Component/GeneralRoom/general_room.py +++ b/tasks/Component/GeneralRoom/general_room.py @@ -140,6 +140,8 @@ def check_zones(self, name: str) -> bool: break if name == '金币妖怪' and "金币" in text_ocr: break + if name == '经验妖怪' and '经验' in text_ocr: + break if click_timer.reached(): click_timer.reset() self.device.click(x=pos[0] + randint(-5, 5), y=pos[1] + randint(-5, 5)) diff --git a/tasks/Component/ReplaceShikigami/assets.py b/tasks/Component/ReplaceShikigami/assets.py index 57c253660..0eda2c4b6 100644 --- a/tasks/Component/ReplaceShikigami/assets.py +++ b/tasks/Component/ReplaceShikigami/assets.py @@ -52,17 +52,17 @@ class ReplaceShikigamiAssets: # description I_RS_NO_ADD = RuleImage(roi_front=(276,222,100,212), roi_back=(28,181,1232,293), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_no_add.png") # 素材 - I_RS_MATERIAL = RuleImage(roi_front=(32,283,59,56), roi_back=(32,283,59,56), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_material.png") + I_RS_MATERIAL = RuleImage(roi_front=(822,620,59,56), roi_back=(129,597,774,98), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_material.png") # description - I_RS_N = RuleImage(roi_front=(138,299,57,59), roi_back=(138,299,57,59), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_n.png") + I_RS_N = RuleImage(roi_front=(709,621,57,59), roi_back=(694,606,89,90), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_n.png") # description - I_RS_R = RuleImage(roi_front=(230,344,64,61), roi_back=(230,344,64,61), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_r.png") + I_RS_R = RuleImage(roi_front=(594,619,64,61), roi_back=(582,601,91,98), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_r.png") # description - I_RS_SR = RuleImage(roi_front=(307,421,62,58), roi_back=(307,421,62,58), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_sr.png") + I_RS_SR = RuleImage(roi_front=(483,619,62,58), roi_back=(470,603,90,96), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_sr.png") # description - I_RS_SSR = RuleImage(roi_front=(354,517,63,58), roi_back=(354,517,63,58), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_ssr.png") + I_RS_SSR = RuleImage(roi_front=(370,621,63,58), roi_back=(353,600,98,100), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_ssr.png") # description - I_RS_SP = RuleImage(roi_front=(372,621,58,60), roi_back=(372,621,58,60), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_sp.png") + I_RS_SP = RuleImage(roi_front=(260,621,58,60), roi_back=(246,605,92,90), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_sp.png") # description I_RS_MATERIAL_SELECTED = RuleImage(roi_front=(27,620,68,65), roi_back=(27,620,68,65), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_material_selected.png") # description @@ -81,6 +81,10 @@ class ReplaceShikigamiAssets: I_RS_LEVEL_MAX = RuleImage(roi_front=(487,248,23,21), roi_back=(52,238,1118,37), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_level_max.png") # 智能放入 I_RS_SMART_EXCHANGE = RuleImage(roi_front=(1150,507,40,44), roi_back=(1128,488,86,162), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_smart_exchange.png") + # description + I_RS_UR = RuleImage(roi_front=(149,623,56,58), roi_back=(136,603,88,95), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_ur.png") + # description + I_RS_UR_SELECTED = RuleImage(roi_front=(36,620,54,58), roi_back=(14,601,100,100), threshold=0.8, method="Template matching", file="./tasks/Component/ReplaceShikigami/rs/rs_rs_ur_selected.png") # Image Rule Assets diff --git a/tasks/Component/ReplaceShikigami/replace_shikigami.py b/tasks/Component/ReplaceShikigami/replace_shikigami.py index 7943a7a74..8c55a3ea7 100644 --- a/tasks/Component/ReplaceShikigami/replace_shikigami.py +++ b/tasks/Component/ReplaceShikigami/replace_shikigami.py @@ -3,6 +3,7 @@ # github https://github.com/runhey from module.atom.ocr import RuleOcr from module.atom.image import RuleImage +from module.base.timer import Timer from module.logger import logger from tasks.base_task import BaseTask @@ -33,13 +34,15 @@ def switch_shikigami_class(self, shikigami_class: ShikigamiClass = ShikigamiClas ShikigamiClass.R: self.I_RS_R_SELECTED, ShikigamiClass.SR: self.I_RS_SR_SELECTED, ShikigamiClass.SSR: self.I_RS_SSR_SELECTED, - ShikigamiClass.SP: self.I_RS_SP_SELECTED} + ShikigamiClass.SP: self.I_RS_SP_SELECTED, + ShikigamiClass.UR: self.I_RS_UR_SELECTED} match_click = {ShikigamiClass.MATERIAL: self.I_RS_MATERIAL, ShikigamiClass.N: self.I_RS_N, ShikigamiClass.R: self.I_RS_R, ShikigamiClass.SR: self.I_RS_SR, ShikigamiClass.SSR: self.I_RS_SSR, - ShikigamiClass.SP: self.I_RS_SP} + ShikigamiClass.SP: self.I_RS_SP, + ShikigamiClass.UR: self.I_RS_UR} check_selected = match_selected[shikigami_class] check_click = match_click[shikigami_class] # 选择式神的种类 @@ -87,11 +90,16 @@ def set_shikigami(self, shikigami_order: int = 7, stop_image: RuleImage = None): click_match = _click_match[shikigami_order] TIMEOUT_SEC = 120 # 超时时长(秒) start_time = time.time() # 记录起始时间 + click_interval_timer = Timer(1.5).start() # 点击选择式神间隔 + clicked = False while 1: # ——1. 先做超时检查—— if time.time() - start_time > TIMEOUT_SEC: logger.error('寄养等待超过 2 分钟,自动退出') raise GameStuckError('寄养超时(>120 s)') + # 恢复点击操作 + if click_interval_timer.reached_and_reset(): + clicked = False self.screenshot() @@ -99,13 +107,17 @@ def set_shikigami(self, shikigami_order: int = 7, stop_image: RuleImage = None): break if self.appear_then_click(self.I_U_CONFIRM_SMALL, interval=0.5): + clicked = False # 点击了确认, 恢复选式神的操作 continue - if self.click(click_match, interval=1.5): + # 与下方点击第7个式神操作互斥, 防止确认按钮还没有出现被下方取消掉 + if not clicked and self.click(click_match, interval=1.5): + clicked = True continue - if self.click(_click_match[6], interval=4.5): + if not clicked and self.click(_click_match[6], interval=4.5): # 有的时候第七个格子被占用到寄养上去了 # 导致一直无法选上 + clicked = True continue if self.appear_then_click(self.I_U_CIRCLE_ALTERNATE, interval=2.5): self.appear_then_click(self.I_U_CONFIRM_ALTERNATE, interval=1.5) @@ -115,10 +127,10 @@ def set_shikigami(self, shikigami_order: int = 7, stop_image: RuleImage = None): def detect_no_shikigami(self) -> bool: self.screenshot() if self.appear(self.I_DETECT_EMPTY_1)\ - and self.appear(self.I_DETECT_EMPTY_2) \ - and self.appear(self.I_DETECT_EMPTY_3) \ - and self.appear(self.I_DETECT_EMPTY_4) \ - and self.appear(self.I_DETECT_EMPTY_5) \ - and self.appear(self.I_DETECT_EMPTY_6): + or self.appear(self.I_DETECT_EMPTY_2) \ + or self.appear(self.I_DETECT_EMPTY_3) \ + or self.appear(self.I_DETECT_EMPTY_4) \ + or self.appear(self.I_DETECT_EMPTY_5) \ + or self.appear(self.I_DETECT_EMPTY_6): return True return False diff --git a/tasks/Component/ReplaceShikigami/rs/image.json b/tasks/Component/ReplaceShikigami/rs/image.json index 79b67bb37..7595a6d59 100644 --- a/tasks/Component/ReplaceShikigami/rs/image.json +++ b/tasks/Component/ReplaceShikigami/rs/image.json @@ -11,8 +11,8 @@ { "itemName": "rs_material", "imageName": "rs_rs_material.png", - "roiFront": "32,283,59,56", - "roiBack": "32,283,59,56", + "roiFront": "822,620,59,56", + "roiBack": "129,597,774,98", "method": "Template matching", "threshold": 0.8, "description": "素材" @@ -20,8 +20,8 @@ { "itemName": "rs_n", "imageName": "rs_rs_n.png", - "roiFront": "138,299,57,59", - "roiBack": "138,299,57,59", + "roiFront": "709,621,57,59", + "roiBack": "694,606,89,90", "method": "Template matching", "threshold": 0.8, "description": "description" @@ -29,8 +29,8 @@ { "itemName": "rs_r", "imageName": "rs_rs_r.png", - "roiFront": "230,344,64,61", - "roiBack": "230,344,64,61", + "roiFront": "594,619,64,61", + "roiBack": "582,601,91,98", "method": "Template matching", "threshold": 0.8, "description": "description" @@ -38,8 +38,8 @@ { "itemName": "rs_sr", "imageName": "rs_rs_sr.png", - "roiFront": "307,421,62,58", - "roiBack": "307,421,62,58", + "roiFront": "483,619,62,58", + "roiBack": "470,603,90,96", "method": "Template matching", "threshold": 0.8, "description": "description" @@ -47,8 +47,8 @@ { "itemName": "rs_ssr", "imageName": "rs_rs_ssr.png", - "roiFront": "354,517,63,58", - "roiBack": "354,517,63,58", + "roiFront": "370,621,63,58", + "roiBack": "353,600,98,100", "method": "Template matching", "threshold": 0.8, "description": "description" @@ -56,8 +56,8 @@ { "itemName": "rs_sp", "imageName": "rs_rs_sp.png", - "roiFront": "372,621,58,60", - "roiBack": "372,621,58,60", + "roiFront": "260,621,58,60", + "roiBack": "246,605,92,90", "method": "Template matching", "threshold": 0.8, "description": "description" @@ -142,5 +142,23 @@ "method": "Template matching", "threshold": 0.8, "description": "智能放入" + }, + { + "itemName": "rs_ur", + "imageName": "rs_rs_ur.png", + "roiFront": "149,623,56,58", + "roiBack": "136,603,88,95", + "method": "Template matching", + "threshold": 0.8, + "description": "description" + }, + { + "itemName": "rs_ur_selected", + "imageName": "rs_rs_ur_selected.png", + "roiFront": "36,620,54,58", + "roiBack": "14,601,100,100", + "method": "Template matching", + "threshold": 0.8, + "description": "description" } ] \ No newline at end of file diff --git a/tasks/Component/ReplaceShikigami/rs/rs_rs_ur.png b/tasks/Component/ReplaceShikigami/rs/rs_rs_ur.png new file mode 100644 index 000000000..12dd81598 Binary files /dev/null and b/tasks/Component/ReplaceShikigami/rs/rs_rs_ur.png differ diff --git a/tasks/Component/ReplaceShikigami/rs/rs_rs_ur_selected.png b/tasks/Component/ReplaceShikigami/rs/rs_rs_ur_selected.png new file mode 100644 index 000000000..de966970a Binary files /dev/null and b/tasks/Component/ReplaceShikigami/rs/rs_rs_ur_selected.png differ diff --git a/tasks/DailyTrifles/assets.py b/tasks/DailyTrifles/assets.py index 4e853b582..09ab4af48 100644 --- a/tasks/DailyTrifles/assets.py +++ b/tasks/DailyTrifles/assets.py @@ -35,7 +35,7 @@ class DailyTriflesAssets: # description I_GIFT_RECOMMEND = RuleImage(roi_front=(1183,454,53,64), roi_back=(1162,77,98,457), threshold=0.7, method="Template matching", file="./tasks/DailyTrifles/store/store_gift_recommend.png") # 免费一抽领黑蛋 - I_GIFT_SIGN = RuleImage(roi_front=(629,192,129,149), roi_back=(130,129,891,473), threshold=0.8, method="Template matching", file="./tasks/DailyTrifles/store/store_gift_sign.png") + I_GIFT_SIGN = RuleImage(roi_front=(186,191,115,83), roi_back=(130,129,891,473), threshold=0.8, method="Template matching", file="./tasks/DailyTrifles/store/store_gift_sign.png") # 体力 I_SPECIAL_SUSHI = RuleImage(roi_front=(180,130,800,460), roi_back=(180,130,800,460), threshold=0.8, method="Template matching", file="./tasks/DailyTrifles/store/store_sushi.png") # 购买时货币类型为勾玉 diff --git a/tasks/DailyTrifles/store/image.json b/tasks/DailyTrifles/store/image.json index 8deba4ed1..e549f471e 100644 --- a/tasks/DailyTrifles/store/image.json +++ b/tasks/DailyTrifles/store/image.json @@ -20,7 +20,7 @@ { "itemName": "gift_sign", "imageName": "store_gift_sign.png", - "roiFront": "629,192,129,149", + "roiFront": "186,191,115,83", "roiBack": "130,129,891,473", "method": "Template matching", "threshold": 0.8, diff --git a/tasks/DailyTrifles/store/store_gift_sign.png b/tasks/DailyTrifles/store/store_gift_sign.png index 6dba1c456..72bbd82aa 100644 Binary files a/tasks/DailyTrifles/store/store_gift_sign.png and b/tasks/DailyTrifles/store/store_gift_sign.png differ diff --git a/tasks/GameUi/page.py b/tasks/GameUi/page.py index bf5a1d4e4..10e66482e 100644 --- a/tasks/GameUi/page.py +++ b/tasks/GameUi/page.py @@ -4,6 +4,7 @@ from module.atom.click import RuleClick from tasks.GameUi.assets import GameUiAssets as G +from tasks.Restart.assets import RestartAssets from tasks.base_task import BaseTask as BT from tasks.RyouToppa.assets import RyouToppaAssets @@ -35,7 +36,8 @@ def link(self, button, destination): page_login = Page(G.I_CHECK_LOGIN_FORM) # Main Home 主页 page_main = Page(G.I_CHECK_MAIN) -page_main.additional = [G.I_AD_CLOSE_RED, G.I_BACK_FRIENDS] +page_main.additional = [G.I_AD_CLOSE_RED, G.I_BACK_FRIENDS, RestartAssets.I_CANCEL_BATTLE, + RestartAssets.I_LOGIN_SCROOLL_CLOSE] # 召唤summon page_summon = Page(G.I_CHECK_SUMMON) page_summon.link(button=G.I_SUMMON_GOTO_MAIN, destination=page_main) @@ -249,7 +251,7 @@ def random_click(low: int = None, high: int = None) -> RuleClick | list[RuleClic :return: RuleClick或者RuleClick的数组 """ click = random.choice([asa.C_RANDOM_LEFT, asa.C_RANDOM_RIGHT, asa.C_RANDOM_TOP]) - click.name = "BATTLE_RANDOM" + click.name = "SAFE_RANDOM_CLICK" if low is None or high is None: return click return [click for _ in range(random.randint(low, high))] diff --git a/tasks/Hyakkiyakou/config.py b/tasks/Hyakkiyakou/config.py index c3e75a7c4..372907a0a 100644 --- a/tasks/Hyakkiyakou/config.py +++ b/tasks/Hyakkiyakou/config.py @@ -2,7 +2,7 @@ from enum import Enum from tasks.Component.config_scheduler import Scheduler -from tasks.Component.config_base import ConfigBase, Time +from tasks.Component.config_base import ConfigBase, Time, dynamic_hide class ModelPrecision(str, Enum): @@ -67,6 +67,9 @@ class DebugConfig(ConfigBase): hya_control_method: ControlMethod = Field(default=ControlMethod.WINDOW_MESSAGE, description='hya_control_method') + hide_fields = dynamic_hide('continuous_learning') + + @field_validator('continuous_learning', mode='after') @classmethod def false_continuous_learning(cls, v): diff --git a/tasks/Hyakkiyakou/hya/hya_check_invitation.png b/tasks/Hyakkiyakou/hya/hya_check_invitation.png new file mode 100644 index 000000000..f95027f48 Binary files /dev/null and b/tasks/Hyakkiyakou/hya/hya_check_invitation.png differ diff --git a/tasks/KekkaiActivation/a/image.json b/tasks/KekkaiActivation/a/image.json index 6137f224d..1992ffc1a 100644 --- a/tasks/KekkaiActivation/a/image.json +++ b/tasks/KekkaiActivation/a/image.json @@ -3,7 +3,7 @@ "itemName": "a_harvest_fish4", "imageName": "a_a_harvest_fish4.png", "roiFront": "897,159,48,40", - "roiBack": "872,128,100,100", + "roiBack": "872,128,140,181", "method": "Template matching", "threshold": 0.8, "description": "斗鱼收获奖励4星" @@ -12,7 +12,7 @@ "itemName": "a_harvest_exp", "imageName": "a_a_harvest_exp.png", "roiFront": "891,153,49,43", - "roiBack": "865,121,100,100", + "roiBack": "865,121,152,183", "method": "Template matching", "threshold": 0.8, "description": "一般的收获奖励" @@ -156,7 +156,7 @@ "itemName": "a_harvest_kaiko_4", "imageName": "a_a_harvest_kaiko_4.png", "roiFront": "894,164,48,41", - "roiBack": "867,132,100,100", + "roiBack": "867,132,148,187", "method": "Template matching", "threshold": 0.8, "description": "太鼓4" @@ -165,7 +165,7 @@ "itemName": "a_harvest_kaiko_3", "imageName": "a_a_harvest_kaiko_3.png", "roiFront": "893,163,47,42", - "roiBack": "865,136,100,100", + "roiBack": "865,136,148,178", "method": "Template matching", "threshold": 0.8, "description": "description" @@ -174,7 +174,7 @@ "itemName": "a_harvest_kaiko_6", "imageName": "a_a_harvest_kaiko_6.png", "roiFront": "898,160,45,38", - "roiBack": "868,129,100,100", + "roiBack": "868,129,146,184", "method": "Template matching", "threshold": 0.7, "description": "太鼓6" @@ -183,7 +183,7 @@ "itemName": "a_harvest_fish_6", "imageName": "a_a_harvest_fish_6.png", "roiFront": "898,159,45,38", - "roiBack": "869,131,100,100", + "roiBack": "869,131,165,184", "method": "Template matching", "threshold": 0.7, "description": "斗鱼6" @@ -192,7 +192,7 @@ "itemName": "a_harvest_moon_3", "imageName": "a_a_harvest_moon_3.png", "roiFront": "897,159,46,40", - "roiBack": "869,127,100,100", + "roiBack": "869,127,155,184", "method": "Template matching", "threshold": 0.7, "description": "太阴3" @@ -210,7 +210,7 @@ "itemName": "a_harvest_fish_3", "imageName": "a_a_harvest_fish_3.png", "roiFront": "891,165,57,39", - "roiBack": "854,128,132,124", + "roiBack": "854,128,160,174", "method": "Template matching", "threshold": 0.8, "description": "斗鱼3" diff --git a/tasks/KekkaiActivation/assets.py b/tasks/KekkaiActivation/assets.py index 6187f4bae..cc9ac2cb3 100644 --- a/tasks/KekkaiActivation/assets.py +++ b/tasks/KekkaiActivation/assets.py @@ -31,9 +31,9 @@ class KekkaiActivationAssets: # Image Rule Assets # 斗鱼收获奖励4星 - I_A_HARVEST_FISH4 = RuleImage(roi_front=(897,159,48,40), roi_back=(872,128,100,100), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_fish4.png") + I_A_HARVEST_FISH4 = RuleImage(roi_front=(897,159,48,40), roi_back=(872,128,140,181), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_fish4.png") # 一般的收获奖励 - I_A_HARVEST_EXP = RuleImage(roi_front=(891,153,49,43), roi_back=(865,121,100,100), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_exp.png") + I_A_HARVEST_EXP = RuleImage(roi_front=(891,153,49,43), roi_back=(865,121,152,183), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_exp.png") # "结界卡" I_A_CARDS_REALM = RuleImage(roi_front=(0,0,100,100), roi_back=(0,0,100,100), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_cards_realm.png") # description @@ -65,19 +65,19 @@ class KekkaiActivationAssets: # description I_A_CHECK_CARD = RuleImage(roi_front=(513,32,260,49), roi_back=(513,32,260,49), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_check_card.png") # 太鼓4 - I_A_HARVEST_KAIKO_4 = RuleImage(roi_front=(894,164,48,41), roi_back=(867,132,100,100), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_kaiko_4.png") + I_A_HARVEST_KAIKO_4 = RuleImage(roi_front=(894,164,48,41), roi_back=(867,132,148,187), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_kaiko_4.png") # description - I_A_HARVEST_KAIKO_3 = RuleImage(roi_front=(893,163,47,42), roi_back=(865,136,100,100), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_kaiko_3.png") + I_A_HARVEST_KAIKO_3 = RuleImage(roi_front=(893,163,47,42), roi_back=(865,136,148,178), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_kaiko_3.png") # 太鼓6 - I_A_HARVEST_KAIKO_6 = RuleImage(roi_front=(898,160,45,38), roi_back=(868,129,100,100), threshold=0.7, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_kaiko_6.png") + I_A_HARVEST_KAIKO_6 = RuleImage(roi_front=(898,160,45,38), roi_back=(868,129,146,184), threshold=0.7, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_kaiko_6.png") # 斗鱼6 - I_A_HARVEST_FISH_6 = RuleImage(roi_front=(898,159,45,38), roi_back=(869,131,100,100), threshold=0.7, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_fish_6.png") + I_A_HARVEST_FISH_6 = RuleImage(roi_front=(898,159,45,38), roi_back=(869,131,165,184), threshold=0.7, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_fish_6.png") # 太阴3 - I_A_HARVEST_MOON_3 = RuleImage(roi_front=(897,159,46,40), roi_back=(869,127,100,100), threshold=0.7, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_moon_3.png") + I_A_HARVEST_MOON_3 = RuleImage(roi_front=(897,159,46,40), roi_back=(869,127,155,184), threshold=0.7, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_moon_3.png") # 卸下 I_A_DEMOUNT = RuleImage(roi_front=(939,575,55,47), roi_back=(903,551,107,91), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_demount.png") # 斗鱼3 - I_A_HARVEST_FISH_3 = RuleImage(roi_front=(891,165,57,39), roi_back=(854,128,132,124), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_fish_3.png") + I_A_HARVEST_FISH_3 = RuleImage(roi_front=(891,165,57,39), roi_back=(854,128,160,174), threshold=0.8, method="Template matching", file="./tasks/KekkaiActivation/a/a_a_harvest_fish_3.png") # Image Rule Assets diff --git a/tasks/KekkaiUtilize/assets.py b/tasks/KekkaiUtilize/assets.py index b19c93344..678423db7 100644 --- a/tasks/KekkaiUtilize/assets.py +++ b/tasks/KekkaiUtilize/assets.py @@ -59,6 +59,8 @@ class KekkaiUtilizeAssets: I_EXP_EXTRACT = RuleImage(roi_front=(592,448,100,73), roi_back=(592,448,100,73), threshold=0.8, method="Template matching", file="./tasks/KekkaiUtilize/realm/realm_exp_extract.png") # 盒子经验满 I_BOX_EXP_MAX = RuleImage(roi_front=(889,430,61,64), roi_back=(829,372,228,186), threshold=0.7, method="Template matching", file="./tasks/KekkaiUtilize/realm/realm_box_exp_max.png") + # 种树活动关闭标识 + I_PLANT_TREE_CLOSE = RuleImage(roi_front=(777,91,36,34), roi_back=(711,52,169,125), threshold=0.8, method="Template matching", file="./tasks/KekkaiUtilize/realm/realm_plant_tree_close.png") # Click Rule Assets diff --git a/tasks/KekkaiUtilize/config.py b/tasks/KekkaiUtilize/config.py index 319419314..32bb377c6 100644 --- a/tasks/KekkaiUtilize/config.py +++ b/tasks/KekkaiUtilize/config.py @@ -31,6 +31,7 @@ class UtilizeConfig(BaseModel): select_friend_list: SelectFriendList = Field(default=SelectFriendList.SAME_SERVER, description='select_friend_list_help') shikigami_class: ShikigamiClass = Field(default=ShikigamiClass.N, description='shikigami_class_help') shikigami_order: int = Field(default=4, description='shikigami_order_help') + harvest_guild_max_times: int = Field(default=3, description='收取寮资金或体力失败的最大尝试次数') utilize_enable: bool = Field(default=True, description='是否蹭卡,小号可以选择不蹭卡') guild_ap_enable: bool = Field(default=True, description='guild_ap_enable_help') guild_assets_enable: bool = Field(default=True, description='guild_assets_enable_help') diff --git a/tasks/KekkaiUtilize/realm/image.json b/tasks/KekkaiUtilize/realm/image.json index d322aaeac..3fe643f5c 100644 --- a/tasks/KekkaiUtilize/realm/image.json +++ b/tasks/KekkaiUtilize/realm/image.json @@ -97,5 +97,14 @@ "method": "Template matching", "threshold": 0.7, "description": "盒子经验满" + }, + { + "itemName": "plant_tree_close", + "imageName": "realm_plant_tree_close.png", + "roiFront": "777,91,36,34", + "roiBack": "711,52,169,125", + "method": "Template matching", + "threshold": 0.8, + "description": "种树活动关闭标识" } ] \ No newline at end of file diff --git a/tasks/KekkaiUtilize/realm/realm_plant_tree_close.png b/tasks/KekkaiUtilize/realm/realm_plant_tree_close.png new file mode 100644 index 000000000..665086b98 Binary files /dev/null and b/tasks/KekkaiUtilize/realm/realm_plant_tree_close.png differ diff --git a/tasks/KekkaiUtilize/script_task.py b/tasks/KekkaiUtilize/script_task.py index 3fe26831a..931804374 100644 --- a/tasks/KekkaiUtilize/script_task.py +++ b/tasks/KekkaiUtilize/script_task.py @@ -50,13 +50,13 @@ def run(self): self.check_box_ap_or_exp(con.box_ap_enable, con.box_exp_enable, con.box_exp_waste) # 收取寮资金和体力 - self.recive_guild_ap_or_assets() + self.recive_guild_ap_or_assets(con.harvest_guild_max_times) if not con.utilize_enable: self.set_next_run(task='KekkaiUtilize', finish=True, success=True) raise TaskEnd - def recive_guild_ap_or_assets(self): - for i in range(1, 5): + def recive_guild_ap_or_assets(self, max_tries: int = 3): + for i in range(1, max_tries+1): self.ui_get_current_page() self.ui_goto(page_guild) # 在寮的主界面 检查是否有收取体力或者是收取寮资金 @@ -198,7 +198,8 @@ def goto_realm(self): break if self.appear(self.I_SHI_DEFENSE): break - + if self.appear_then_click(self.I_PLANT_TREE_CLOSE): + continue if self.appear_then_click(self.I_GUILD_REALM, interval=1): continue @@ -718,6 +719,8 @@ def back_guild(self): break if self.appear(self.I_GUILD_REALM): break + if self.appear_then_click(self.I_PLANT_TREE_CLOSE): + continue if self.appear_then_click(self.I_UI_BACK_RED, interval=1): continue diff --git a/tasks/Restart/assets.py b/tasks/Restart/assets.py index b39629451..4eae017b9 100644 --- a/tasks/Restart/assets.py +++ b/tasks/Restart/assets.py @@ -22,7 +22,7 @@ class RestartAssets: # 邮件小图标 I_HARVEST_MAIL = RuleImage(roi_front=(337,505,37,25), roi_back=(38,465,880,89), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_harvest_mail.png") # 全部收取 - I_HARVEST_MAIL_ALL = RuleImage(roi_front=(80,622,75,64), roi_back=(80,622,75,64), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_harvest_mail_all.png") + I_HARVEST_MAIL_ALL = RuleImage(roi_front=(69,589,64,57), roi_back=(28,572,115,123), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_harvest_mail_all.png") # 有些邮件需要点击一次 I_HARVEST_MAIL_OPEN = RuleImage(roi_front=(163,367,45,48), roi_back=(139,86,100,487), threshold=0.9, method="Template matching", file="./tasks/Restart/harvest/harvest_harvest_mail_open.png") # 确认收取邮件 @@ -55,6 +55,16 @@ class RestartAssets: I_HARVEST_MAIL_COPY = RuleImage(roi_front=(257,509,29,21), roi_back=(192,472,790,100), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_harvest_mail_copy.png") # description I_HARVEST_MAIL_2 = RuleImage(roi_front=(156,125,65,60), roi_back=(120,94,290,536), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_harvest_mail_2.png") + # 系统邮件打开状态 + I_SYSTEM_MAIL_OPEN = RuleImage(roi_front=(1201,223,51,112), roi_back=(1197,219,59,118), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_system_mail_open.png") + # 特殊邮件关闭状态 + I_SPECIAL_MAIL_CLOSE = RuleImage(roi_front=(1200,379,53,108), roi_back=(1185,342,80,178), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_special_mail_close.png") + # 系统邮件关闭状态 + I_SYSTEM_MAIL_CLOSE = RuleImage(roi_front=(1200,222,53,112), roi_back=(1186,193,81,156), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_system_mail_close.png") + # 特殊邮件打开状态 + I_SPECIAL_MAIL_OPEN = RuleImage(roi_front=(1201,380,55,110), roi_back=(1190,348,79,162), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_special_mail_open.png") + # 一键已读所有邮件 + I_READ_ALL_MAIL = RuleImage(roi_front=(155,603,166,44), roi_back=(149,588,182,72), threshold=0.8, method="Template matching", file="./tasks/Restart/harvest/harvest_read_all_mail.png") # Click Rule Assets @@ -95,6 +105,8 @@ class RestartAssets: I_EARLY_SERVER = RuleImage(roi_front=(596,269,115,33), roi_back=(596,269,115,33), threshold=0.8, method="Template matching", file="./tasks/Restart/login/login_early_server.png") # 取消体验服切换弹窗 I_EARLY_SERVER_CANCEL = RuleImage(roi_front=(435,404,172,56), roi_back=(435,404,172,56), threshold=0.8, method="Template matching", file="./tasks/Restart/login/login_early_server_cancel.png") + # 取消继续战斗 + I_CANCEL_BATTLE = RuleImage(roi_front=(471,395,129,55), roi_back=(367,227,545,296), threshold=0.8, method="Template matching", file="./tasks/Restart/login/login_cancel_battle.png") # Ocr Rule Assets diff --git a/tasks/Restart/harvest/harvest_harvest_mail_all.png b/tasks/Restart/harvest/harvest_harvest_mail_all.png index 9abd1dc10..368ae9b51 100644 Binary files a/tasks/Restart/harvest/harvest_harvest_mail_all.png and b/tasks/Restart/harvest/harvest_harvest_mail_all.png differ diff --git a/tasks/Restart/harvest/harvest_read_all_mail.png b/tasks/Restart/harvest/harvest_read_all_mail.png new file mode 100644 index 000000000..1ff54fa4b Binary files /dev/null and b/tasks/Restart/harvest/harvest_read_all_mail.png differ diff --git a/tasks/Restart/harvest/harvest_special_mail_close.png b/tasks/Restart/harvest/harvest_special_mail_close.png new file mode 100644 index 000000000..881bd95cf Binary files /dev/null and b/tasks/Restart/harvest/harvest_special_mail_close.png differ diff --git a/tasks/Restart/harvest/harvest_special_mail_open.png b/tasks/Restart/harvest/harvest_special_mail_open.png new file mode 100644 index 000000000..1644a6b01 Binary files /dev/null and b/tasks/Restart/harvest/harvest_special_mail_open.png differ diff --git a/tasks/Restart/harvest/harvest_system_mail_close.png b/tasks/Restart/harvest/harvest_system_mail_close.png new file mode 100644 index 000000000..73b453cbe Binary files /dev/null and b/tasks/Restart/harvest/harvest_system_mail_close.png differ diff --git a/tasks/Restart/harvest/harvest_system_mail_open.png b/tasks/Restart/harvest/harvest_system_mail_open.png new file mode 100644 index 000000000..07c07b0f0 Binary files /dev/null and b/tasks/Restart/harvest/harvest_system_mail_open.png differ diff --git a/tasks/Restart/harvest/image.json b/tasks/Restart/harvest/image.json index 4fa8c8a0a..783878650 100644 --- a/tasks/Restart/harvest/image.json +++ b/tasks/Restart/harvest/image.json @@ -47,8 +47,8 @@ { "itemName": "harvest_mail_all", "imageName": "harvest_harvest_mail_all.png", - "roiFront": "80,622,75,64", - "roiBack": "80,622,75,64", + "roiFront": "69,589,64,57", + "roiBack": "28,572,115,123", "method": "Template matching", "threshold": 0.8, "description": "全部收取" @@ -196,5 +196,50 @@ "method": "Template matching", "threshold": 0.8, "description": "description" + }, + { + "itemName": "system_mail_open", + "imageName": "harvest_system_mail_open.png", + "roiFront": "1201,223,51,112", + "roiBack": "1197,219,59,118", + "method": "Template matching", + "threshold": 0.8, + "description": "系统邮件打开状态" + }, + { + "itemName": "special_mail_close", + "imageName": "harvest_special_mail_close.png", + "roiFront": "1200,379,53,108", + "roiBack": "1185,342,80,178", + "method": "Template matching", + "threshold": 0.8, + "description": "特殊邮件关闭状态" + }, + { + "itemName": "system_mail_close", + "imageName": "harvest_system_mail_close.png", + "roiFront": "1200,222,53,112", + "roiBack": "1186,193,81,156", + "method": "Template matching", + "threshold": 0.8, + "description": "系统邮件关闭状态" + }, + { + "itemName": "special_mail_open", + "imageName": "harvest_special_mail_open.png", + "roiFront": "1201,380,55,110", + "roiBack": "1190,348,79,162", + "method": "Template matching", + "threshold": 0.8, + "description": "特殊邮件打开状态" + }, + { + "itemName": "read_all_mail", + "imageName": "harvest_read_all_mail.png", + "roiFront": "155,603,166,44", + "roiBack": "149,588,182,72", + "method": "Template matching", + "threshold": 0.8, + "description": "一键已读所有邮件" } ] \ No newline at end of file diff --git a/tasks/Restart/login.py b/tasks/Restart/login.py index 89825406d..7f0ed0315 100644 --- a/tasks/Restart/login.py +++ b/tasks/Restart/login.py @@ -1,7 +1,7 @@ # This Python file uses the following encoding: utf-8 # @author runhey # github https://github.com/runhey - +import random from module.base.timer import Timer from module.exception import RequestHumanTakeover, GameTooManyClickError, GameStuckError from module.logger import logger @@ -38,7 +38,10 @@ def _app_handle_login(self) -> bool: orientation_timer.reset() self.screenshot() - + # 取消继续战斗 + if self.appear_then_click(self.I_CANCEL_BATTLE, interval=0.8): + logger.info('Cancel continue battle') + continue # 确认进入庭院 if self.appear_then_click(self.I_LOGIN_SCROOLL_CLOSE, interval=2, threshold=0.9): logger.info('Open scroll') @@ -227,32 +230,9 @@ def harvest(self): timer_harvest.reset() continue # 判断是否勾选了收取邮件(不收取邮件可以查看每日收获) - if not skip_default and self.config.restart.harvest_config.enable_mail: - if self.appear(self.I_HARVEST_MAIL_CONFIRM): - self.click(self.I_HARVEST_MAIL_CONFIRM, interval=2) - timer_harvest.reset() - continue - if self.appear(self.I_HARVEST_MAIL_ALL, threshold=0.9): - self.click(self.I_HARVEST_MAIL_ALL, interval=2) - self.wait_until_appear(self.I_HARVEST_MAIL_CONFIRM, wait_time=1) - timer_harvest.reset() - continue - # threshold如果是0.9,可能会导致有邮件但无法识别永久卡住 - if self.appear(self.I_HARVEST_MAIL_OPEN, threshold=0.8): - self.click(self.I_HARVEST_MAIL_OPEN, interval=0.8) - timer_harvest.reset() - continue - if self.appear(self.I_HARVEST_MAIL_2): - self.click(self.I_HARVEST_MAIL_2, interval=0.8) - timer_harvest.reset() - continue - if ((self.appear(self.I_HARVEST_MAIL) or self.appear(self.I_HARVEST_MAIL_COPY)) - and not self.appear(self.I_LOGIN_RED_CLOSE)): - self.click(self.I_HARVEST_MAIL, interval=2) - self.wait_until_appear(self.I_HARVEST_MAIL_ALL, wait_time=2) - timer_harvest.reset() - continue - + if not skip_default and self.config.restart.harvest_config.enable_mail and self.harvest_mail(): + timer_harvest.reset() + continue if self.appear_then_click(self.I_HARVEST_AP, interval=1, threshold=0.7): timer_harvest.reset() continue @@ -289,3 +269,37 @@ def harvest(self): def set_specific_usr(self, character: str): self.character = character self.O_LOGIN_SPECIFIC_SERVE.keyword = character + + def harvest_mail(self, ) -> bool: + if ((self.appear(self.I_HARVEST_MAIL) or self.appear(self.I_HARVEST_MAIL_COPY)) + and not self.appear(self.I_LOGIN_RED_CLOSE)): + self.click(self.I_HARVEST_MAIL, interval=2) + self.wait_until_appear(self.I_READ_ALL_MAIL, wait_time=2) + else: + return False + logger.info('Harvest system mail') + self.click(self.I_SYSTEM_MAIL_CLOSE) + self.wait_until_appear(self.I_SYSTEM_MAIL_OPEN, wait_time=2) + self.exec_harvest_mail() + logger.info('Harvest special mail') + self.click(self.I_SPECIAL_MAIL_CLOSE) + self.wait_until_appear(self.I_SPECIAL_MAIL_OPEN, wait_time=2) + self.exec_harvest_mail() + return True + + def exec_harvest_mail(self): + timeout_timer = Timer(3).start() + while not timeout_timer.reached(): + self.screenshot() + if self.appear_then_click(self.I_READ_ALL_MAIL, interval=1.5): + continue + if self.appear(self.I_HARVEST_MAIL_CONFIRM): + self.click(self.I_HARVEST_MAIL_CONFIRM, interval=2) + self.wait_until_disappear(self.I_HARVEST_MAIL_CONFIRM) + break + if self.appear(self.I_HARVEST_MAIL_ALL, threshold=0.9): + time.sleep(random.uniform(0.3, 0.5)) + self.click(self.I_HARVEST_MAIL_ALL, interval=2) + self.wait_until_appear(self.I_HARVEST_MAIL_CONFIRM, wait_time=1) + timeout_timer.reset() + continue diff --git a/tasks/Restart/login/image.json b/tasks/Restart/login/image.json index 5ec4943ff..8daae39aa 100644 --- a/tasks/Restart/login/image.json +++ b/tasks/Restart/login/image.json @@ -142,5 +142,14 @@ "method": "Template matching", "threshold": 0.8, "description": "取消体验服切换弹窗" + }, + { + "itemName": "cancel_battle", + "imageName": "login_cancel_battle.png", + "roiFront": "471,395,129,55", + "roiBack": "367,227,545,296", + "method": "Template matching", + "threshold": 0.8, + "description": "取消继续战斗" } ] \ No newline at end of file diff --git a/tasks/Restart/login/login_cancel_battle.png b/tasks/Restart/login/login_cancel_battle.png new file mode 100644 index 000000000..4e70bfc56 Binary files /dev/null and b/tasks/Restart/login/login_cancel_battle.png differ diff --git a/tasks/RichMan/assets.py b/tasks/RichMan/assets.py index 758998b44..d20f7d45d 100644 --- a/tasks/RichMan/assets.py +++ b/tasks/RichMan/assets.py @@ -25,8 +25,8 @@ class RichManAssets: I_GUILD_SKIN = RuleImage(roi_front=(795,438,71,72), roi_back=(320,162,573,371), threshold=0.8, method="Template matching", file="./tasks/RichMan/guild/guild_guild_skin.png") # 皮肤券判断是否到末端 I_GUILD_SKIN_CHECK = RuleImage(roi_front=(795,438,71,72), roi_back=(320,162,573,371), threshold=0.8, method="Template matching", file="./tasks/RichMan/guild/guild_guild_skin.png") - # 购买检查 - I_GUILD_CHECK_SCRAP = RuleImage(roi_front=(561,429,90,88), roi_back=(561,429,90,88), threshold=0.8, method="Template matching", file="./tasks/RichMan/guild/guild_guild_check_scrap.png") + # 购买黑碎检查 + I_GUILD_CHECK_SCRAP = RuleImage(roi_front=(592,248,90,88), roi_back=(593,249,90,88), threshold=0.6, method="Template matching", file="./tasks/RichMan/guild/guild_guild_check_scrap.png") # Ocr Rule Assets @@ -256,7 +256,7 @@ class RichManAssets: # description I_SCA_SELECT_3 = RuleImage(roi_front=(972,517,123,50), roi_back=(972,517,123,50), threshold=0.8, method="Template matching", file="./tasks/RichMan/mall/scales/scales_sca_select_3.png") # 获得的六星 - I_SCA_SIX_STAR = RuleImage(roi_front=(119,261,100,22), roi_back=(108,246,261,57), threshold=0.8, method="Template matching", file="./tasks/RichMan/mall/scales/scales_sca_six_star.png") + I_SCA_SIX_STAR = RuleImage(roi_front=(120,216,97,22), roi_back=(113,102,1057,157), threshold=0.8, method="Template matching", file="./tasks/RichMan/mall/scales/scales_sca_six_star.png") # 点击屏幕继续 I_SCA_REWARD = RuleImage(roi_front=(584,503,100,100), roi_back=(584,503,100,100), threshold=0.8, method="Template matching", file="./tasks/RichMan/mall/scales/scales_sca_reward.png") # 点击兑换 diff --git a/tasks/RichMan/guild/guild_guild_check_scrap.png b/tasks/RichMan/guild/guild_guild_check_scrap.png index a0f477326..97be0626f 100644 Binary files a/tasks/RichMan/guild/guild_guild_check_scrap.png and b/tasks/RichMan/guild/guild_guild_check_scrap.png differ diff --git a/tasks/RichMan/guild/image.json b/tasks/RichMan/guild/image.json index a9807cb3a..fe9216173 100644 --- a/tasks/RichMan/guild/image.json +++ b/tasks/RichMan/guild/image.json @@ -65,10 +65,10 @@ { "itemName": "guild_check_scrap", "imageName": "guild_guild_check_scrap.png", - "roiFront": "561,429,90,88", - "roiBack": "561,429,90,88", + "roiFront": "592,248,90,88", + "roiBack": "593,249,90,88", "method": "Template matching", - "threshold": 0.8, - "description": "购买检查" + "threshold": 0.6, + "description": "购买黑碎检查" } ] \ No newline at end of file diff --git a/tasks/RichMan/mall/scales/image.json b/tasks/RichMan/mall/scales/image.json index b008782f3..5cd27c687 100644 --- a/tasks/RichMan/mall/scales/image.json +++ b/tasks/RichMan/mall/scales/image.json @@ -110,8 +110,8 @@ { "itemName": "sca_six_star", "imageName": "scales_sca_six_star.png", - "roiFront": "119,261,100,22", - "roiBack": "108,246,261,57", + "roiFront": "120,216,97,22", + "roiBack": "113,102,1057,157", "method": "Template matching", "threshold": 0.8, "description": "获得的六星" diff --git a/tasks/RichMan/mall/scales/scales_sca_six_star.png b/tasks/RichMan/mall/scales/scales_sca_six_star.png index 8d5097e0f..854190f32 100644 Binary files a/tasks/RichMan/mall/scales/scales_sca_six_star.png and b/tasks/RichMan/mall/scales/scales_sca_six_star.png differ diff --git a/tasks/RyouToppa/script_task.py b/tasks/RyouToppa/script_task.py index ccbe4f91b..06260a90c 100644 --- a/tasks/RyouToppa/script_task.py +++ b/tasks/RyouToppa/script_task.py @@ -304,7 +304,7 @@ def attack_area(self, index: int): click_failure_count = 0 while True: self.screenshot() - if click_failure_count >= 3: + if click_failure_count >= 5: logger.warning("Click failure, check your click position") return False if not self.appear(self.I_TOPPA_RECORD, threshold=0.85): @@ -319,6 +319,7 @@ def attack_area(self, index: int): click_failure_count += 1 continue if self.click(rcl, interval=5): + click_failure_count += 1 continue diff --git a/tasks/Utils/config_enum.py b/tasks/Utils/config_enum.py index 3d57f357c..480fa2f65 100644 --- a/tasks/Utils/config_enum.py +++ b/tasks/Utils/config_enum.py @@ -4,6 +4,7 @@ from enum import Enum class ShikigamiClass(str, Enum): + UR = 'UR' SP = 'SP' SSR = 'SSR' SR = 'SR' diff --git a/tasks/WeeklyTrifles/assets.py b/tasks/WeeklyTrifles/assets.py index 31e0137ab..92418def4 100644 --- a/tasks/WeeklyTrifles/assets.py +++ b/tasks/WeeklyTrifles/assets.py @@ -35,6 +35,8 @@ class WeeklyTriflesAssets: I_BM_CONFIRM = RuleImage(roi_front=(418,620,173,59), roi_back=(418,620,173,59), threshold=0.8, method="Template matching", file="./tasks/WeeklyTrifles/broken_amulet/broken_amulet_bm_confirm.png") # 再次召唤 I_BM_AGAIN = RuleImage(roi_front=(686,617,178,60), roi_back=(686,617,178,60), threshold=0.8, method="Template matching", file="./tasks/WeeklyTrifles/broken_amulet/broken_amulet_bm_again.png") + # 破碎符咒召唤次数选择标志 + I_BMT_CHECK = RuleImage(roi_front=(742,571,32,33), roi_back=(644,565,276,41), threshold=0.8, method="Template matching", file="./tasks/WeeklyTrifles/broken_amulet/broken_amulet_bmt_check.png") # Ocr Rule Assets @@ -42,6 +44,8 @@ class WeeklyTriflesAssets: O_BA_AMOUNT_1 = RuleOcr(roi=(535,11,124,36), area=(535,11,124,36), mode="Digit", method="Default", keyword="", name="ba_amount_1") # 召唤的时候的数量 O_BA_AMOUNT_2 = RuleOcr(roi=(762,570,125,35), area=(762,570,125,35), mode="DigitCounter", method="Default", keyword="", name="ba_amount_2") + # 破碎符咒召唤次数 + O_BA_TIMES = RuleOcr(roi=(741,564,174,44), area=(641,566,278,41), mode="Full", method="Default", keyword="", name="ba_times") # Click Rule Assets diff --git a/tasks/WeeklyTrifles/broken_amulet/broken_amulet_bmt_check.png b/tasks/WeeklyTrifles/broken_amulet/broken_amulet_bmt_check.png new file mode 100644 index 000000000..38682e3b9 Binary files /dev/null and b/tasks/WeeklyTrifles/broken_amulet/broken_amulet_bmt_check.png differ diff --git a/tasks/WeeklyTrifles/broken_amulet/image.json b/tasks/WeeklyTrifles/broken_amulet/image.json index b9737c881..747f23214 100644 --- a/tasks/WeeklyTrifles/broken_amulet/image.json +++ b/tasks/WeeklyTrifles/broken_amulet/image.json @@ -25,5 +25,14 @@ "method": "Template matching", "threshold": 0.8, "description": "再次召唤" + }, + { + "itemName": "bmt_check", + "imageName": "broken_amulet_bmt_check.png", + "roiFront": "742,571,32,33", + "roiBack": "644,565,276,41", + "method": "Template matching", + "threshold": 0.8, + "description": "破碎符咒召唤次数选择标志" } ] \ No newline at end of file diff --git a/tasks/WeeklyTrifles/broken_amulet/ocr.json b/tasks/WeeklyTrifles/broken_amulet/ocr.json index 434d13644..8f1d97caf 100644 --- a/tasks/WeeklyTrifles/broken_amulet/ocr.json +++ b/tasks/WeeklyTrifles/broken_amulet/ocr.json @@ -16,5 +16,14 @@ "method": "Default", "keyword": "", "description": "召唤的时候的数量" + }, + { + "itemName": "ba_times", + "roiFront": "741,564,174,44", + "roiBack": "641,566,278,41", + "mode": "Full", + "method": "Default", + "keyword": "", + "description": "破碎符咒召唤次数" } ] \ No newline at end of file diff --git a/tasks/WeeklyTrifles/script_task.py b/tasks/WeeklyTrifles/script_task.py index aab228004..ce8aab1a8 100644 --- a/tasks/WeeklyTrifles/script_task.py +++ b/tasks/WeeklyTrifles/script_task.py @@ -2,13 +2,14 @@ # @author runhey # github https://github.com/runhey import time +from time import sleep from module.exception import TaskEnd from module.logger import logger from module.base.timer import Timer from tasks.GameUi.game_ui import GameUi -from tasks.GameUi.page import page_main, page_collection, page_area_boss, page_secret_zones, page_summon +from tasks.GameUi.page import page_main, page_collection, page_area_boss, page_secret_zones, page_summon, random_click from tasks.WeeklyTrifles.config import Trifles from tasks.WeeklyTrifles.assets import WeeklyTriflesAssets @@ -203,14 +204,14 @@ def _share_secret(self): # 返回 self.ui_click(self.I_UI_BACK_BLUE, self.I_CHECK_MAIN) - def _broken_amulet(self, num: int): + def _broken_amulet(self, dest_num: int): """ - :param num: + :param dest_num: :return: """ - def click_confirm(): - self.wait_until_appear(self.I_BM_CONFIRM) + def exit_amulet(): + self.wait_until_appear(self.I_BM_CONFIRM, wait_time=3) while 1: self.screenshot() if not self.appear(self.I_BM_CONFIRM): @@ -223,47 +224,58 @@ def click_confirm(): self.ui_get_current_page() self.ui_goto(page_summon) self.screenshot() - number = self.O_BA_AMOUNT_1.ocr(self.device.image) - if number == 0: + real_num = self.O_BA_AMOUNT_1.ocr(self.device.image) + if real_num <= 0: logger.warning('No broken amulet') return - logger.info(f'Broken amulet: {number}') + logger.info(f'Broken amulet: {real_num}') count = 0 self.wait_until_appear(self.I_BM_ENTER) - while 1: - self.screenshot() - if not self.appear(self.I_BM_ENTER): - break - if self.appear_then_click(self.I_BM_ENTER, interval=1): - continue - count += 10 logger.info('Enter broken amulet') - while 1: + while count < dest_num: self.screenshot() - time.sleep(0.5) - - if not self.appear(self.I_BM_CONFIRM): - continue - if count >= num: - logger.info(f'Broken amulet finished: {count}') - click_confirm() - break - cu, re, total = self.O_BA_AMOUNT_2.ocr(self.device.image) - if cu <= 10 and total == 10: - logger.info(f'Broken amulet count: {count}. Current: {cu}. Total: {total}') - click_confirm() - break - if self.appear_then_click(self.I_BM_AGAIN, interval=1): - logger.info(f'Broken amulet count: {count}. Current: {cu}') + real_num = self.O_BA_AMOUNT_1.ocr(self.device.image) + if real_num <= 0: + exit_amulet() + return + if self.appear_then_click(self.I_BM_ENTER, interval=1) or self.appear_then_click(self.I_BM_AGAIN, interval=1): + sleep(0.4) # 等待动画开始 + timeout_timer = Timer(5).start() + # 随机点击直到再次召唤出现或者超时 + while not timeout_timer.reached(): + if not self.click(random_click(), interval=0.8): + continue + self.screenshot() + if self.appear(self.I_BM_AGAIN, interval=0.8): + break + else: + logger.warning(f'Wait for again timeout:Count[{count}], Remain[{real_num}]') + exit_amulet() + return + else: + # 既没有出现召唤破碎符咒也没有出现再次召唤, 则退出(一般不会出现这种情况, 只是为了异常处理) + exit_amulet() + return + x_10, _, _, _ = self.O_BA_TIMES.ocr(self.device.image, '10次') + x_50, _, _, _ = self.O_BA_TIMES.ocr(self.device.image, '50次') + self.I_BMT_CHECK.match(self.device.image) + x_check, y_check, width_check, height_check = self.I_BMT_CHECK.roi_front + selected_10 = min(abs(x_10 - x_check), abs(x_50 - x_check)) == abs(x_10 - x_check) + logger.info(f'Current selected {"10" if selected_10 else "50"} amulet') + count += 10 if selected_10 else 50 + logger.info(f'Broken amulet:Count[{count}], Remain[{real_num}]') + # 一次50票不超过限制且当前选择的是10票则切换50票 + if count + 50 < dest_num and selected_10: + logger.hr('Switch to 50 amulet') + self.device.click(x=x_50 - width_check // 2, y=y_check + height_check // 2, control_name='Click_50') self.device.click_record_clear() - count += 10 - continue - - - - - - + # 一次50票会超过限制且当前选择的是50票则切换10票 + if count + 50 >= dest_num and not selected_10: + logger.hr('Switch to 10 amulet') + self.device.click(x=x_10 - width_check // 2, y=y_check + height_check // 2, control_name='Click_10') + self.device.click_record_clear() + # 正常结束且还有票, 则执行一次退出 + exit_amulet() if __name__ == '__main__':