mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-16 06:25:24 +00:00
Fix: Retry when joystick contact lost
This commit is contained in:
parent
d314bab51c
commit
a800bdb214
@ -152,20 +152,21 @@ class ModuleBase:
|
||||
prev_image = image
|
||||
timer.reset()
|
||||
|
||||
def image_crop(self, button):
|
||||
def image_crop(self, button, copy=True):
|
||||
"""Extract the area from image.
|
||||
|
||||
Args:
|
||||
button(Button, tuple): Button instance or area tuple.
|
||||
copy:
|
||||
"""
|
||||
if isinstance(button, Button):
|
||||
return crop(self.device.image, button.area)
|
||||
return crop(self.device.image, button.area, copy=copy)
|
||||
elif isinstance(button, ButtonWrapper):
|
||||
return crop(self.device.image, button.area)
|
||||
return crop(self.device.image, button.area, copy=copy)
|
||||
elif hasattr(button, 'area'):
|
||||
return crop(self.device.image, button.area)
|
||||
return crop(self.device.image, button.area, copy=copy)
|
||||
else:
|
||||
return crop(self.device.image, button)
|
||||
return crop(self.device.image, button, copy=copy)
|
||||
|
||||
def image_color_count(self, button, color, threshold=221, count=50):
|
||||
"""
|
||||
@ -178,9 +179,14 @@ class ModuleBase:
|
||||
Returns:
|
||||
bool:
|
||||
"""
|
||||
image = self.image_crop(button)
|
||||
mask = color_similarity_2d(image, color=color) > threshold
|
||||
return np.sum(mask) > count
|
||||
if isinstance(button, np.ndarray):
|
||||
image = button
|
||||
else:
|
||||
image = self.image_crop(button, copy=False)
|
||||
mask = color_similarity_2d(image, color=color)
|
||||
cv2.inRange(mask, threshold, 255, dst=mask)
|
||||
sum_ = cv2.countNonZero(mask)
|
||||
return sum_ > count
|
||||
|
||||
def image_color_button(self, area, color, color_threshold=250, encourage=5, name='COLOR_BUTTON'):
|
||||
"""
|
||||
|
@ -106,7 +106,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
|
||||
continue
|
||||
if self.appear(COMBAT_TEAM_PREPARE):
|
||||
self.interval_reset(COMBAT_PREPARE)
|
||||
self._map_A_timer.reset()
|
||||
self.map_A_timer.reset()
|
||||
if self.appear(COMBAT_PREPARE, interval=2):
|
||||
if not self.handle_combat_prepare():
|
||||
return False
|
||||
|
@ -248,7 +248,7 @@ class Dungeon(DungeonUI, DungeonEvent, Combat):
|
||||
area = area_offset((-50, -150, 0, 0), offset=self.config.ASSETS_RESOLUTION)
|
||||
|
||||
skip_first_screenshot = True
|
||||
self._map_A_timer.reset()
|
||||
self.map_A_timer.reset()
|
||||
handled = False
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
@ -265,7 +265,7 @@ class Dungeon(DungeonUI, DungeonEvent, Combat):
|
||||
logger.info(f'No destructible object')
|
||||
if not handled:
|
||||
break
|
||||
if self._map_A_timer.reached():
|
||||
if self.map_A_timer.reached():
|
||||
break
|
||||
|
||||
return handled
|
||||
|
@ -130,7 +130,7 @@ class MapControl(MapControlJoystick):
|
||||
if allow_straight_run and diff < 15:
|
||||
logger.info(f'Approaching target, diff={round(diff, 1)}, disallow straight_run')
|
||||
direction_interval = Timer(0.2)
|
||||
self._map_2x_run_timer.reset()
|
||||
self.map_2x_run_timer.reset()
|
||||
allow_straight_run = False
|
||||
if allow_run and diff < 7:
|
||||
logger.info(f'Approaching target, diff={round(diff, 1)}, disallow run')
|
||||
@ -244,7 +244,7 @@ class MapControl(MapControlJoystick):
|
||||
if __name__ == '__main__':
|
||||
# Control test in Himeko trail
|
||||
# Must manually enter Himeko trail first and dismiss popup
|
||||
self = MapControl('alas')
|
||||
self = MapControl('src')
|
||||
self.minimap.set_plane('Jarilo_BackwaterPass', floor='F1')
|
||||
self.device.screenshot()
|
||||
self.minimap.init_position((519, 359))
|
||||
|
@ -1,6 +1,9 @@
|
||||
import math
|
||||
from functools import cached_property
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.device.method.maatouch import MaatouchBuilder
|
||||
from module.device.method.minitouch import CommandBuilder, insert_swipe, random_normal_distribution
|
||||
@ -36,10 +39,8 @@ class JoystickContact:
|
||||
Can not lift finger when:
|
||||
- Process is force terminated
|
||||
"""
|
||||
builder = self.builder
|
||||
if self.is_downed:
|
||||
builder.up().commit()
|
||||
builder.send()
|
||||
self.up()
|
||||
logger.info('JoystickContact ends')
|
||||
else:
|
||||
logger.info('JoystickContact ends but it was never downed')
|
||||
@ -98,6 +99,13 @@ class JoystickContact:
|
||||
point = (int(round(point[0])), int(round(point[1])))
|
||||
return point
|
||||
|
||||
def up(self):
|
||||
builder = self.builder
|
||||
if self.is_downed:
|
||||
builder.up().commit()
|
||||
builder.send()
|
||||
self.prev_point = None
|
||||
|
||||
def set(self, direction, run=True):
|
||||
"""
|
||||
Set joystick to given position
|
||||
@ -110,6 +118,13 @@ class JoystickContact:
|
||||
point = JoystickContact.direction2screen(direction, run=run)
|
||||
builder = self.builder
|
||||
|
||||
if self.is_downed and not self.main.joystick_speed():
|
||||
if self.main.joystick_lost_timer.reached():
|
||||
logger.warning(f'Joystick contact lost: {self.main.joystick_lost_timer}, re-down')
|
||||
self.up()
|
||||
else:
|
||||
self.main.joystick_lost_timer.reset()
|
||||
|
||||
if self.is_downed:
|
||||
points = insert_swipe(p0=self.prev_point, p3=point, speed=20)
|
||||
for point in points[1:]:
|
||||
@ -121,20 +136,56 @@ class JoystickContact:
|
||||
# Character starts moving, RUN button is still unavailable in a short time.
|
||||
# Assume available in 0.3s
|
||||
# We still have reties if 0.3s is incorrect.
|
||||
self.main._map_2x_run_timer.set_current(0.7)
|
||||
self.main.map_2x_run_timer.set_current(0.7)
|
||||
self.main.joystick_lost_timer.reset()
|
||||
|
||||
self.prev_point = point
|
||||
|
||||
|
||||
class MapControlJoystick(UI):
|
||||
_map_A_timer = Timer(1)
|
||||
_map_E_timer = Timer(1)
|
||||
_map_2x_run_timer = Timer(1)
|
||||
map_A_timer = Timer(1)
|
||||
map_E_timer = Timer(1)
|
||||
map_2x_run_timer = Timer(1)
|
||||
|
||||
joystick_lost_timer = Timer(1, count=2)
|
||||
|
||||
@cached_property
|
||||
def joystick_center(self) -> tuple[float, float]:
|
||||
def joystick_center(self) -> tuple[int, int]:
|
||||
x1, y1, x2, y2 = JOYSTICK.area
|
||||
return (x1 + x2) / 2, (y1 + y2) / 2
|
||||
return int((x1 + x2) // 2), int((y1 + y2) // 2)
|
||||
|
||||
@cached_property
|
||||
def DirectionRemapData(self):
|
||||
d = JoystickContact.RADIUS_RUN[1] * 2
|
||||
mx = np.zeros((d, d), dtype=np.float32)
|
||||
my = np.zeros((d, d), dtype=np.float32)
|
||||
for i in range(d):
|
||||
for j in range(d):
|
||||
mx[i, j] = d / 2 + i / 2 * np.cos(2 * np.pi * j / d)
|
||||
my[i, j] = d / 2 + i / 2 * np.sin(2 * np.pi * j / d)
|
||||
return mx, my
|
||||
|
||||
def joystick_speed(self) -> str:
|
||||
"""
|
||||
Returns:
|
||||
str: 'run', 'walk', ''
|
||||
"""
|
||||
# About 1.5ms
|
||||
x, y = self.joystick_center
|
||||
radius = JoystickContact.RADIUS_RUN[1]
|
||||
image = self.image_crop((x - radius, y - radius, x + radius, y + radius), copy=False)
|
||||
image = cv2.remap(image, *self.DirectionRemapData, cv2.INTER_CUBIC)
|
||||
|
||||
# 190~205
|
||||
run = image[185:210, :]
|
||||
if self.image_color_count(run, color=(223, 199, 145), threshold=221, count=100):
|
||||
return 'run'
|
||||
# 90~100
|
||||
walk = image[85:105, :]
|
||||
if self.image_color_count(walk, color=(235, 235, 235), threshold=221, count=50):
|
||||
return 'walk'
|
||||
|
||||
return ''
|
||||
|
||||
def map_get_technique_points(self):
|
||||
"""
|
||||
@ -162,9 +213,9 @@ class MapControlJoystick(UI):
|
||||
Returns:
|
||||
bool: If clicked.
|
||||
"""
|
||||
if self._map_A_timer.reached():
|
||||
if self.map_A_timer.reached():
|
||||
self.device.click(A_BUTTON)
|
||||
self._map_A_timer.reset()
|
||||
self.map_A_timer.reset()
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -177,9 +228,9 @@ class MapControlJoystick(UI):
|
||||
Returns:
|
||||
bool: If clicked.
|
||||
"""
|
||||
if self._map_E_timer.reached():
|
||||
if self.map_E_timer.reached():
|
||||
self.device.click(E_BUTTON)
|
||||
self._map_E_timer.reset()
|
||||
self.map_E_timer.reset()
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -194,13 +245,13 @@ class MapControlJoystick(UI):
|
||||
"""
|
||||
is_running = self.image_color_count(RUN_BUTTON, color=(208, 183, 138), threshold=221, count=100)
|
||||
|
||||
if run and not is_running and self._map_2x_run_timer.reached():
|
||||
if run and not is_running and self.map_2x_run_timer.reached():
|
||||
self.device.click(RUN_BUTTON)
|
||||
self._map_2x_run_timer.reset()
|
||||
self.map_2x_run_timer.reset()
|
||||
return True
|
||||
if not run and is_running and self._map_2x_run_timer.reached():
|
||||
if not run and is_running and self.map_2x_run_timer.reached():
|
||||
self.device.click(RUN_BUTTON)
|
||||
self._map_2x_run_timer.reset()
|
||||
self.map_2x_run_timer.reset()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
Loading…
Reference in New Issue
Block a user