mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-16 06:25:24 +00:00
Refactor: Auto-switch between domain exit implements
This commit is contained in:
parent
0bf4b45c8c
commit
2591a3aee0
@ -121,6 +121,12 @@ class ManualConfig:
|
|||||||
OS_ACTION_POINT_PRESERVE = 0
|
OS_ACTION_POINT_PRESERVE = 0
|
||||||
OS_CL1_YELLOW_COINS_PRESERVE = 100000
|
OS_CL1_YELLOW_COINS_PRESERVE = 100000
|
||||||
|
|
||||||
|
"""
|
||||||
|
tasks.rogue
|
||||||
|
"""
|
||||||
|
# 2023.11.13 Migrate domain exit implementation, True to stop before domain exit
|
||||||
|
DOMAIN_EXIT_MIGRATE_DEV = False
|
||||||
|
|
||||||
|
|
||||||
ADDING = ''.join([chr(int(f)) for f in ManualConfig.OS_EXPLORE_CENTER.split('>')])
|
ADDING = ''.join([chr(int(f)) for f in ManualConfig.OS_EXPLORE_CENTER.split('>')])
|
||||||
|
|
||||||
|
@ -51,6 +51,9 @@ class Waypoint:
|
|||||||
|
|
||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
|
def __bool__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def run_2x(self) -> "Waypoint":
|
def run_2x(self) -> "Waypoint":
|
||||||
"""
|
"""
|
||||||
Product a Waypoint object with overridden "speed",
|
Product a Waypoint object with overridden "speed",
|
||||||
|
@ -267,6 +267,7 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward):
|
|||||||
logger.hr('Domain single exit', level=1)
|
logger.hr('Domain single exit', level=1)
|
||||||
waypoints = ensure_waypoints(waypoints)
|
waypoints = ensure_waypoints(waypoints)
|
||||||
end_point = waypoints[-1]
|
end_point = waypoints[-1]
|
||||||
|
end_point.min_speed = 'run'
|
||||||
end_point.interact_radius = 5
|
end_point.interact_radius = 5
|
||||||
end_point.expected_end.append(self._domain_exit_expected_end)
|
end_point.expected_end.append(self._domain_exit_expected_end)
|
||||||
|
|
||||||
@ -274,6 +275,32 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward):
|
|||||||
self._domain_exit_wait_next()
|
self._domain_exit_wait_next()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _domain_exit_old(self):
|
||||||
|
"""
|
||||||
|
An old implementation that go along specific direction without retries
|
||||||
|
"""
|
||||||
|
logger.info(f'Using old predict_door()')
|
||||||
|
direction = self.predict_door_old()
|
||||||
|
direction_limit = 55
|
||||||
|
if direction is not None:
|
||||||
|
if abs(direction) > direction_limit:
|
||||||
|
logger.warning(f'Unexpected direction to go: {direction}, limited in {direction_limit}')
|
||||||
|
if direction > 0:
|
||||||
|
direction = direction_limit
|
||||||
|
elif direction < 0:
|
||||||
|
direction = -direction_limit
|
||||||
|
|
||||||
|
point = Waypoint(
|
||||||
|
position=(0, 0),
|
||||||
|
min_speed='run',
|
||||||
|
lock_direction=direction,
|
||||||
|
interact_radius=10000,
|
||||||
|
expected_end=[self._domain_exit_expected_end],
|
||||||
|
)
|
||||||
|
self.goto(point)
|
||||||
|
self._domain_exit_wait_next()
|
||||||
|
return True
|
||||||
|
|
||||||
def domain_exit(
|
def domain_exit(
|
||||||
self,
|
self,
|
||||||
*waypoints,
|
*waypoints,
|
||||||
@ -281,22 +308,36 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward):
|
|||||||
left_door: Waypoint = None,
|
left_door: Waypoint = None,
|
||||||
right_door: Waypoint = None
|
right_door: Waypoint = None
|
||||||
):
|
):
|
||||||
|
"""
|
||||||
|
Goto domain exit, choose one door, goto door
|
||||||
|
"""
|
||||||
logger.hr('Domain exit', level=1)
|
logger.hr('Domain exit', level=1)
|
||||||
|
# Goto the front of the two doors
|
||||||
waypoints = ensure_waypoints(waypoints)
|
waypoints = ensure_waypoints(waypoints)
|
||||||
end_point = waypoints[-1]
|
end_point = waypoints[-1]
|
||||||
end_point.endpoint_threshold = 1.5
|
end_point.endpoint_threshold = 1.5
|
||||||
self.goto(*waypoints)
|
self.goto(*waypoints)
|
||||||
|
|
||||||
|
# Rotate camera to insight two doors
|
||||||
logger.hr('End rotation', level=2)
|
logger.hr('End rotation', level=2)
|
||||||
self.rotation_set(end_rotation, threshold=10)
|
self.rotation_set(end_rotation, threshold=10)
|
||||||
|
|
||||||
|
# Choose a door
|
||||||
logger.hr('Find domain exit', level=2)
|
logger.hr('Find domain exit', level=2)
|
||||||
|
logger.info(f'Migrate={self.config.DOMAIN_EXIT_MIGRATE_DEV}, left_door={left_door}, right_door={right_door}')
|
||||||
|
if not self.config.DOMAIN_EXIT_MIGRATE_DEV and (not left_door and not right_door):
|
||||||
|
return self._domain_exit_old()
|
||||||
|
|
||||||
|
logger.info(f'Using new predict_door()')
|
||||||
door = self.predict_door()
|
door = self.predict_door()
|
||||||
if left_door is None or right_door is None:
|
if self.config.DOMAIN_EXIT_MIGRATE_DEV and self.exit_has_double_door and (not left_door or not right_door):
|
||||||
logger.critical(f'Domain exit is not defined in: {self.route_func}')
|
logger.critical(f'Domain exit is not defined in: {self.route_func}')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
# Goto door
|
||||||
if door == 'left_door':
|
if door == 'left_door':
|
||||||
|
if not left_door:
|
||||||
|
return self._domain_exit_old()
|
||||||
if self.domain_single_exit(left_door):
|
if self.domain_single_exit(left_door):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@ -306,6 +347,8 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
elif door == 'right_door':
|
elif door == 'right_door':
|
||||||
|
if not right_door:
|
||||||
|
return self._domain_exit_old()
|
||||||
if self.domain_single_exit(right_door):
|
if self.domain_single_exit(right_door):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@ -316,6 +359,10 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward):
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
logger.error('Cannot goto either exit doors, try both')
|
logger.error('Cannot goto either exit doors, try both')
|
||||||
|
if not left_door:
|
||||||
|
return self._domain_exit_old()
|
||||||
|
if not right_door:
|
||||||
|
return self._domain_exit_old()
|
||||||
if self.domain_single_exit(left_door):
|
if self.domain_single_exit(left_door):
|
||||||
return True
|
return True
|
||||||
elif self.domain_single_exit(right_door):
|
elif self.domain_single_exit(right_door):
|
||||||
|
@ -139,6 +139,83 @@ class RogueExit(CombatInteract):
|
|||||||
logger.info(f'PlanarDoor: {planar_door}, direction: {direction}')
|
logger.info(f'PlanarDoor: {planar_door}, direction: {direction}')
|
||||||
return direction
|
return direction
|
||||||
|
|
||||||
|
def predict_door_by_name_old(self, image) -> float | None:
|
||||||
|
# Paint current name black
|
||||||
|
x1, y1, x2, y2 = OCR_MAP_NAME.area
|
||||||
|
image[y1:y2, x1:x2] = (0, 0, 0)
|
||||||
|
|
||||||
|
ocr = OcrDomainExit(OCR_DOMAIN_EXIT)
|
||||||
|
results = ocr.matched_ocr(image, keyword_classes=MapPlane)
|
||||||
|
centers = [area_center(result.area) for result in results]
|
||||||
|
logger.info(f'DomainDoor: {centers}')
|
||||||
|
directions = [self.screen2direction(center) for center in centers]
|
||||||
|
|
||||||
|
count = len(centers)
|
||||||
|
if count == 0:
|
||||||
|
logger.warning('No domain exit found')
|
||||||
|
return None
|
||||||
|
if count == 1:
|
||||||
|
logger.info(f'Goto next domain: {results[0]}')
|
||||||
|
return directions[0]
|
||||||
|
|
||||||
|
# Doors >= 2
|
||||||
|
for expect in [
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainBoss,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainElite,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainRespite,
|
||||||
|
]:
|
||||||
|
for domain, direction in zip(results, directions):
|
||||||
|
if domain == expect:
|
||||||
|
logger.warning('Found multiple doors but has unique domain in it')
|
||||||
|
logger.info(f'Goto next domain: {domain}')
|
||||||
|
return direction
|
||||||
|
|
||||||
|
logger.attr('DomainStrategy', self.config.RogueWorld_DomainStrategy)
|
||||||
|
if self.config.RogueWorld_DomainStrategy == 'occurrence':
|
||||||
|
for expect in [
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainTransaction,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainOccurrence,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainEncounter,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainCombat,
|
||||||
|
]:
|
||||||
|
for domain, direction in zip(results, directions):
|
||||||
|
if domain == expect:
|
||||||
|
logger.info(f'Goto next domain: {domain}')
|
||||||
|
return direction
|
||||||
|
elif self.config.RogueWorld_DomainStrategy == 'combat':
|
||||||
|
for expect in [
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainCombat,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainEncounter,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainOccurrence,
|
||||||
|
KEYWORDS_MAP_PLANE.Rogue_DomainTransaction,
|
||||||
|
]:
|
||||||
|
for domain, direction in zip(results, directions):
|
||||||
|
if domain == expect:
|
||||||
|
logger.info(f'Goto next domain: {domain}')
|
||||||
|
return direction
|
||||||
|
else:
|
||||||
|
logger.error(f'Unknown domain strategy: {self.config.RogueWorld_DomainStrategy}')
|
||||||
|
|
||||||
|
logger.error('No domain was selected, return the first instead')
|
||||||
|
logger.info(f'Goto next domain: {results[0]}')
|
||||||
|
return directions[0]
|
||||||
|
|
||||||
|
def predict_door_old(self, skip_first_screenshot=True) -> float | None:
|
||||||
|
timeout = Timer(3, count=6).start()
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if timeout.reached():
|
||||||
|
logger.error('Predict door timeout')
|
||||||
|
return None
|
||||||
|
|
||||||
|
direction = self.predict_door_by_name_old(self.device.image)
|
||||||
|
if direction is not None:
|
||||||
|
return direction
|
||||||
|
|
||||||
def predict_door_by_name(self, image) -> tuple[MapPlane | None, MapPlane | None]:
|
def predict_door_by_name(self, image) -> tuple[MapPlane | None, MapPlane | None]:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
@ -223,16 +300,18 @@ class RogueExit(CombatInteract):
|
|||||||
logger.error(f'Unknown domain strategy: {self.config.RogueWorld_DomainStrategy}')
|
logger.error(f'Unknown domain strategy: {self.config.RogueWorld_DomainStrategy}')
|
||||||
|
|
||||||
logger.error('No domain was selected, return the first instead')
|
logger.error('No domain was selected, return the first instead')
|
||||||
if left_door is not None:
|
if left_door:
|
||||||
logger.info(f'Goto next domain: left_door={left_door}')
|
logger.info(f'Goto next domain: left_door={left_door}')
|
||||||
return 'left_door'
|
return 'left_door'
|
||||||
elif right_door is not None:
|
elif right_door:
|
||||||
logger.info(f'Goto next domain: right_door={right_door}')
|
logger.info(f'Goto next domain: right_door={right_door}')
|
||||||
return 'right_door'
|
return 'right_door'
|
||||||
else:
|
else:
|
||||||
logger.error(f'No domain door')
|
logger.error(f'No domain door')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
exit_has_double_door = False
|
||||||
|
|
||||||
def predict_door(self, skip_first_screenshot=True) -> str | None:
|
def predict_door(self, skip_first_screenshot=True) -> str | None:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
@ -242,19 +321,25 @@ class RogueExit(CombatInteract):
|
|||||||
str: 'left_door' or 'right_door' or None
|
str: 'left_door' or 'right_door' or None
|
||||||
"""
|
"""
|
||||||
timeout = Timer(3, count=6).start()
|
timeout = Timer(3, count=6).start()
|
||||||
|
self.exit_has_double_door = False
|
||||||
while 1:
|
while 1:
|
||||||
if skip_first_screenshot:
|
if skip_first_screenshot:
|
||||||
skip_first_screenshot = False
|
skip_first_screenshot = False
|
||||||
else:
|
else:
|
||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
|
|
||||||
|
# End
|
||||||
if timeout.reached():
|
if timeout.reached():
|
||||||
logger.error('Predict door timeout')
|
logger.error('Predict door timeout')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
left_door, right_door = self.predict_door_by_name(self.device.image)
|
left_door, right_door = self.predict_door_by_name(self.device.image)
|
||||||
logger.info(f'DomainExit: left_door={left_door}, right_door={right_door}')
|
logger.info(f'DomainExit: left_door={left_door}, right_door={right_door}')
|
||||||
if left_door is not None or right_door is not None:
|
if not left_door and not right_door:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# End
|
||||||
|
self.exit_has_double_door = left_door and right_door
|
||||||
door = self.choose_door(left_door, right_door)
|
door = self.choose_door(left_door, right_door)
|
||||||
if door is not None:
|
if door is not None:
|
||||||
return door
|
return door
|
||||||
|
Loading…
Reference in New Issue
Block a user