Skip to content

Commit 42ae287

Browse files
committed
feat: 凹图次数限制
1 parent 3bfb544 commit 42ae287

2 files changed

Lines changed: 63 additions & 15 deletions

File tree

custom/maa/farm.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@
2323
sys.path.insert(0, _ROOT)
2424

2525
from custom.core.timing import calibration # noqa: E402
26+
from custom.maa.reco.click_stage import get_attempt_count, reset_attempt_count # noqa: E402
2627
from custom.maa.registry import register_all # noqa: E402
2728
from custom.utils.jsonc import load as load_jsonc # noqa: E402
2829
from custom.utils.logger import setup_logging # noqa: E402
2930
from custom.utils.runtime_paths import configure_paths # noqa: E402
3031

3132
logger = logging.getLogger(__name__)
3233

33-
# 每轮估时(秒),用于 max-retries 超时估算
34-
_EST_SECONDS_PER_ROUND = 120
34+
# 次数监控线程的轮询间隔(秒)
35+
_POLL_INTERVAL = 2.0
3536

3637

3738
def main() -> int:
@@ -48,7 +49,10 @@ def main() -> int:
4849
help="难度:normal=普通 | sand=沙盘推演",
4950
)
5051
parser.add_argument(
51-
"--max-retries", type=int, default=50, help="最大重试次数(0=无限,靠 Ctrl+C 停)"
52+
"--max-retries",
53+
type=int,
54+
default=50,
55+
help="最大凹图次数(0=无限,靠 Ctrl+C 停)。按实际尝试计数,不再用估时",
5256
)
5357
parser.add_argument(
5458
"--profile", default=None, help="校准文件名(可选,默认 config.DEFAULT_CALIBRATION)"
@@ -72,6 +76,7 @@ def main() -> int:
7276

7377
if args.profile:
7478
calibration.load(args.profile) # 校验可加载
79+
reset_attempt_count() # 每次运行从 0 计数
7580
logger.info("时间轴: %s(map_code 从文件读取)", args.timeline)
7681

7782
wins = Toolkit.find_desktop_windows()
@@ -115,23 +120,29 @@ def main() -> int:
115120
pipeline["Farm"]["anchor"] = {"Farm@SwitchDifficulty": anchor_target}
116121
logger.info("难度:%s", "沙盘推演" if args.difficulty == "sand" else "普通")
117122

118-
# max-retries 超时定时器(到点 post_stop)
123+
# max-retries 次数监控线程:累计凹图尝试达上限则 post_stop
124+
# 用 > 而非 >=:count 在 ClickStage 识别成功时自增(约每轮一次),
125+
# 故 count > max_retries 意味着已发起 max_retries 次完整尝试、第 N+1 次刚开始,此时停。
119126
if args.max_retries:
120-
deadline = args.max_retries * _EST_SECONDS_PER_ROUND
121127

122-
def _timeout_stop() -> None:
123-
time.sleep(deadline)
124-
if not tasker.stopping:
125-
logger.warning("已达 max-retries %d(≈%ds),停止", args.max_retries, deadline)
126-
tasker.post_stop()
127-
128-
threading.Thread(target=_timeout_stop, daemon=True).start()
128+
def _count_stop() -> None:
129+
while not tasker.stopping:
130+
time.sleep(_POLL_INTERVAL)
131+
if get_attempt_count() > args.max_retries:
132+
if not tasker.stopping:
133+
logger.warning(
134+
"已达 max-retries %d 次(实际 %d 次),停止",
135+
args.max_retries,
136+
get_attempt_count(),
137+
)
138+
tasker.post_stop()
139+
return
140+
141+
threading.Thread(target=_count_stop, daemon=True).start()
129142

130143
logger.info(
131144
"开始凹图%s。请在关卡列表页等待...",
132-
f"(最多 {args.max_retries} 次,≈{args.max_retries * _EST_SECONDS_PER_ROUND}s)"
133-
if args.max_retries
134-
else "(无限,Ctrl+C 停)",
145+
f"(最多 {args.max_retries} 次凹图)" if args.max_retries else "(无限,Ctrl+C 停)",
135146
)
136147

137148
t_start = time.time()

custom/maa/reco/click_stage.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import json
1010
import logging
11+
import time
1112
from pathlib import Path
1213

1314
from maa.context import Context
@@ -20,6 +21,41 @@
2021

2122
_TIMELINE_DIR = project_root() / "config" / "timelines"
2223

24+
# —— 凹图轮次计数 ——
25+
# ClickStage 每轮循环进入一次 ≈ 一次凹图尝试。Farm 用 JumpBack 反复跳回
26+
# ClickStage,同一轮里识别失败会重试,故用时间间隔去重避免重复计数。
27+
_MIN_ATTEMPT_INTERVAL = 5.0 # 秒:距上次计数不足此值则不计数
28+
_attempt_count = 0
29+
_last_attempt_time = 0.0 # monotonic,0 表示尚未计过
30+
31+
32+
def get_attempt_count() -> int:
33+
"""当前累计的有效凹图尝试次数(供外部读取,如 max-retries 判定)。"""
34+
return _attempt_count
35+
36+
37+
def reset_attempt_count() -> None:
38+
"""重置计数(新一轮 farm 运行前调用)。"""
39+
global _attempt_count, _last_attempt_time
40+
_attempt_count = 0
41+
_last_attempt_time = 0.0
42+
43+
44+
def _maybe_count_attempt() -> None:
45+
"""进入 ClickStage 即记一次尝试;距上次不足 _MIN_ATTEMPT_INTERVAL 则跳过。"""
46+
global _attempt_count, _last_attempt_time
47+
now = time.monotonic()
48+
if _last_attempt_time and (now - _last_attempt_time) < _MIN_ATTEMPT_INTERVAL:
49+
logger.debug(
50+
"跳过凹图计数(距上次 %.1fs < %.0fs)",
51+
now - _last_attempt_time,
52+
_MIN_ATTEMPT_INTERVAL,
53+
)
54+
return
55+
_attempt_count += 1
56+
_last_attempt_time = now
57+
logger.info("▶ 第 %d 次凹图尝试", _attempt_count)
58+
2359

2460
def _resolve_timeline_path(timeline_path: str) -> Path:
2561
"""timeline_path 纯文件名 → config/timelines/ 下;带路径 → 相对项目根。"""
@@ -105,4 +141,5 @@ def analyze(
105141
if not box:
106142
return None
107143
logger.info("识别到关卡 %s at %s", stage_text, box)
144+
_maybe_count_attempt()
108145
return box

0 commit comments

Comments
 (0)