Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -2314,7 +2314,8 @@
"NotifyOpsiMail": true,
"LauncherPush": true,
"IndependentPush": false,
"OpsiOnePushConfig": "provider: null"
"OpsiOnePushConfig": "provider: null",
"AutoSearchTimeLimit": 5
},
"Storage": {
"Storage": {}
Expand Down
2 changes: 1 addition & 1 deletion module/base/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def from_seconds(cls, limit, speed=0.5):
count = int(limit / speed)
return cls(limit, count=count)

def start(self):
def start(self) -> Timer:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Timer 类内部直接使用 -> Timer 作为返回值类型标注,如果文件顶部没有 from __future__ import annotations,在 Python 3.11 以下版本中导入该模块时会抛出 NameError: name 'Timer' is not defined 错误。为了确保在所有 Python 版本中的兼容性,建议使用字符串字面量 -> "Timer"

Suggested change
def start(self) -> Timer:
def start(self) -> "Timer":

"""启动计时器。

如果计时器未启动,reached() 始终返回 True,从而实现首次快速尝试:
Expand Down
8 changes: 8 additions & 0 deletions module/config/argument/args.json
Original file line number Diff line number Diff line change
Expand Up @@ -12085,6 +12085,14 @@
"type": "textarea",
"value": "provider: null",
"mode": "yaml"
},
"AutoSearchTimeLimit": {
"type": "input",
"value": 5,
"validate": [
1,
240
]
}
},
"Storage": {
Expand Down
3 changes: 3 additions & 0 deletions module/config/argument/argument.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,9 @@ OpsiGeneral:
type: textarea
mode: yaml
value: "provider: null"
AutoSearchTimeLimit:
value: 5
validate: [1, 240]
OpsiAshBeacon:
AttackMode:
value: current
Expand Down
1 change: 1 addition & 0 deletions module/config/config_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ class GeneratedConfig:
OpsiGeneral_LauncherPush = True
OpsiGeneral_IndependentPush = False
OpsiGeneral_OpsiOnePushConfig = 'provider: null'
OpsiGeneral_AutoSearchTimeLimit = 5

# 配置组 `OpsiAshBeacon`
OpsiAshBeacon_AttackMode = 'current' # current, current_dossier, current_dossier_only
Expand Down
4 changes: 4 additions & 0 deletions module/config/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,10 @@
"OpsiOnePushConfig": {
"name": "Operation Siren notifications push settings",
"help": "The settings will take effect only when the \"Siren Operation Information Independent Push\" function is enabled. Use Onepush to push a message about Corrosion 1 and Short Cat. See the document for configuration method: https://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BCN%5D"
},
"AutoSearchTimeLimit": {
"name": "Auto Search Time Limit",
"help": "Unit: minutes. During auto search, the script will assume the game is stuck if no event is detected for this period."
}
},
"OpsiAshBeacon": {
Expand Down
4 changes: 4 additions & 0 deletions module/config/i18n/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,10 @@
"OpsiOnePushConfig": {
"name": "セイレーン作戦プッシュ通知設定",
"help": "「塞壬行動信息獨立推送」功能開啟時設置才生效。Onepushを使用して、侵食1と短毛猫に関する情報を1つプッシュします。設定方法はドキュメントを参照してください:https://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BCN%5D"
},
"AutoSearchTimeLimit": {
"name": "自動探索時間制限",
"help": "単位:分。自動探索中にイベントが一定時間発生しない場合、フリーズと判定されます。"
}
},
"OpsiAshBeacon": {
Expand Down
4 changes: 4 additions & 0 deletions module/config/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,10 @@
"OpsiOnePushConfig": {
"name": "大世界推送设置",
"help": "“大世界信息独立推送”功能开启时设置才生效。使用 Onepush 推送一条关于侵蚀1和短猫的信息。配置方法见文档:https://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BCN%5D"
},
"AutoSearchTimeLimit": {
"name": "自律寻敌时间限制",
"help": "单位:分钟。自律寻敌时连续多长时间没遇到事件会判定为游戏卡死"
}
},
"OpsiAshBeacon": {
Expand Down
4 changes: 4 additions & 0 deletions module/config/i18n/zh-MIAO.json
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,10 @@
"OpsiOnePushConfig": {
"name": "大世界推送设置",
"help": "“大世界信息独立推送”功能开启时设置才生效喵。使用 Onepush 推送一条关于侵蚀1和短猫的信息喵。配置方法见文档喵:https://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BCN%5D"
},
"AutoSearchTimeLimit": {
"name": "自律寻敌时间限制喵~",
"help": "单位:分钟。自律寻敌时连续多长时间没遇到事件会判定为游戏卡死喵~"
}
},
"OpsiAshBeacon": {
Expand Down
4 changes: 4 additions & 0 deletions module/config/i18n/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -2930,6 +2930,10 @@
"OpsiOnePushConfig": {
"name": "大世界推送設定",
"help": "”大世界資訊獨立推送”功能開啟時設定才生效。使用 Onepush 推送一條關於侵蝕1和短貓的資訊。配置方法見文檔:https://github.com/LmeSzinc/AzurLaneAutoScript/wiki/Onepush-configuration-%5BCN%5D"
},
"AutoSearchTimeLimit": {
"name": "自律尋敵時間限制",
"help": "單位:分鐘。自律尋敵時連續多長時間沒遇到事件會判定為遊戲卡死"
}
},
"OpsiAshBeacon": {
Expand Down
126 changes: 31 additions & 95 deletions module/os/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from module.exception import (
CampaignEnd,
GameTooManyClickError,
GameStuckError,
MapDetectionError,
MapWalkError,
RequestHumanTakeover,
Expand Down Expand Up @@ -954,6 +955,7 @@ def false_func(*args, **kwargs):
finished_combat = 0
died_timer = Timer(1.5, count=3)
self.hp_reset()
auto_search_time_limit_timer = Timer(self.config.OpsiGeneral_AutoSearchTimeLimit * 60, count=1).start()
for _ in self.loop():
# 结束条件
if not unlock_checked and unlock_check_timer.reached():
Expand Down Expand Up @@ -986,10 +988,12 @@ def false_func(*args, **kwargs):

if self.handle_os_auto_search_map_option(drop=drop, enable=success):
unlock_checked = True
auto_search_time_limit_timer.reset()
continue
if self.handle_retirement():
# 退役会中断自动搜索,需要重试
self.ash_popup_canceled = True
auto_search_time_limit_timer.reset()
continue
if self.combat_appear():
self.on_auto_search_battle_count_add()
Expand All @@ -998,7 +1002,7 @@ def false_func(*args, **kwargs):
self.interrupt_auto_search()
elif (
strategic
and not getattr(self, 'is_running_smart_scheduling_task', lambda: False)()
and not getattr(self.config, '_disable_task_switch', False)
and self.config.task_switched()
):
if self.config.task.command == "OpsiMeowfficerFarming":
Expand All @@ -1018,102 +1022,15 @@ def false_func(*args, **kwargs):
):
success = False
logger.warning("Fleet died, stop auto search")
auto_search_time_limit_timer.reset()
continue
auto_search_time_limit_timer.reset()
if self.handle_map_event():
# 自动搜索无法处理塞壬搜索装置。
auto_search_time_limit_timer.reset()
continue

return finished_combat

def os_auto_search_daemon_until_combat(
self, drop=None, strategic=False, interrupt=None, skip_first_screenshot=True
):
"""
自动寻敌,遇到第一次战斗就返回。

Args:
drop (DropRecord): 掉落记录对象。
strategic (bool): 是否运行战略搜索。
interrupt (callable): 中断回调函数。
skip_first_screenshot: 是否跳过第一次截图。

Returns:
int: 完成的战斗次数。

Raises:
CampaignEnd: 自动搜索结束时抛出。
RequestHumanTakeover: 没有自动搜索选项时抛出。

Pages:
in: AUTO_SEARCH_OS_MAP_OPTION_OFF
out: AUTO_SEARCH_OS_MAP_OPTION_OFF 且 info_bar_count() >= 2(地图上无可清理对象时)。
AUTO_SEARCH_REWARD(获得自动搜索奖励时)。
"""
logger.hr("OS auto search until combat", level=2)
self.on_auto_search_battle_count_reset()
unlock_checked = False
unlock_check_timer = Timer(5, count=10).start()
self.ash_popup_canceled = False

def false_func(*args, **kwargs):
return False

success = True
interrupt_confirm = False
if callable(interrupt):
is_interrupt, not_interrupt = interrupt, false_func
elif isinstance(interrupt, list) and len(interrupt) == 2:
is_interrupt = interrupt[0] if callable(interrupt[0]) else false_func
not_interrupt = interrupt[1] if callable(interrupt[1]) else false_func
else:
is_interrupt, not_interrupt = false_func, false_func
finished_combat = 0
died_timer = Timer(1.5, count=3)
self.hp_reset()
for _ in self.loop():
# 结束条件
if not unlock_checked and unlock_check_timer.reached():
logger.critical("当前海域未解锁自律,请先完成剧情任务。")
raise RequestHumanTakeover
if self.is_in_map():
self.device.stuck_record_clear()
if not success:
if died_timer.reached():
logger.warning("Fleet died confirm")
break
else:
if not interrupt_confirm and is_interrupt():
interrupt_confirm = True
if interrupt_confirm and not_interrupt():
interrupt_confirm = False
died_timer.reset()
else:
died_timer.reset()

if not unlock_checked:
if self.appear(AUTO_SEARCH_OS_MAP_OPTION_OFF, offset=(5, 120)):
unlock_checked = True
elif self.appear(
AUTO_SEARCH_OS_MAP_OPTION_OFF_DISABLED, offset=(5, 120)
):
unlock_checked = True
elif self.appear(AUTO_SEARCH_OS_MAP_OPTION_ON, offset=(5, 120)):
unlock_checked = True

if self.handle_os_auto_search_map_option(drop=drop, enable=success):
unlock_checked = True
continue
if self.handle_retirement():
# 退役会中断自动搜索,需要重试
self.ash_popup_canceled = True
continue
if self.combat_appear():
self.on_auto_search_battle_count_add()
self.interrupt_auto_search(goto_main=False, end_task=False)
return finished_combat
if self.handle_map_event():
# 自动搜索无法处理塞壬搜索装置。
continue
if auto_search_time_limit_timer.reached():
raise GameStuckError('自律寻敌卡死')
Comment on lines +1032 to +1033

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

auto_search_time_limit_timerself.is_in_map()False 时(例如在战斗中、加载界面或剧情对话中)不会被重置。如果单次战斗或加载时间超过了 AutoSearchTimeLimit(用户可以设置为 1 分钟),计时器就会超时并抛出误报的 GameStuckError。为了避免这种情况,建议在非地图界面时重置该计时器,使其仅在地图上卡死时生效。

Suggested change
if auto_search_time_limit_timer.reached():
raise GameStuckError('自律寻敌卡死')
if not self.is_in_map():
auto_search_time_limit_timer.reset()
if auto_search_time_limit_timer.reached():
raise GameStuckError('自律寻敌卡死')


return finished_combat

Expand Down Expand Up @@ -1503,8 +1420,13 @@ def run_strategic_search(self):
self.hp_reset()
self.hp_get()
return True
except TaskEnd:
# 任务切换,让异常继续向上传播
except (
TaskEnd,
GameStuckError,
GameTooManyClickError,
RequestHumanTakeover,
):
# 任务切换和恢复型异常必须交给上层调度器处理。
raise
except Exception as e:
logger.warning(f"Strategic search interrupted: {e}")
Expand Down Expand Up @@ -2141,6 +2063,13 @@ def _execute_fixed_patrol_scan(
for _ in range(2):
try:
self.map_rescan(rescan_mode="full")
except (
TaskEnd,
GameStuckError,
GameTooManyClickError,
RequestHumanTakeover,
):
raise
except Exception as e:
logger.debug(f"最终全图重扫出现异常,继续重试: {e}", exc_info=True)
time.sleep(0.6)
Expand All @@ -2150,6 +2079,13 @@ def _execute_fixed_patrol_scan(
logger.info("执行一次自律寻敌以清理可能的装置")
try:
self.run_auto_search(question=True, rescan=None, after_auto_search=True)
except (
TaskEnd,
GameStuckError,
GameTooManyClickError,
RequestHumanTakeover,
):
raise
except Exception as e:
logger.warning(f"自律寻敌过程出现异常: {e}")

Expand Down
11 changes: 9 additions & 2 deletions module/os/tasks/meowfficer_farming.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from module.config.config import TaskEnd
from module.config.utils import get_os_reset_remain
from module.exception import RequestHumanTakeover, ScriptError
from module.exception import (
GameStuckError,
GameTooManyClickError,
RequestHumanTakeover,
ScriptError,
)
from module.logger import logger
from module.map.map_grids import SelectedGrids
from module.os.map import OSMap
Expand Down Expand Up @@ -181,7 +186,7 @@ def _meow_handle_stay_in_zone(self, zone):
try:
try:
search_completed = self.run_strategic_search()
except TaskEnd:
except (TaskEnd, GameStuckError, GameTooManyClickError, RequestHumanTakeover):
raise
except Exception as e:
logger.warning(f'战略搜索异常: {e}')
Expand All @@ -194,6 +199,8 @@ def _meow_handle_stay_in_zone(self, zone):

try:
self.handle_after_auto_search()
except (TaskEnd, GameStuckError, GameTooManyClickError, RequestHumanTakeover):
raise
except Exception:
logger.exception('handle_after_auto_search 发生异常')
finally:
Expand Down
Loading
Loading