1
0
mirror of https://github.com/sui-feng-cb/AzurLaneAutoScript1.git synced 2026-07-13 02:54:25 +08:00

Feat: clear exercise attempts based on downtime

This commit is contained in:
positnuec
2026-07-10 07:25:55 +08:00
parent 9cc7aa804b
commit 22ca2d0542

View File

@@ -1,11 +1,11 @@
import datetime import datetime
from module.config.utils import get_server_last_update from module.config.utils import get_server_next_update, get_server_last_update
from module.exercise.assets import * from module.exercise.assets import *
from module.exercise.combat import ExerciseCombat from module.exercise.combat import ExerciseCombat
from module.logger import logger from module.logger import logger
from module.ocr.ocr import Digit, Ocr, OcrYuv from module.ocr.ocr import Digit, Ocr, OcrYuv
from module.ui.page import page_exercise from module.ui.page import page_exercise
from module.config.utils import get_server_next_update from module.smart_mgmt.utils import parse_downtime
class DatedDuration(Ocr): class DatedDuration(Ocr):
def __init__(self, buttons, lang='cnocr', letter=(255, 255, 255), threshold=128, alphabet='0123456789:IDS天日d', def __init__(self, buttons, lang='cnocr', letter=(255, 255, 255), threshold=128, alphabet='0123456789:IDS天日d',
@@ -77,6 +77,7 @@ class Exercise(ExerciseCombat):
opponent_change_count = 0 opponent_change_count = 0
remain = 0 remain = 0
preserve = 0 preserve = 0
DOWNTIME_END_HOUR_THRESHOLD = 15
def _new_opponent(self): def _new_opponent(self):
logger.info('New opponent') logger.info('New opponent')
@@ -171,18 +172,6 @@ class Exercise(ExerciseCombat):
self.config.set_record(Exercise_OpponentRefreshValue=0) self.config.set_record(Exercise_OpponentRefreshValue=0)
return 0 return 0
def _get_thursday_strategy(self, remain_time):
"""
Args:
remain_time(datetime.timedelta):
Returns:
bool: if use Thursday strategy
"""
if 96 > remain_time >= 84 or 264 > remain_time >= 252:
return True
return False
def _get_exercise_reset_remain(self): def _get_exercise_reset_remain(self):
""" """
Returns: Returns:
@@ -206,7 +195,43 @@ class Exercise(ExerciseCombat):
return preserve, admiral_interval return preserve, admiral_interval
def _should_force_clear(self, remain_time, admiral_interval): def _get_thursday_strategy(self, remain_hours):
"""
Args:
remain_hours(int):
Returns:
bool: if use Thursday strategy
"""
if 96 > remain_hours >= 84 or 264 > remain_hours >= 252:
return True
return False
def _get_downtime_strategy(self, now):
"""
Check smart_mgmt downtime window to decide whether to clear attempts.
Returns:
bool:
True if today is maintenance day with end time at or after DOWNTIME_END_HOUR_THRESHOLD.
False if available but today is not maintenance day.
None if unavailable (disabled, non-CN server, window missing, or parse failed).
"""
if self.config.SERVER != 'cn':
return None
if not self.config.cross_get('DowntimeMgmt.DowntimeStrategy.ManageExercise', False):
return None
window = self.config.cross_get('DowntimeMgmt.Downtime.Window', None)
if not window:
return None
end_dt = parse_downtime(window)
if end_dt is None:
return None
if end_dt <= now:
return False
return end_dt.date() == now.date() and end_dt.hour >= self.DOWNTIME_END_HOUR_THRESHOLD
def _should_force_clear(self, now, remain_time, admiral_interval):
"""Decide whether to clear all exercise attempts this run.""" """Decide whether to clear all exercise attempts this run."""
if admiral_interval is None or not remain_time: if admiral_interval is None or not remain_time:
return False return False
@@ -214,9 +239,16 @@ class Exercise(ExerciseCombat):
remain_hours = int(remain_time.total_seconds() // 3600) remain_hours = int(remain_time.total_seconds() // 3600)
admiral_start, admiral_end = admiral_interval admiral_start, admiral_end = admiral_interval
if self._get_thursday_strategy(remain_hours): downtime_strategy = self._get_downtime_strategy(now)
logger.info('Reach Thursday, using all attempts') if downtime_strategy is True:
logger.info('Downtime today, using all attempts before downtime')
return True return True
elif downtime_strategy is None:
# Fallback to thursday strategy when smart_mgmt is unavailable
if self._get_thursday_strategy(remain_hours):
logger.info('Reach Thursday, using all attempts before downtime')
return True
if admiral_start > remain_hours >= admiral_end: if admiral_start > remain_hours >= admiral_end:
logger.info('Reach set time for admiral trial, using all attempts') logger.info('Reach set time for admiral trial, using all attempts')
return True return True
@@ -226,11 +258,11 @@ class Exercise(ExerciseCombat):
return False return False
def _should_delay(self, next_update, forced_clear): def _should_delay(self, now, next_update, forced_clear):
"""Check whether to delay exercise to the configured time before next update.""" """Check whether to delay exercise to the configured time before next update."""
if forced_clear: if forced_clear:
return False return False
seconds_until_update = (next_update - datetime.datetime.now()).seconds seconds_until_update = (next_update - now).seconds
return seconds_until_update > 3600 * self.config.Exercise_DelayUntilHoursBeforeNextUpdate return seconds_until_update > 3600 * self.config.Exercise_DelayUntilHoursBeforeNextUpdate
def _exercise(self, preserve): def _exercise(self, preserve):
@@ -258,15 +290,17 @@ class Exercise(ExerciseCombat):
logger.attr('Exercise_ExerciseStrategy', self.config.Exercise_ExerciseStrategy) logger.attr('Exercise_ExerciseStrategy', self.config.Exercise_ExerciseStrategy)
self.preserve, admiral_interval = self._get_exercise_strategy() self.preserve, admiral_interval = self._get_exercise_strategy()
now = datetime.datetime.now()
remain_time = self._get_exercise_reset_remain() remain_time = self._get_exercise_reset_remain()
logger.info(f'Exercise period remain: {remain_time}') logger.info(f'Exercise period remain: {remain_time}')
forced_clear = self._should_force_clear(remain_time, admiral_interval) forced_clear = self._should_force_clear(now, remain_time, admiral_interval)
if forced_clear: if forced_clear:
self.preserve = 0 self.preserve = 0
logger.attr("exercise preserve", self.preserve)
next_update = get_server_next_update(server_update) next_update = get_server_next_update(server_update)
should_delay = self._should_delay(next_update, forced_clear) should_delay = self._should_delay(now, next_update, forced_clear)
if should_delay: if should_delay:
logger.warning(f'Exercise should run at {self.config.Exercise_DelayUntilHoursBeforeNextUpdate} ' logger.warning(f'Exercise should run at {self.config.Exercise_DelayUntilHoursBeforeNextUpdate} '
f'hours before next update. Delay task to it.') f'hours before next update. Delay task to it.')
@@ -280,7 +314,6 @@ class Exercise(ExerciseCombat):
self.config.set_record(Exercise_OpponentRefreshValue=self.opponent_change_count) self.config.set_record(Exercise_OpponentRefreshValue=self.opponent_change_count)
if self.remain <= self.preserve or self.opponent_change_count >= 5: if self.remain <= self.preserve or self.opponent_change_count >= 5:
next_run = next_update - datetime.timedelta(hours=self.config.Exercise_DelayUntilHoursBeforeNextUpdate) next_run = next_update - datetime.timedelta(hours=self.config.Exercise_DelayUntilHoursBeforeNextUpdate)
now = datetime.datetime.now()
if next_run >= now or should_delay: if next_run >= now or should_delay:
minutes_to_delay = int((next_run - now).total_seconds() / 60 + 1) minutes_to_delay = int((next_run - now).total_seconds() / 60 + 1)
self.config.task_delay(minute=minutes_to_delay) self.config.task_delay(minute=minutes_to_delay)