1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2026-01-07 14:05:12 +00:00

Compare commits

..

No commits in common. "f8404edd9e9c45b688f854065fdae0b6a624c291" and "baac90ecf01a06f66ed8d94039db815e90630e63" have entirely different histories.

8 changed files with 128 additions and 120 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1018 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1018 KiB

View File

@ -77,12 +77,6 @@ class DeployConfig(ConfigModel):
self.config_template = {}
self.read()
self.set_repo()
self.write()
self.show_config()
def set_repo(self):
# Bypass webui.config.DeployConfig.__setattr__()
# Don't write these into deploy.yaml
if self.Repository == 'cn':
@ -90,6 +84,9 @@ class DeployConfig(ConfigModel):
if self.Repository == 'global':
super().__setattr__('Repository', 'https://github.com/TheFunny/ArisuAutoSweeper')
self.write()
self.show_config()
def show_config(self):
logger.hr("Show deploy config", 1)
for k, v in self.config.items():

View File

@ -5,7 +5,6 @@ import time
from typing import Generator, List, Tuple
import requests
from deploy.Windows.config import ExecutionError
from deploy.Windows.git import GitManager
from deploy.Windows.pip import PipManager
@ -21,7 +20,6 @@ from module.webui.utils import TaskHandler, get_next_time
class Updater(DeployConfig, GitManager, PipManager):
def __init__(self, file=DEPLOY_CONFIG):
super().__init__(file=file)
self.set_repo()
self.state = 0
self.event: threading.Event = None

View File

@ -20,23 +20,6 @@ BOX_CAFE = ButtonWrapper(
button=(33, 130, 1247, 569),
),
)
BOX_SEARCH = ButtonWrapper(
name='BOX_SEARCH',
jp=Button(
file='./assets/jp/cafe/BOX_SEARCH.png',
area=(61, 72, 1176, 653),
search=(41, 52, 1196, 673),
color=(172, 180, 188),
button=(61, 72, 1176, 653),
),
en=Button(
file='./assets/en/cafe/BOX_SEARCH.png',
area=(61, 72, 1176, 653),
search=(41, 52, 1196, 673),
color=(172, 180, 188),
button=(61, 72, 1176, 653),
),
)
CAFE_FIRST = ButtonWrapper(
name='CAFE_FIRST',
jp=Button(

View File

@ -1,12 +1,18 @@
import cv2
import numpy as np
from enum import Enum
from module.base.decorator import Config
from module.base.timer import Timer
from module.logger import logger
from module.base.timer import Timer
from module.base.button import ClickButton
from module.base.decorator import Config
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 *
from tasks.cafe.ui import CafeUI
SWITCH_CAFE = Switch('Cafe_switch')
SWITCH_CAFE.add_state('off', CHANGE_CAFE_NOT_SELECTED)
@ -27,17 +33,103 @@ class CafeStatus(Enum):
FINISHED = -1
class Cafe(CafeUI):
@Config.when(Emulator_GameLanguage='jp')
def is_second_cafe_on(self):
return self.config.Cafe_SecondCafe
class Cafe(UI):
template = CLICKABLE_TEMPLATE
@Config.when(Emulator_GameLanguage=None)
def is_second_cafe_on(self):
@staticmethod
def merge_points(points, threshold=3):
if len(points) <= 1:
return points
result = []
for point in points:
if not result:
result.append(point)
continue
if point[0] - result[-1][0] < threshold and point[1] - result[-1][1] < threshold:
result[-1] = ((point[0] + result[-1][0]) // 2, (point[1] + result[-1][1]) // 2)
continue
result.append(point)
return result
@staticmethod
def _extract_clickable_from_image(image):
# convert to hsv for better color matching
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
# set color range
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.8):
image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
template = cv2.cvtColor(self.template.matched_button.image, cv2.COLOR_RGB2GRAY)
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(res >= threshold)
return [point for point in zip(*loc[::-1])]
def _get_clickable_buttons(self, threshold=0.8, offset=(0, 0)):
image = self.device.image
h, w = image.shape[:2]
image = cv2.rectangle(image, (0, 10), (w - 25, h - 10), (0, 0, 0), 50)
image = self._extract_clickable_from_image(image)
points = self._match_clickable_points(image, threshold)
points = self.merge_points(points)
if not points:
return []
area = area_offset((0, 0, self.template.width, self.template.height), offset)
return [
ClickButton(
button=area_offset(area, offset=point),
name=self.template.name
)
for point in points
]
def _reset_cafe_position(self, direction: str):
width = BOX_CAFE.width
height = BOX_CAFE.height
r = np.random.uniform(0.6, 0.8)
vector_down = (width * r, height * r)
vector_up = (width * r, -height * r)
vector_left = (-width * r, 0)
vector_right = (width * r, 0)
random_r = (-5, -5, 5, 5)
match direction:
case 'init':
self.device.pinch()
self.device.swipe_vector(vector_down, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5)
case 'left':
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5)
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)
num = ocr.detect_and_ocr(self.device.image)
if len(num) != 1:
logger.warning(f'Invalid reward num: {num}')
num = float(num[0].ocr_text.rstrip('%'))
logger.attr('Reward', num)
return num
def _cafe_additional(self) -> bool:
if self.appear_then_click(INVENTORY):
return True
if self.appear_then_click(MOMOTALK_CLOSE):
return True
return False
is_second_cafe_on = property(is_second_cafe_on)
def _handle_cafe(self, status):
match status:
case CafeStatus.STUDENT_LIST:
@ -45,7 +137,7 @@ class Cafe(CafeUI):
if not self.appear(STUDENT_LIST):
return CafeStatus.OCR
case CafeStatus.OCR:
reward = self.get_reward_num()
reward = self._get_reward_num()
if reward == 0:
return CafeStatus.GOT
if self.appear_then_click(CHECK_REWARD):
@ -65,14 +157,14 @@ class Cafe(CafeUI):
if not self.appear(GET_REWARD_CLOSE):
return CafeStatus.CLICK
case CafeStatus.CLICK:
buttons = self.get_clickable_buttons(offset=(45, 10))
buttons = self._get_clickable_buttons(offset=(45, 10))
self.click = len(buttons)
logger.attr('Clickable', self.click)
if not buttons:
return CafeStatus.CHECK
self.click_with_interval(buttons[0], interval=1)
case CafeStatus.CHECK:
buttons = self.get_clickable_buttons()
buttons = self._get_clickable_buttons()
if not self.is_adjust_on:
if not buttons:
return CafeStatus.FINISHED
@ -85,11 +177,11 @@ class Cafe(CafeUI):
return CafeStatus.CLICK
match self.check:
case 1:
self.reset_cafe_position('left')
self._reset_cafe_position('left')
case 2:
self.reset_cafe_position('right')
self._reset_cafe_position('right')
case 3:
self.reset_cafe_position('init')
self._reset_cafe_position('init')
case 4:
return CafeStatus.FINISHED
case CafeStatus.FINISHED:
@ -98,6 +190,16 @@ class Cafe(CafeUI):
logger.warning(f'Invalid status: {status}')
return status
@Config.when(Emulator_GameLanguage='jp')
def is_second_cafe_on(self):
return self.config.Cafe_SecondCafe
@Config.when(Emulator_GameLanguage=None)
def is_second_cafe_on(self):
return False
is_second_cafe_on = property(is_second_cafe_on)
def run(self):
self.click = 0
self.check = 0
@ -110,7 +212,7 @@ class Cafe(CafeUI):
status = CafeStatus.STUDENT_LIST
loading_timer = Timer(2).start()
action_timer = Timer(1, count=1)
action_timer = Timer(1, count=1) # cant be too fast
is_list = False
is_reset = False
is_second = False
@ -122,7 +224,7 @@ class Cafe(CafeUI):
self.device.screenshot()
if self.ui_additional() or self.cafe_additional():
if self.ui_additional() or self._cafe_additional():
continue
if not loading_timer.reached():
@ -144,7 +246,7 @@ class Cafe(CafeUI):
continue
if is_touch_on and not is_reset and status == CafeStatus.CLICK:
self.reset_cafe_position('init')
self._reset_cafe_position('init')
is_reset = True
continue

View File

@ -1,72 +0,0 @@
import cv2
import numpy as np
from module.logger import logger
from module.ocr.ocr import Digit
from tasks.base.ui import UI
from tasks.cafe.assets.assets_cafe import *
class CafeUI(UI):
template = CLICKABLE_TEMPLATE
def get_reward_num(self):
ocr = Digit(OCR_CAFE)
num = ocr.detect_and_ocr(self.device.image)
if len(num) != 1:
logger.warning(f'Invalid reward num: {num}')
num = float(num[0].ocr_text.rstrip('%'))
logger.attr('Reward', num)
return num
@staticmethod
def extract_clickable_from_image(image):
# convert to hsv for better color matching
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
# set color range
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 get_clickable_buttons(self, similarity=0.8, offset=(45, 10)):
image = self.extract_clickable_from_image(self.device.image)
self.template.matched_button._button_offset = offset
self.template.load_offset(self.template)
self.template.load_search(BOX_SEARCH.area)
points = self.template.match_multi_template(image, similarity)
return points
def reset_cafe_position(self, direction: str):
width = BOX_CAFE.width
height = BOX_CAFE.height
r = np.random.uniform(0.6, 0.8)
vector_down = (width * r, height * r)
vector_up = (width * r, -height * r)
vector_left = (-width * r, 0)
vector_right = (width * r, 0)
random_r = (-5, -5, 5, 5)
match direction:
case 'init':
self.device.pinch()
self.device.swipe_vector(vector_down, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5)
case 'left':
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5)
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 cafe_additional(self) -> bool:
if self.appear_then_click(INVENTORY):
return True
if self.appear_then_click(MOMOTALK_CLOSE):
return True
return False

View File

@ -21,12 +21,12 @@ class ScrimmageStatus(Enum):
class Scrimmage(ScrimmageUI):
@property
def scrimmage_info(self):
scrimmage = (SELECT_TRINITY, SELECT_GEHENNA, SELECT_MILLENNIUM)
bounty = (SELECT_TRINITY, SELECT_GEHENNA, SELECT_MILLENNIUM)
check = (CHECK_TRINITY, CHECK_GEHENNA, CHECK_MILLENNIUM)
stage = (self.config.Trinity_Stage, self.config.Gehenna_Stage, self.config.Millennium_Stage)
count = (self.config.Trinity_Count, self.config.Gehenna_Count, self.config.Millennium_Count)
ap = (10 if stage == 1 else 15 for stage in stage)
info = zip(scrimmage, check, stage, count, ap)
info = zip(bounty, check, stage, count, ap)
return filter(lambda x: x[3] > 0, info)
@property
@ -38,7 +38,7 @@ class Scrimmage(ScrimmageUI):
return task
def error_handler(self):
action = self.config.Scrimmage_OnError
action = self.config.Bounty_OnError
if action == 'stop':
raise RequestHumanTakeover
elif action == 'skip':