Validations
问题描述
当前停止机(Hard Stop)功能处于半实现状态。前端已有 StopCondition 框架和日志解析触发的 taskStop() 调用,但后端的单轮战斗流程内部并没有被 stop 信号真正穿透,导致停止行为只能达到**「轮次级」(即等当前这一整轮 run_normal_fight(times=1) 跑完才能停下),而非「秒级」**(类似 Ctrl+C 在下一个安全检查点立即退出)。
具体表现:
- 当船舱接近 500、胖次接近 50,或已经捞到目标船时,如果当前轮次刚好进入
run_combat 状态机,即使点击停止或条件已触发,也必须等整场战斗(包括地图导航、出征准备、多节点战斗、结算动画)全部结束后才能停;
- 对于只想「捞到某艘船就停」的场景,目前
StopCondition 完全缺失 target_ship_dropped 字段,没有任何自动停止手段;
- 后端
DailyAutomationConfig 中存在 stop_max_ship / stop_max_loot 两个声明了但未被任何代码读取的死字段,属于未落地的配置残留。
另外,现有 taskStop() 的语义偏向「强制终止当前任务线程」,停止后任务虽然会标记为 STOPPED,但:
- 前端
stopRunning() 会把任务恢复为未执行状态并塞回队列;
- 后端 executor 只是在
for 循环开头检查 should_stop(),状态机内部(如长时间 OCR 等待、点击重试、地图导航)完全不检查 ctx.stop_event;
- 这种设计使得「立即停止」与「优雅恢复」之间存在张力:要么等很久才停,要么强行中断后前后端状态可能不一致。
解决方案
建议将停止机升级为前后端协同的安全检查点机制,核心目标:
- 在战斗流程内部增加可安全退出的检查点(如出征准备页、战斗节点间、结算页),实现秒级响应;
- 停止后不影响后端进程和后续任务队列,无需用户手动重启后端;
- 补齐目标船掉落停止条件,并统一前后端配置入口。
1. 扩展 StopCondition 语义
在前后端统一的停止条件定义中增加:
ship_count_ge: int — 舰船获取数达到即停;
loot_count_ge: int — 战利品达到即停(已半实现,需后端兜底);
target_ship_dropped: list[str] — 掉落指定舰船即停(新增);
- (可选)
stop_after_map_count: int — 完成 N 张地图后停止。
2. 后端在战斗流程中嵌入安全检查点
NormalFightRunner(及 EventFightRunner 等)在以下节点主动检查停止条件:
- 出征前(
_enter_fight 读取面板数量后):若已触及上限,直接返回一个 STOP_CONDITION_MET 标志的 CombatResult,该轮不再进入战斗;
- 战斗节点间 / 结算后:若检测到目标船掉落或数量达标,立即标记本轮结果为停止条件触发;
- 状态机空闲期:在
combat.engine 的页面跳转、等待动画、OCR 轮询等非原子操作间隙,检查 ctx.stop_event.is_set(),安全退出当前轮次。
3. 统一停止后的行为语义
- 当停止条件触发或被用户手动停止时,当前任务应被标记为已完成但提前终止(
stopped / condition_met),而不是失败;
TaskScheduler / task.py 的各 executor 应识别该状态,不再重试、不再塞回队列,而是正常进入 handleTaskFinished 的后续流程;
- 后端进程保持存活,队列中其他任务(如远征、日常)仍可继续执行。
4. 清理并暴露配置入口
- 移除或激活
DailyAutomationConfig 中的 stop_max_ship / stop_max_loot 死字段(建议映射为全局默认 StopCondition,或直接删除避免误导);
- 在前端 Plan / Preset 编辑器中增加「停止条件」配置项,将条件随
TaskRequest 下发到后端;
- 后端
CombatPlan.from_yaml() / from_dict() 支持读取 stop_condition 字段,runner 直接消费,不再完全依赖前端日志解析作为触发源。
通过以上改造,停止机可以从「轮次结束后才能停」升级为「在下一个安全检查点立刻停」,同时保证停止是可恢复、可继续的,不会导致后端进程异常或必须手动重启。
Validations
问题描述
当前停止机(Hard Stop)功能处于半实现状态。前端已有
StopCondition框架和日志解析触发的taskStop()调用,但后端的单轮战斗流程内部并没有被 stop 信号真正穿透,导致停止行为只能达到**「轮次级」(即等当前这一整轮run_normal_fight(times=1)跑完才能停下),而非「秒级」**(类似 Ctrl+C 在下一个安全检查点立即退出)。具体表现:
run_combat状态机,即使点击停止或条件已触发,也必须等整场战斗(包括地图导航、出征准备、多节点战斗、结算动画)全部结束后才能停;StopCondition完全缺失target_ship_dropped字段,没有任何自动停止手段;DailyAutomationConfig中存在stop_max_ship/stop_max_loot两个声明了但未被任何代码读取的死字段,属于未落地的配置残留。另外,现有
taskStop()的语义偏向「强制终止当前任务线程」,停止后任务虽然会标记为STOPPED,但:stopRunning()会把任务恢复为未执行状态并塞回队列;for循环开头检查should_stop(),状态机内部(如长时间 OCR 等待、点击重试、地图导航)完全不检查ctx.stop_event;解决方案
建议将停止机升级为前后端协同的安全检查点机制,核心目标:
1. 扩展 StopCondition 语义
在前后端统一的停止条件定义中增加:
ship_count_ge: int— 舰船获取数达到即停;loot_count_ge: int— 战利品达到即停(已半实现,需后端兜底);target_ship_dropped: list[str]— 掉落指定舰船即停(新增);stop_after_map_count: int— 完成 N 张地图后停止。2. 后端在战斗流程中嵌入安全检查点
NormalFightRunner(及EventFightRunner等)在以下节点主动检查停止条件:_enter_fight读取面板数量后):若已触及上限,直接返回一个STOP_CONDITION_MET标志的CombatResult,该轮不再进入战斗;combat.engine的页面跳转、等待动画、OCR 轮询等非原子操作间隙,检查ctx.stop_event.is_set(),安全退出当前轮次。3. 统一停止后的行为语义
stopped/condition_met),而不是失败;TaskScheduler/task.py的各 executor 应识别该状态,不再重试、不再塞回队列,而是正常进入handleTaskFinished的后续流程;4. 清理并暴露配置入口
DailyAutomationConfig中的stop_max_ship/stop_max_loot死字段(建议映射为全局默认StopCondition,或直接删除避免误导);TaskRequest下发到后端;CombatPlan.from_yaml()/from_dict()支持读取stop_condition字段,runner 直接消费,不再完全依赖前端日志解析作为触发源。通过以上改造,停止机可以从「轮次结束后才能停」升级为「在下一个安全检查点立刻停」,同时保证停止是可恢复、可继续的,不会导致后端进程异常或必须手动重启。