mirror of
https://github.com/TheFunny/ArisuAutoSweeper
synced 2026-06-09 20:04:52 +00:00
Upload code
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
from module.base.button import Button, ButtonWrapper
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.button_extract ```
|
||||
|
||||
BOX_CAFE = ButtonWrapper(
|
||||
name='BOX_CAFE',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/BOX_CAFE.png',
|
||||
area=(33, 130, 1247, 569),
|
||||
search=(13, 110, 1267, 589),
|
||||
color=(175, 181, 186),
|
||||
button=(33, 130, 1247, 569),
|
||||
),
|
||||
)
|
||||
CHECK_REWARD = ButtonWrapper(
|
||||
name='CHECK_REWARD',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/CHECK_REWARD.png',
|
||||
area=(1095, 621, 1146, 637),
|
||||
search=(1075, 601, 1166, 657),
|
||||
color=(82, 105, 129),
|
||||
button=(1086, 607, 1225, 685),
|
||||
),
|
||||
)
|
||||
CLICKABLE_TEMPLATE = ButtonWrapper(
|
||||
name='CLICKABLE_TEMPLATE',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/CLICKABLE_TEMPLATE.png',
|
||||
area=(0, 0, 42, 56),
|
||||
search=(0, 0, 62, 76),
|
||||
color=(77, 63, 1),
|
||||
button=(0, 0, 42, 56),
|
||||
),
|
||||
)
|
||||
GET_REWARD = ButtonWrapper(
|
||||
name='GET_REWARD',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/GET_REWARD.png',
|
||||
area=(611, 514, 669, 543),
|
||||
search=(591, 494, 689, 563),
|
||||
color=(159, 133, 48),
|
||||
button=(546, 494, 735, 563),
|
||||
),
|
||||
)
|
||||
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),
|
||||
),
|
||||
)
|
||||
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),
|
||||
),
|
||||
)
|
||||
OCR_CAFE = ButtonWrapper(
|
||||
name='OCR_CAFE',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/OCR_CAFE.png',
|
||||
area=(1103, 642, 1202, 672),
|
||||
search=(1083, 622, 1222, 692),
|
||||
color=(87, 107, 129),
|
||||
button=(1103, 642, 1202, 672),
|
||||
),
|
||||
)
|
||||
STUDENT_LIST = ButtonWrapper(
|
||||
name='STUDENT_LIST',
|
||||
jp=Button(
|
||||
file='./assets/jp/cafe/STUDENT_LIST.png',
|
||||
area=(612, 172, 667, 201),
|
||||
search=(592, 152, 687, 221),
|
||||
color=(145, 157, 172),
|
||||
button=(545, 423, 738, 495),
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,227 @@
|
||||
import cv2
|
||||
import numpy as np
|
||||
from enum import Enum
|
||||
|
||||
from module.logger import logger
|
||||
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 tasks.base.page import page_cafe
|
||||
from tasks.base.ui import UI
|
||||
from tasks.cafe.assets.assets_cafe import *
|
||||
|
||||
|
||||
class CafeStatus(Enum):
|
||||
STUDENT_LIST = 0
|
||||
OCR = 1
|
||||
REWARD = 2
|
||||
GOT = 3
|
||||
CLICK = 4
|
||||
CHECK = 5
|
||||
FINISHED = -1
|
||||
|
||||
|
||||
class Cafe(UI):
|
||||
@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
|
||||
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])
|
||||
# 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):
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||
template = self.btn.matched_button.image
|
||||
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
res = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
|
||||
loc = np.where(res >= threshold)
|
||||
return [point for point in zip(*loc[::-1])]
|
||||
|
||||
def _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))
|
||||
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.btn.width, self.btn.height), offset)
|
||||
return [
|
||||
ClickButton(
|
||||
button=area_offset(area, offset=point),
|
||||
name=self.btn.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)
|
||||
|
||||
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 _handle_cafe(self, status):
|
||||
match status:
|
||||
case CafeStatus.STUDENT_LIST:
|
||||
self.appear_then_click(STUDENT_LIST)
|
||||
if not self.appear(STUDENT_LIST):
|
||||
return CafeStatus.OCR
|
||||
case CafeStatus.OCR:
|
||||
reward = self._get_reward_num()
|
||||
if reward == 0:
|
||||
return CafeStatus.GOT
|
||||
if self.appear_then_click(CHECK_REWARD):
|
||||
return CafeStatus.REWARD
|
||||
case CafeStatus.REWARD:
|
||||
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)
|
||||
case CafeStatus.GOT:
|
||||
logger.info('Cafe reward have been got')
|
||||
self.appear_then_click(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])
|
||||
case CafeStatus.CHECK:
|
||||
buttons = self._get_clickable_buttons()
|
||||
if not self.is_adjust_on:
|
||||
if not buttons:
|
||||
return CafeStatus.FINISHED
|
||||
else:
|
||||
return CafeStatus.CLICK
|
||||
if not buttons:
|
||||
self.check += 1
|
||||
else:
|
||||
self.check = 0
|
||||
return CafeStatus.CLICK
|
||||
match self.check:
|
||||
case 1:
|
||||
self._reset_cafe_position('left')
|
||||
case 2:
|
||||
self._reset_cafe_position('right')
|
||||
case 3:
|
||||
self._reset_cafe_position('init')
|
||||
case 4:
|
||||
return CafeStatus.FINISHED
|
||||
case CafeStatus.FINISHED:
|
||||
return status
|
||||
case _:
|
||||
logger.warning(f'Invalid status: {status}')
|
||||
return status
|
||||
|
||||
def run(self):
|
||||
self.btn = CLICKABLE_TEMPLATE
|
||||
self.click = 0
|
||||
self.check = 0
|
||||
|
||||
is_reward_on = self.config.Cafe_Reward
|
||||
is_touch_on = self.config.Cafe_Touch
|
||||
self.is_adjust_on = self.config.Cafe_AutoAdjust
|
||||
|
||||
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)
|
||||
is_list = False
|
||||
is_reset = False
|
||||
is_enable = is_reward_on or is_touch_on
|
||||
|
||||
while is_enable:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.ui_additional():
|
||||
continue
|
||||
|
||||
if not loading_timer.reached():
|
||||
continue
|
||||
|
||||
if not is_list and status == CafeStatus.STUDENT_LIST and self.appear(STUDENT_LIST):
|
||||
is_list = True
|
||||
loading_timer = Timer(5).start()
|
||||
continue
|
||||
|
||||
if not is_reward_on and status == CafeStatus.OCR:
|
||||
logger.info('Skip reward')
|
||||
status = CafeStatus.CLICK
|
||||
continue
|
||||
|
||||
if not is_touch_on and status == CafeStatus.CLICK:
|
||||
logger.info('Skip touch')
|
||||
status = CafeStatus.FINISHED
|
||||
continue
|
||||
|
||||
if is_touch_on and not is_reset and status == CafeStatus.CLICK:
|
||||
self._reset_cafe_position('init')
|
||||
is_reset = True
|
||||
continue
|
||||
|
||||
if status == CafeStatus.CHECK and not check_timer.reached_and_reset():
|
||||
continue
|
||||
|
||||
if action_timer.reached_and_reset():
|
||||
status = self._handle_cafe(status)
|
||||
logger.attr('Status', status)
|
||||
|
||||
if status is CafeStatus.FINISHED:
|
||||
break
|
||||
|
||||
self.config.task_delay(server_update=True, minute=180)
|
||||
Reference in New Issue
Block a user