Opt: Remove unnecessary use of drags, fallback to swipe+click if drag is a must

This commit is contained in:
LmeSzinc 2022-02-01 21:49:57 +08:00
parent 7c4dfd8948
commit df310b9d09
13 changed files with 85 additions and 32 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -1,16 +1,18 @@
from module.base.utils import random_rectangle_vector
from module.campaign.campaign_base import CampaignBase as CampaignBase_
from module.exception import RequestHumanTakeover
from module.logger import logger
from module.ui.assets import WAR_ARCHIVES_CHECK
from module.ui.page import page_archives
from module.ui.scroll import Scroll
from module.ui.switch import Switch
from module.war_archives.assets import WAR_ARCHIVES_EX_ON, WAR_ARCHIVES_SP_ON, WAR_ARCHIVES_CAMPAIGN_CHECK
from module.war_archives.assets import WAR_ARCHIVES_EX_ON, WAR_ARCHIVES_SP_ON, \
WAR_ARCHIVES_CAMPAIGN_CHECK, WAR_ARCHIVES_SCROLL
from module.war_archives.dictionary import dic_archives_template
WAR_ARCHIVES_SWITCH = Switch('War_Archives_switch', is_selector=True)
WAR_ARCHIVES_SWITCH.add_status('ex', WAR_ARCHIVES_EX_ON)
WAR_ARCHIVES_SWITCH.add_status('sp', WAR_ARCHIVES_SP_ON)
WAR_ARCHIVES_SCROLL = Scroll(WAR_ARCHIVES_SCROLL, color=(247, 211, 66), name='WAR_ARCHIVES_SCROLL')
class CampaignBase(CampaignBase_):
@ -53,8 +55,6 @@ class CampaignBase(CampaignBase_):
Fixed number of scrolls until give up, may need to
increase as more war archives campaigns are added
"""
detection_area = (565, 125, 700, 675)
for _ in range(10):
if skip_first_screenshot:
skip_first_screenshot = False
@ -73,12 +73,11 @@ class CampaignBase(CampaignBase_):
if entrance is not None:
return entrance
# backup = self.config.cover(DEVICE_CONTROL_METHOD='minitouch')
p1, p2 = random_rectangle_vector(
(0, -275), box=detection_area, random_range=(-50, -50, 50, 50), padding=20)
self.device.drag(p1, p2, segments=2, shake=(0, 25), point_random=(0, 0, 0, 0), shake_random=(0, -5, 0, 5))
# backup.recover()
self.device.sleep(0.3)
if WAR_ARCHIVES_SCROLL.appear(main=self):
WAR_ARCHIVES_SCROLL.next_page(main=self)
continue
else:
break
logger.warning('Failed to find archives entrance')
return None

View File

@ -147,7 +147,8 @@ def ensure_time(second, n=3, precision=3):
"""
if isinstance(second, tuple):
multiply = 10 ** precision
return random_normal_distribution_int(second[0] * multiply, second[1] * multiply, n) / multiply
result = random_normal_distribution_int(second[0] * multiply, second[1] * multiply, n) / multiply
return round(result, precision)
elif isinstance(second, str):
if ',' in second:
lower, upper = second.replace(' ', '').split(',')
@ -163,6 +164,29 @@ def ensure_time(second, n=3, precision=3):
return second
def ensure_int(*args):
"""
Convert all elements to int.
Return the same structure as nested objects.
Args:
*args:
Returns:
list:
"""
def to_int(item):
try:
return int(item)
except TypeError:
result = [to_int(i) for i in item]
if len(result) == 1:
result = result[0]
return result
return to_int(args)
def area_offset(area, offset):
"""

View File

@ -506,5 +506,5 @@ def type_to_str(typ):
str: Such as `int`, 'datetime.datetime'.
"""
if not isinstance(typ, type):
typ = type(typ)
return str(typ).strip("<class '>").replace('<', '_').replace('>', '_')
typ = type(typ).__name__
return str(typ)

View File

@ -1,3 +1,4 @@
from module.base.button import Button
from module.base.timer import Timer
from module.base.utils import *
from module.device.method.hermit import Hermit
@ -21,6 +22,7 @@ class Control(Hermit, Uiautomator2, Minitouch):
if control_check:
self.handle_control_check(button)
x, y = random_rectangle_point(button.button)
x, y = ensure_int(x, y)
logger.info(
'Click %s @ %s' % (point2str(x, y), button)
)
@ -54,6 +56,7 @@ class Control(Hermit, Uiautomator2, Minitouch):
"""
self.handle_control_check(button)
x, y = random_rectangle_point(button.button)
x, y = ensure_int(x, y)
duration = ensure_time(duration)
logger.info(
'Click %s @ %s, %s' % (point2str(x, y), button, duration)
@ -68,10 +71,18 @@ class Control(Hermit, Uiautomator2, Minitouch):
def swipe(self, p1, p2, duration=(0.1, 0.2), name='SWIPE', distance_check=True):
self.handle_control_check(name)
p1, p2 = ensure_int(p1, p2)
duration = ensure_time(duration)
logger.info(
'Swipe %s -> %s, %s' % (point2str(*p1), point2str(*p2), duration)
)
method = self.config.Emulator_ControlMethod
if method == 'minitouch':
logger.info('Swipe %s -> %s' % (point2str(*p1), point2str(*p2)))
elif method == 'uiautomator2':
logger.info('Swipe %s -> %s, %s' % (point2str(*p1), point2str(*p2), duration))
else:
# ADB needs to be slow, or swipe doesn't work
duration *= 2.5
logger.info('Swipe %s -> %s, %s' % (point2str(*p1), point2str(*p2), duration))
if distance_check:
if np.linalg.norm(np.subtract(p1, p2)) < 10:
# Should swipe a certain distance, otherwise AL will treat it as click.
@ -79,7 +90,6 @@ class Control(Hermit, Uiautomator2, Minitouch):
logger.info('Swipe distance < 10px, dropped')
return
method = self.config.Emulator_ControlMethod
if method == 'minitouch':
self.swipe_minitouch(p1, p2)
elif method == 'uiautomator2':
@ -116,14 +126,21 @@ class Control(Hermit, Uiautomator2, Minitouch):
self.swipe(p1, p2, duration=duration, name=name, distance_check=distance_check)
def drag(self, p1, p2, segments=1, shake=(0, 15), point_random=(-10, -10, 10, 10), shake_random=(-5, -5, 5, 5),
swipe_duration=0.25, shake_duration=0.1):
swipe_duration=0.25, shake_duration=0.1, name='DRAG'):
self.handle_control_check(name)
p1, p2 = ensure_int(p1, p2)
logger.info(
'Drag %s -> %s' % (point2str(*p1), point2str(*p2))
)
method = self.config.Emulator_ControlMethod
if method == 'minitouch':
self.drag_minitouch(p1, p2, point_random=point_random)
else:
elif method == 'uiautomator2':
self.drag_uiautomator2(
p1, p2, segments=segments, shake=shake, point_random=point_random, shake_random=shake_random,
swipe_duration=swipe_duration, shake_duration=shake_duration)
else:
logger.warning(f'Control method {method} does not support drag well, '
f'falling back to ADB swipe may cause unexpected behaviour')
self.swipe_adb(p1, p2, duration=ensure_time(swipe_duration * 2))
self.click(Button(area=(), color=(), button=area_offset(point_random, p2), name=name))

View File

@ -95,8 +95,9 @@ class Adb(Connection):
self.adb_shell(['input', 'tap', x, y])
@retry
def swipe_adb(self, fx, fy, tx, ty, duration=0.1):
self.adb_shell(['input', 'swipe', fx, fy, tx, ty, duration])
def swipe_adb(self, p1, p2, duration=0.1):
duration = int(duration * 1000)
self.adb_shell(['input', 'swipe', *p1, *p2, duration])
@retry
def app_current_adb(self):

View File

@ -91,7 +91,7 @@ class RewardDorm(UI):
self.device.minitouch_builder.up().commit()
self.device.minitouch_send()
@Config.when(DEVICE_CONTROL_METHOD=None)
@Config.when(DEVICE_CONTROL_METHOD='uiautomator2')
def _dorm_feed_long_tap(self, button, count):
timeout = Timer(count // 5 + 5).start()
x, y = random_rectangle_point(button.button)
@ -112,7 +112,13 @@ class RewardDorm(UI):
self.device.u2.touch.up(x, y)
def dorm_receive(self):
@Config.when(DEVICE_CONTROL_METHOD=None)
def _dorm_feed_long_tap(self, button, count):
logger.warning(f'Current control method {self.config.Emulator_ControlMethod} '
f'does not support DOWN/UP events, use multi-click instead')
self.device.multi_click(button, count)
def dorm_collect(self):
"""
Click all coins and loves on current screen.
Zoom-out dorm to detect coins and loves, because swipes in dorm may treat as dragging ships.
@ -122,6 +128,12 @@ class RewardDorm(UI):
in: page_dorm, without info_bar
out: page_dorm, without info_bar
"""
logger.hr('Dorm collect')
if self.config.Emulator_ControlMethod not in ['uiautomator2', 'minitouch']:
logger.warning(f'Current control method {self.config.Emulator_ControlMethod} '
f'does not support 2 finger zoom out, skip dorm collect')
return
for _ in range(2):
logger.info('Dorm zoom out')
# Left hand down
@ -282,7 +294,7 @@ class RewardDorm(UI):
self.ui_goto(page_dorm, skip_first_screenshot=True)
if collect:
self.dorm_receive()
self.dorm_collect()
if feed:
self.ui_click(click_button=DORM_FEED_ENTER, appear_button=DORM_CHECK, check_button=DORM_FEED_CHECK,

View File

@ -1,7 +1,6 @@
from module.base.button import ButtonGrid
from module.base.decorator import cached_property
from module.base.timer import Timer
from module.base.utils import *
from module.shop.assets import *
from module.ui.assets import BACK_ARROW
from module.ui.navbar import Navbar
@ -117,11 +116,7 @@ class ShopUI(UI):
self.appear(SHOP_GENERAL_SWIPE_END, offset=(15, 5)):
return True
# backup = self.config.cover(DEVICE_CONTROL_METHOD='minitouch')
p1, p2 = random_rectangle_vector(
(480, 0), box=detection_area, random_range=(-50, -50, 50, 50), padding=20)
self.device.drag(p1, p2, segments=2, shake=(0, 25), point_random=(0, 0, 0, 0), shake_random=(0, -5, 0, 5))
# backup.recover()
self.device.swipe_vector((480, 0), box=detection_area, random_range=(-50, -10, 50, 10), padding=0)
self.device.sleep(0.3)
return False
@ -142,3 +137,7 @@ class ShopUI(UI):
self.ui_ensure(page_munitions)
return self._shop_swipe()
if __name__ == '__main__':
self = ShopUI('alas')
self.device.screenshot()
self._shop_swipe()

View File

@ -136,7 +136,7 @@ class Scroll:
if self.drag_interval.reached():
p1 = random_rectangle_point(self.position_to_screen(current), n=1)
p2 = random_rectangle_point(self.position_to_screen(position, random_range=random_range), n=1)
main.device.drag(p1, p2, shake=(0, 0), point_random=(0, 0, 0, 0), shake_random=(0, 0, 0, 0))
main.device.swipe(p1, p2)
main.device.sleep(0.3)
self.drag_interval.reset()
@ -162,7 +162,7 @@ class Scroll:
multiply = self.length / (self.total - self.length)
target = current + page * multiply
target = min(max(target, 0), 1)
target = round(min(max(target, 0), 1), 3)
self.set(target, main=main, random_range=random_range, skip_first_screenshot=True)
def next_page(self, main, random_range=(-0.01, 0.01), skip_first_screenshot=True):

View File

@ -18,5 +18,6 @@ TEMPLATE_WINTERS_CROWN = Template(file={'cn': './assets/cn/war_archives/TEMPLATE
WAR_ARCHIVES_CAMPAIGN_CHECK = Button(area={'cn': (1150, 101, 1166, 130), 'en': (1150, 101, 1166, 130), 'jp': (1150, 101, 1166, 130), 'tw': (1150, 101, 1166, 130)}, color={'cn': (134, 175, 207), 'en': (134, 175, 207), 'jp': (134, 175, 207), 'tw': (134, 175, 207)}, button={'cn': (1150, 101, 1166, 130), 'en': (1150, 101, 1166, 130), 'jp': (1150, 101, 1166, 130), 'tw': (1150, 101, 1166, 130)}, file={'cn': './assets/cn/war_archives/WAR_ARCHIVES_CAMPAIGN_CHECK.png', 'en': './assets/en/war_archives/WAR_ARCHIVES_CAMPAIGN_CHECK.png', 'jp': './assets/jp/war_archives/WAR_ARCHIVES_CAMPAIGN_CHECK.png', 'tw': './assets/tw/war_archives/WAR_ARCHIVES_CAMPAIGN_CHECK.png'})
WAR_ARCHIVES_EX_OFF = Button(area={'cn': (908, 42, 991, 72), 'en': (908, 42, 991, 72), 'jp': (908, 42, 991, 72), 'tw': (908, 42, 991, 72)}, color={'cn': (40, 42, 56), 'en': (40, 42, 56), 'jp': (40, 42, 56), 'tw': (40, 42, 56)}, button={'cn': (908, 42, 991, 72), 'en': (908, 42, 991, 72), 'jp': (908, 42, 991, 72), 'tw': (908, 42, 991, 72)}, file={'cn': './assets/cn/war_archives/WAR_ARCHIVES_EX_OFF.png', 'en': './assets/en/war_archives/WAR_ARCHIVES_EX_OFF.png', 'jp': './assets/jp/war_archives/WAR_ARCHIVES_EX_OFF.png', 'tw': './assets/tw/war_archives/WAR_ARCHIVES_EX_OFF.png'})
WAR_ARCHIVES_EX_ON = Button(area={'cn': (903, 42, 994, 72), 'en': (903, 42, 994, 72), 'jp': (903, 42, 994, 72), 'tw': (903, 42, 994, 72)}, color={'cn': (75, 93, 151), 'en': (75, 93, 151), 'jp': (75, 93, 151), 'tw': (75, 93, 151)}, button={'cn': (903, 42, 994, 72), 'en': (903, 42, 994, 72), 'jp': (903, 42, 994, 72), 'tw': (903, 42, 994, 72)}, file={'cn': './assets/cn/war_archives/WAR_ARCHIVES_EX_ON.png', 'en': './assets/en/war_archives/WAR_ARCHIVES_EX_ON.png', 'jp': './assets/jp/war_archives/WAR_ARCHIVES_EX_ON.png', 'tw': './assets/tw/war_archives/WAR_ARCHIVES_EX_ON.png'})
WAR_ARCHIVES_SCROLL = Button(area={'cn': (1253, 130, 1260, 695), 'en': (1253, 130, 1260, 695), 'jp': (1253, 130, 1260, 695), 'tw': (1253, 130, 1260, 695)}, color={'cn': (142, 131, 75), 'en': (142, 131, 75), 'jp': (142, 131, 75), 'tw': (142, 131, 75)}, button={'cn': (1253, 130, 1260, 695), 'en': (1253, 130, 1260, 695), 'jp': (1253, 130, 1260, 695), 'tw': (1253, 130, 1260, 695)}, file={'cn': './assets/cn/war_archives/WAR_ARCHIVES_SCROLL.png', 'en': './assets/en/war_archives/WAR_ARCHIVES_SCROLL.png', 'jp': './assets/jp/war_archives/WAR_ARCHIVES_SCROLL.png', 'tw': './assets/tw/war_archives/WAR_ARCHIVES_SCROLL.png'})
WAR_ARCHIVES_SP_OFF = Button(area={'cn': (1012, 43, 1095, 71), 'en': (1012, 43, 1095, 71), 'jp': (1012, 43, 1095, 71), 'tw': (1012, 43, 1095, 71)}, color={'cn': (40, 42, 56), 'en': (40, 42, 56), 'jp': (40, 42, 56), 'tw': (40, 42, 56)}, button={'cn': (1012, 43, 1095, 71), 'en': (1012, 43, 1095, 71), 'jp': (1012, 43, 1095, 71), 'tw': (1012, 43, 1095, 71)}, file={'cn': './assets/cn/war_archives/WAR_ARCHIVES_SP_OFF.png', 'en': './assets/en/war_archives/WAR_ARCHIVES_SP_OFF.png', 'jp': './assets/jp/war_archives/WAR_ARCHIVES_SP_OFF.png', 'tw': './assets/tw/war_archives/WAR_ARCHIVES_SP_OFF.png'})
WAR_ARCHIVES_SP_ON = Button(area={'cn': (1010, 43, 1095, 71), 'en': (1010, 43, 1095, 71), 'jp': (1010, 43, 1095, 71), 'tw': (1010, 43, 1095, 71)}, color={'cn': (77, 95, 152), 'en': (77, 95, 152), 'jp': (77, 95, 152), 'tw': (77, 95, 152)}, button={'cn': (1010, 43, 1095, 71), 'en': (1010, 43, 1095, 71), 'jp': (1010, 43, 1095, 71), 'tw': (1010, 43, 1095, 71)}, file={'cn': './assets/cn/war_archives/WAR_ARCHIVES_SP_ON.png', 'en': './assets/en/war_archives/WAR_ARCHIVES_SP_ON.png', 'jp': './assets/jp/war_archives/WAR_ARCHIVES_SP_ON.png', 'tw': './assets/tw/war_archives/WAR_ARCHIVES_SP_ON.png'})