2023-05-16 18:54:03 +00:00
|
|
|
from module.base.button import ClickButton
|
2023-05-14 07:48:34 +00:00
|
|
|
from module.base.decorator import cached_property
|
|
|
|
from module.base.timer import Timer
|
|
|
|
from module.base.utils import *
|
|
|
|
from module.device.method.hermit import Hermit
|
|
|
|
from module.device.method.maatouch import MaaTouch
|
|
|
|
from module.device.method.minitouch import Minitouch
|
|
|
|
from module.device.method.scrcpy import Scrcpy
|
|
|
|
from module.logger import logger
|
|
|
|
|
|
|
|
|
|
|
|
class Control(Hermit, Minitouch, Scrcpy, MaaTouch):
|
|
|
|
def handle_control_check(self, button):
|
|
|
|
# Will be overridden in Device
|
|
|
|
pass
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def click_methods(self):
|
|
|
|
return {
|
|
|
|
'ADB': self.click_adb,
|
|
|
|
'uiautomator2': self.click_uiautomator2,
|
|
|
|
'minitouch': self.click_minitouch,
|
|
|
|
'Hermit': self.click_hermit,
|
|
|
|
'MaaTouch': self.click_maatouch,
|
|
|
|
}
|
|
|
|
|
|
|
|
def click(self, button, control_check=True):
|
|
|
|
"""Method to click a button.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
button (button.Button): AzurLane Button instance.
|
|
|
|
control_check (bool):
|
|
|
|
"""
|
|
|
|
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)
|
|
|
|
)
|
|
|
|
method = self.click_methods.get(
|
|
|
|
self.config.Emulator_ControlMethod,
|
|
|
|
self.click_adb
|
|
|
|
)
|
|
|
|
method(x, y)
|
|
|
|
|
|
|
|
def multi_click(self, button, n, interval=(0.1, 0.2)):
|
|
|
|
self.handle_control_check(button)
|
|
|
|
click_timer = Timer(0.1)
|
|
|
|
for _ in range(n):
|
|
|
|
remain = ensure_time(interval) - click_timer.current()
|
|
|
|
if remain > 0:
|
|
|
|
self.sleep(remain)
|
|
|
|
click_timer.reset()
|
|
|
|
|
|
|
|
self.click(button, control_check=False)
|
|
|
|
|
|
|
|
def long_click(self, button, duration=(1, 1.2)):
|
|
|
|
"""Method to long click a button.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
button (button.Button): AzurLane Button instance.
|
|
|
|
duration(int, float, tuple):
|
|
|
|
"""
|
|
|
|
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)
|
|
|
|
)
|
|
|
|
method = self.config.Emulator_ControlMethod
|
|
|
|
if method == 'minitouch':
|
|
|
|
self.long_click_minitouch(x, y, duration)
|
|
|
|
elif method == 'uiautomator2':
|
|
|
|
self.long_click_uiautomator2(x, y, duration)
|
|
|
|
elif method == 'scrcpy':
|
|
|
|
self.long_click_scrcpy(x, y, duration)
|
|
|
|
elif method == 'MaaTouch':
|
|
|
|
self.long_click_maatouch(x, y, duration)
|
|
|
|
else:
|
|
|
|
self.swipe_adb((x, y), (x, y), duration)
|
|
|
|
|
|
|
|
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)
|
|
|
|
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))
|
|
|
|
elif method == 'scrcpy':
|
|
|
|
logger.info('Swipe %s -> %s' % (point2str(*p1), point2str(*p2)))
|
|
|
|
elif method == 'MaaTouch':
|
|
|
|
logger.info('Swipe %s -> %s' % (point2str(*p1), point2str(*p2)))
|
|
|
|
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.
|
|
|
|
# uiautomator2 should >= 6px, minitouch should >= 5px
|
|
|
|
logger.info('Swipe distance < 10px, dropped')
|
|
|
|
return
|
|
|
|
|
|
|
|
if method == 'minitouch':
|
|
|
|
self.swipe_minitouch(p1, p2)
|
|
|
|
elif method == 'uiautomator2':
|
|
|
|
self.swipe_uiautomator2(p1, p2, duration=duration)
|
|
|
|
elif method == 'scrcpy':
|
|
|
|
self.swipe_scrcpy(p1, p2)
|
|
|
|
elif method == 'MaaTouch':
|
|
|
|
self.swipe_maatouch(p1, p2)
|
|
|
|
else:
|
|
|
|
self.swipe_adb(p1, p2, duration=duration)
|
|
|
|
|
|
|
|
def swipe_vector(self, vector, box=(123, 159, 1175, 628), random_range=(0, 0, 0, 0), padding=15,
|
|
|
|
duration=(0.1, 0.2), whitelist_area=None, blacklist_area=None, name='SWIPE', distance_check=True):
|
|
|
|
"""Method to swipe.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
box (tuple): Swipe in box (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y).
|
|
|
|
vector (tuple): (x, y).
|
|
|
|
random_range (tuple): (x_min, y_min, x_max, y_max).
|
|
|
|
padding (int):
|
|
|
|
duration (int, float, tuple):
|
|
|
|
whitelist_area: (list[tuple[int]]):
|
|
|
|
A list of area that safe to click. Swipe path will end there.
|
|
|
|
blacklist_area: (list[tuple[int]]):
|
|
|
|
If none of the whitelist_area satisfies current vector, blacklist_area will be used.
|
|
|
|
Delete random path that ends in any blacklist_area.
|
|
|
|
name (str): Swipe name
|
|
|
|
distance_check: (bool):
|
|
|
|
"""
|
|
|
|
p1, p2 = random_rectangle_vector_opted(
|
|
|
|
vector,
|
|
|
|
box=box,
|
|
|
|
random_range=random_range,
|
|
|
|
padding=padding,
|
|
|
|
whitelist_area=whitelist_area,
|
|
|
|
blacklist_area=blacklist_area
|
|
|
|
)
|
|
|
|
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, 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)
|
|
|
|
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)
|
|
|
|
elif method == 'scrcpy':
|
|
|
|
self.drag_scrcpy(p1, p2, point_random=point_random)
|
|
|
|
elif method == 'MaaTouch':
|
|
|
|
self.drag_maatouch(p1, p2, point_random=point_random)
|
|
|
|
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))
|
2023-10-04 03:04:51 +00:00
|
|
|
self.click(ClickButton(area=area_offset(point_random, p2), name=name))
|