feat: add recruit sign-in automation
This commit is contained in:
1 parent
19c502f659
commit
8b7c5d45da
12 files changed
+288
No files matched your search
@@ -0,0 +1,168 @@
|
||||
"""商城英雄招募的限时 UP 神灯任务与免费神灯领取。"""
|
||||
import time
|
||||
|
||||
from .engine import WorkflowError
|
||||
|
||||
|
||||
class RecruitRunner:
|
||||
def __init__(self, desktop, matcher, flow, region_provider, log=print, timeout=12):
|
||||
self.desktop = desktop
|
||||
self.matcher = matcher
|
||||
self.flow = flow
|
||||
self.region_provider = region_provider
|
||||
self.log = log
|
||||
self.timeout = timeout
|
||||
|
||||
def wait(self, *names):
|
||||
end = time.monotonic() + self.timeout
|
||||
previous, stable = None, 0
|
||||
while time.monotonic() < end:
|
||||
shot = self.desktop.screenshot()
|
||||
region = self.region_provider(shot)
|
||||
frame = self.matcher.frame(shot, region)
|
||||
found = next((name for name in names
|
||||
if self.matcher.matches(frame, self.flow['states'][name])), None)
|
||||
stable = stable + 1 if found and found == previous else (1 if found else 0)
|
||||
previous = found
|
||||
if stable >= 2:
|
||||
return found, shot, region, frame
|
||||
time.sleep(.25)
|
||||
raise WorkflowError('未识别到预期页面 ' + '/'.join(names) + ',已停止。')
|
||||
|
||||
def observe(self):
|
||||
shot = self.desktop.screenshot()
|
||||
region = self.region_provider(shot)
|
||||
return shot, region, self.matcher.frame(shot, region)
|
||||
|
||||
def click(self, name, observation, hold=.8):
|
||||
shot, region, _ = observation[-3:]
|
||||
if self.region_provider(shot) != region:
|
||||
raise WorkflowError('识别后游戏窗口移动,已停止,请重新运行。')
|
||||
self.desktop.click(self.flow['clicks'][name], region, shot.size, hold=hold)
|
||||
self.log('已执行:' + name)
|
||||
|
||||
def click_location(self, location, observation):
|
||||
shot, region, _ = observation[-3:]
|
||||
x, y, width, height = location
|
||||
self.desktop.click(((x + width / 2) / 562, (y + height / 2) / 1002),
|
||||
region, shot.size, hold=.8)
|
||||
|
||||
def swipe(self, name, observation):
|
||||
shot, region, _ = observation[-3:]
|
||||
start, end = self.flow['swipes'][name]
|
||||
self.desktop.drag(start, end, region, shot.size)
|
||||
time.sleep(self.flow.get('swipe_settle_seconds', .5))
|
||||
|
||||
def has_dot(self, frame, spec_name, search=None):
|
||||
spec = dict(self.flow[spec_name])
|
||||
if search:
|
||||
spec['search'] = search
|
||||
score, _ = self.matcher.locate(frame, spec)
|
||||
return score >= spec.get('threshold', .86)
|
||||
|
||||
def task_buttons_with_dot(self, frame):
|
||||
buttons = self.matcher.locate_all(frame, self.flow['task_button'], limit=8)
|
||||
for _, location in buttons:
|
||||
x, y, width, _ = location
|
||||
# The red dot sits just above the task-button's top-right corner.
|
||||
dot_search = [x + width - 32, max(0, y - 31), x + width + 8, y + 5]
|
||||
if self.has_dot(frame, 'card_task_dot', dot_search):
|
||||
yield location
|
||||
|
||||
def dismiss_reward(self):
|
||||
reward = self.wait('reward')
|
||||
self.click('dismiss_reward', reward, hold=.2)
|
||||
self.wait('lamp')
|
||||
|
||||
def claim_visible_tasks(self):
|
||||
claimed = 0
|
||||
empty_scrolls = 0
|
||||
while claimed < self.flow['limits']['task_claims']:
|
||||
lamp = self.wait('lamp')
|
||||
spec = self.flow['task_claim']
|
||||
matches = self.matcher.locate_all(lamp[3], spec, limit=8)
|
||||
if matches:
|
||||
_, location = matches[0]
|
||||
self.click_location(location, lamp)
|
||||
self.log('已领取神灯任务奖励。')
|
||||
self.dismiss_reward()
|
||||
claimed += 1
|
||||
empty_scrolls = 0
|
||||
continue
|
||||
if empty_scrolls >= self.flow['limits']['task_scrolls']:
|
||||
break
|
||||
self.swipe('task_list_up', lamp)
|
||||
empty_scrolls += 1
|
||||
return claimed
|
||||
|
||||
def process_lamp(self):
|
||||
lamp = self.wait('lamp')
|
||||
if self.has_dot(lamp[3], 'task_tab_dot'):
|
||||
self.click('task_tab', lamp)
|
||||
self.wait('lamp')
|
||||
self.claim_visible_tasks()
|
||||
|
||||
lamp = self.wait('lamp')
|
||||
if self.has_dot(lamp[3], 'gift_tab_dot'):
|
||||
self.click('gift_tab', lamp)
|
||||
gift = self.wait('gift')
|
||||
score, location = self.matcher.locate(gift[3], self.flow['free_button'])
|
||||
if score >= self.flow['free_button'].get('threshold', .86):
|
||||
self.click_location(location, gift)
|
||||
self.log('已领取免费神灯。')
|
||||
self.dismiss_reward()
|
||||
else:
|
||||
self.log('神灯礼包没有可领取的免费神灯,跳过。')
|
||||
|
||||
lamp = self.wait('lamp')
|
||||
self.click('close_lamp', lamp, hold=.2)
|
||||
time.sleep(.5)
|
||||
|
||||
def return_home(self):
|
||||
observation = self.observe()
|
||||
self.click('shop_back', observation, hold=.2)
|
||||
self.wait('home')
|
||||
self.log('已确认返回首页。')
|
||||
|
||||
def run(self, dry_run=False):
|
||||
home = self.wait('home')
|
||||
if dry_run:
|
||||
self.log('首页识别通过。计划:商城 → 英雄招募限时 UP → 神灯任务/礼包 → 返回首页。未点击。')
|
||||
return 'preview'
|
||||
|
||||
self.click('shop', home, hold=.8)
|
||||
shop = self.wait('shop')
|
||||
for _ in range(self.flow['limits']['scroll_to_recruit']):
|
||||
self.swipe('shop_down', shop)
|
||||
shop = self.observe()
|
||||
if self.matcher.locate_all(shop[2], self.flow['task_button'], limit=1):
|
||||
break
|
||||
|
||||
handled, blank_pages = 0, 0
|
||||
while handled < self.flow['limits']['cards']:
|
||||
_, _, frame = self.observe()
|
||||
task_button = next(self.task_buttons_with_dot(frame), None)
|
||||
if task_button:
|
||||
# Click the button itself, rather than its red dot.
|
||||
x, y, width, height = task_button
|
||||
shot, region, current = self.observe()
|
||||
self.desktop.click(((x + width / 2) / 562, (y + height / 2) / 1002),
|
||||
region, shot.size, hold=.8)
|
||||
self.log('已打开限时 UP 卡片的神灯召唤。')
|
||||
self.process_lamp()
|
||||
handled += 1
|
||||
blank_pages = 0
|
||||
continue
|
||||
if blank_pages >= self.flow['limits']['card_pages']:
|
||||
break
|
||||
# The card stack precedes 图腾寻宝. Pulling the list down shows
|
||||
# earlier UP cards without ever touching the treasure buttons.
|
||||
self.swipe('shop_down', self.observe())
|
||||
blank_pages += 1
|
||||
|
||||
self.return_home()
|
||||
if handled:
|
||||
self.log('已处理 %s 张限时 UP 卡片。' % handled)
|
||||
return 'claimed'
|
||||
self.log('没有带红点的限时 UP 任务卡片,未领取奖励。')
|
||||
return 'no_card_dot'
|
||||
Reference in new issue
Block a user