# ldplayer-daily-grind **Repository Path**: omni331/ldplayer-daily-grind ## Basic Information - **Project Name**: ldplayer-daily-grind - **Description**: 雷电模拟器 + MaaEnd(终末地) + m9a(重返未来1999) 每日刷日常自动化。接管自 Kimi Desktop 的 Daimon 自动化,改由 Windows 计划任务每天四次(05:00 / 11:00 / 17:00 / 23:00)调度;含前台看门狗、ADB 健康探测与模拟器自愈。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-23 - **Last Updated**: 2026-10-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 每日刷日常 · 雷电模拟器 + m9a(重返未来1999) 接管自 Kimi Desktop(Daimon) 的自动化。2026-09-23 由 DSH 完成接管:脚本搬到本目录, 调度改为 Windows 计划任务,Kimi 侧同一条自动化已停用,避免两边同时抢模拟器。 > **2026-10-05 退役。** 用户玩的手游都出了手机版 MAA,PC 端这套不再需要(用户原话: > 「雷电和相关的都可以卸载了,我玩的手游都出了手机版maa了」)。已执行:计划任务 > `DailyGrind-LDPlayer` **删除**;雷电模拟器14 卸载(`D:\leidian\LDPlayer14`、 > `C:\Program Files\ldplayer9box`、服务 `LDPlayerSvr`、驱动 `Ld9BoxSup` 全清,D: 释放约 106 GB); > MAA 工具目录(M9A/MaaEnd/MAA)与相关快捷方式删除。**保留** `D:\leidian\wujie`(无界趣连2.0)、 > 本仓库与 `logs\` 作档案。**要恢复**:重装雷电 → `pwsh -File install_task.ps1` 重建任务; > 下面记录的所有坑仍然有效。 > > 残留清扫(2026-10-05 12:3x,脚本见 `logs\ld_cleanup.ps1`、输出见 `logs\ldplayer-cleanup.txt`): > 防火墙规则 `Ld9BoxSup`(3) / `Ld9BoxNat`(1) / `dnplayer`(1) 删除;`HKLM\SOFTWARE\leidian\ldplayer14` > 删除;`HKCU\SOFTWARE\ld\dnplayer`(雷电设备指纹 pcid/oaid/mpid…)删除;`%APPDATA%\leidian` 与 > `%APPDATA%\leidian14` 删除。**保留** 无界趣连的 `SOFTWARE\leidian\wujie`、`SOFTWARE\ld\wujie` > (HKLM+HKCU)。唯一没删掉的是 `HKLM\SOFTWARE\LDFSuggest`(空的 shell 能力注册,ACL 不让删, > 无实际影响)。 > **2026-10-01 起只跑 m9a。** 终末地改用 MaaEnd 手机版,PC 端不再启动 MaaEnd.exe, > 脚本里 `PHASES` 的 `maaend` 项标了 `enabled: False`(要恢复 PC 版改回 `True` 即可)。 > 下面所有与 MaaEnd 有关的章节都保留着——那是排查了整整一周的结论,将来复现或维护时还有用。 原位置(只读参考): D:\kimi-desktop\daimon-share\daimon\agents\main\blueprint\automations\automation_f4a3f203-3f5b-4d6b-960e-70846f15bcd0 ## 当前状态 | 项 | 值 | | --- | --- | | 调度 | Windows 计划任务 DailyGrind-LDPlayer | | 触发 | 每天八次:02:00 / 05:00 / 08:00 / 11:00 / 14:00 / 17:00 / 20:00 / 23:00,本机时区 China Standard Time (UTC+8)。按 02:00 起算每 3 小时一次(8 条独立的天级触发器) | | 动作 | D:\miniconda3\python.exe "D:\Desktop\DSH\daily-grind\daily_grind.py" | | 工作目录 | D:\Desktop\DSH\daily-grind | | 运行身份 | wangf,仅登录时运行,**普通权限**(2026-10-01 起取消了「使用最高权限运行」)。MaaEnd 的 UAC 弹窗曾要求提权,但 PC 版 MaaEnd 已停用 —— **若把 `PHASES` 里 maaend 的 `enabled` 改回 `True`,必须同时把「使用最高权限运行」勾回来**,否则它会永远卡在 UAC 弹窗上。取消勾选的好处:改这个任务不再需要管理员,触发器可以用 `Set-ScheduledTask` 直接改 | | 改触发器 | `$t = @(2,5,8,11,14,17,20,23) \| % { New-ScheduledTaskTrigger -Daily -At ([datetime]::Today.AddHours($_)) }; Set-ScheduledTask -TaskName DailyGrind-LDPlayer -Trigger $t`(提权勾着时会报「拒绝访问」) | | 时限 | 任务侧 4 小时上限;脚本自身最长约 75 分钟(m9a 60 分钟上限 + 启动与校准开销) | | 补偿 | StartWhenAvailable,错过的触发在机器可用时补跑 | | 并发 | 上一次还在跑时,新触发直接跳过(IgnoreNew) | ## 流程 现在的执行顺序只有 **m9a(重返未来1999)** 一个阶段(原先是终末地优先,2026-10-01 起终末地交给 MaaEnd 手机版): 0. 清掉上一轮残留的工具进程(见下"残留处理") 1. 启动雷电模拟器 LDPlayer14 (D:\leidian\LDPlayer14\dnplayer.exe),已在运行则跳过 2. 轮询雷电自带 adb 等设备就绪,最长 240s;**再跑一条 shell 命令确认 guest 真的活着**。 adb devices 列出 device 不代表模拟器没卡死——卡死时它照样列,但 echo 都超时 (2026-09-24 15:1x 就是这样,最后卡在横屏校准把后面所有阶段都拖没了)。 探到无响应就 ldconsole quit + 重新拉起,重启一次再等;然后等 20s 让桌面稳定 3. **每个工具开跑前**先锁横屏并把分辨率校准回 1280x720,最多重试 3 次 (2026-10-01 改成"开跑前"而不是"两阶段之间"——只剩一个阶段时,原来的位置等于一次都不校准) 4. 启动 m9a(重返未来1999),宽限 60s,等它进程退出,上限 60 分钟 (2026-10-03 从 30 分钟抬到 60:那份「日常-长草」配置带"刷到体力耗尽"性质的重复战斗, 实测有一轮跑了 42 分钟还在刷 —— 见 `M9A_WAIT_TIMEOUT_S` 附近的注释) (停用前的老流程里还有一段"启动 MaaEnd(终末地),宽限 60s,等日志静默 10 分钟判定收工, 上限 60 分钟"——它插在步骤 3 之前,见下文各 MaaEnd 章节。) 工具串行跑,避免同时抢模拟器。步骤 3 三次都失败才放弃步骤 4。 ## 前台看门狗 **为什么需要**:游戏被别的 App 盖住时,游戏进程其实还活着,但自动化工具的模板识别会 全部失败、原地空转直到把等待时间耗满。已实测到两次: - 2026-09-23 22:22 B 站客户端弹出的《重返未来1999-4.0版本预约》页面盖住游戏, 且整屏转成竖屏;m9a 在 Reward / ClosePage / StartGame / VictoryReturn 之间无限循环。 这是 Kimi 那 5 次 m9a_wait:timeout 的成因。 - 2026-09-24 00:31 雷电自带的 com.android.flysilkworm(应用中心)弹到前台, 看门狗清场 3 次后画面回到游戏,该轮 m9a 正常跑完退出。 - 2026-09-24 08:49~08:56 雷电的系统浏览器 com.android.browser 反复弹到前台 12 次, 看门狗每次都把画面拉回游戏(force_stopped 生效),该轮 m9a 跑满 9.4 分钟正常退出。 **怎么做的**:等工具的循环里每一轮读一次前台包名,跟**当前阶段对应的游戏包**比对。 - 前台就是当前阶段的游戏 -> 不动 - 前台是模拟器桌面 / 系统 UI -> 不动 - 前台是**另一个阶段的游戏** -> 只把它自己那轮的游戏拉回前台,**不强杀对方游戏** (强杀会把对方那一轮的进度一起干掉) - 前台是其它 App、且当前阶段的游戏进程还活着 -> am force-stop 那个包,等 3 秒; 游戏没回来就自己查启动 Activity 把它拉回前台;最后调一次横屏校准 - 当前阶段的游戏进程已经没了(工具收尾阶段)-> 不动,避免把游戏又拉起来 游戏包按阶段取(终末地 com.hypergryph.endfield.bilibili、 1999 com.shenlan.m.reverse1999.bilibili),所以先跑终末地时不会把终末地当入侵者杀掉。 雷电的某些窗口会带 Sys: 前缀(如 Sys2038:com.android.flysilkworm), 包名要用正则抠,不能直接取第一个带 / 的 token,否则 force-stop 会因为包名非法而静默失败。 ## 残留处理 上一轮如果留下还在跑的 m9a / MaaEnd,开跑前会先结束掉。杀不掉时分两种情况: - **日志还在更新** -> 判定它仍在干活,标 busy,不重新启动它,等它自己结束 - **日志已停超过 10 分钟** -> 判定卡死,标 blocked,**本轮直接放弃** 放弃而不硬跑,是因为两个工具同时操作一个模拟器会互相破坏,跑了也是白跑。 放弃时 last_run.json 的 summary 会写明是哪个进程,需要人工结束它 (任务管理器需以管理员身份运行)或重启电脑。 MaaEnd 有两个特性必须分开处理:**能多开**(实测卡死的旧实例不妨碍新实例干活), 而且**跑完不退出**(日志 Close log 之后就那么挂着)。所以: - 启动 MaaEnd 前先看日志是否静默:静默了说明上一轮早收工,**另起一个新实例** (状态记 launched_extra),而不是傻等一个已经干完活的进程 - 等它收工也不看进程,只看日志静默(进程表里永远有残留) m9a 相反:验证过多开不成立、而且跑完会自己退出(实测退出码 0),所以按老规矩走—— 残留挡路就跳过,等待也以进程退出为准。 > 2026-09-24 出现过一个删不掉的 MaaEnd(pid 29400,Access is denied,疑似被提权启动或受保护)。 > 当时手工建了个临时计划任务 **MaaEndOneOff** 把新实例拉起来完成了当天的终末地日常。 > 这个任务还在,跑完用 schtasks /delete /tn MaaEndOneOff /f 删掉即可(不要让它挂着)。 如果确认那个进程不会再干活,想跳过它对应的阶段、把能跑的那半跑掉: 在脚本目录放一个空的 force.flag 文件,下一次运行会当作启用 --force, 并把这个文件删掉(一次性)。计划任务的动作是固定的、不方便临时改命令行, 所以留了这么个文件开关。 ## 其它已经踩过的坑 - **不要从交互式 shell 用 Popen 起这个脚本**:子进程活不过父程序退出, 实测父程序返回 3 秒后,脚本连同它拉起的 m9a 一起被杀(日志停在半句话上)。 要跑就经计划任务:schtasks /run /tn DailyGrind-LDPlayer。 - **MaaEnd.exe 是引导进程**:启动后它会再拉起一个同名进程。所以判断"跑完没有" 必须以 tasklist 为准,不能只看 Popen 句柄——只看句柄会把"引导进程退出" 误判成"任务跑完",导致 m9a 和 MaaEnd 同时抢模拟器(2026-09-24 01:25 那轮就这样翻的车)。 - **MaaEnd 跑完不退出**:任务结束时它只在日志里写一行 Close log,进程一直挂着。 因此"进程还在"完全不能说明它还在干活——2026-09-24 12:30 那轮就是这么漏掉终末地的: 11:57 就收工的实例还挂着,脚本看到"已在运行"便跳过启动,白等 10 分钟直接进了 m9a。 现在的判据是日志 mtime。 - **停滞告警**:工具自己的日志目录超过 10 分钟没更新就记一条告警,用来发现 "游戏卡在加载画面"这类看门狗看不见的故障(终末地出现过长时间停在 SceneWaitLoadingExit)。 - **退出码**:工具是我们启动的会记录退出码,已在运行的记录不到。 - **PowerShell 一律用 PS7 (pwsh),不要再用 powershell(PS5)**: PS5 读无 BOM 的 UTF-8 脚本会按 ANSI 解码,中文路径直接读坏——2026-09-24 建 MaaEndOneOff 任务时就是这么失败的(注册成功但进程起不来,LastTaskResult 0x80070002 文件找不到,其实就是路径乱码)。PS7 默认按 UTF-8 读,没这个问题。 万一必须用 PS5:脚本存成带 BOM,或者用 -EncodedCommand 传 base64(UTF-16LE)。 ## 终末地卡在「登录」那里(2026-09-28 定位) B 站渠道的终末地启动时会弹一个「登录记录」页:账号名 + 蓝色「登录」按钮, Activity 是 com.gsc.login_record.LoginRecordActivity。它画在 Unity 画布上, uiautomator 扒不到控件,MaaEnd 的 OpenGame 节点链里也没有对应节点, 于是它一直对着这一页空转直到把等待时间耗满——这就是「终末地总是卡在登录游戏那里」。 登录真的失败时还会弹「账号登录失败,请检查网络状态后重试」,点「确认」后游戏直接退出, MaaEnd 同样处理不了。 对策分两层: 1. **脚本侧(已实现)**:看门狗每轮读一次 dumpsys window 的 Activity 名, 命中 GAME_TAP_TARGETS 里的页面就替它点一下(当前只登记了登录记录页 -> 点 640,406)。 这是「控件树里看不见、但 Activity 名会变」这一类弹窗的通用解法。 2. **MaaEnd 配置侧(2026-09-28 修)**:任务清单里「打开游戏」原本排了**三次** (一次正常 + 两个「🎮打开游戏(副本)」),已删掉重复的两条。 备份在同目录 mxu-MaaEnd.json.bak-20260927-235126。 改 MaaEnd 配置前必须先关掉 MaaEnd,否则它会把内存里的配置写回去,改了白改。 ## MaaEnd「压根没启动」(2026-09-28 定位) 现象:daily-grind 明明把 MaaEnd 拉起来了,终末地却什么都没做,最后 `maaend_wait` 干等到超时。 真因在 MaaEnd 自己的日志里:**AdbControlUnitMgr::connect failed to connect**。 模拟器的 ADB 是时有时无的(`adb devices` 一会儿有一会儿空),MaaEnd 启动那一刻正好没设备, 连接失败它就罢工了——**但进程还挂着**。脚本原来只看进程在不在,就以为它在跑。 对策(两层): 1. **启动每个工具之前先 `ensure_device()`**:adb 列到设备 + `shell echo ok` 有响应才算数, 不行就重启模拟器再等。不能只在整轮开头查一次,因为那之后设备还可能掉。 2. **起来之后 90 秒内日志毫无进展就判失败**:杀掉、确认设备、重启一次; 还是没进展就放弃本阶段,不再干等到超时。 用日志进展而不是进程存活来判断"到底干活没有",这类工具的进程太容易"活着但不干活"了。 ## MaaEnd 自动点登录:已验证生效(2026-09-30) **结论:`attach_resource_path` 确实有 pipeline 覆盖语义,自定义节点是活的。** 铁证(MaaEnd 自己的日志): [2026-09-28 02:00:31.421][PipelineTask::recognize_list] [cur_node_=OpenGame] [list=[{"anchor":false,"jump_back":false, "name":"TapEndfieldLogin"}, ... `OpenGame` 的 next 列表第一个就是 `TapEndfieldLogin`,全日志里出现 360 处。 也就是说 resource_custom/pipeline/login.json 里那句 `OpenGame.next` 前置生效了。 **踩过的读日志坑**:MaaEnd 的 `debug/maafw.log` 会轮转成 `maafw.bak.<时间>.log`。 判断"某个节点有没有出现"时只看 `maafw.log` 会漏——那一轮的内容可能已经被轮转走了。 2026-09-28 我就因此连报两次"未见",实际早就生效了。**要搜就搜 `maafw.bak.*.log` 一起搜。** **还没验到的一环**:`TapEndfieldLogin` 出现了 360 次,但没有一次 `cur_node_=TapEndfieldLogin`, 说明它每次都被求值、但当时屏幕上没有「登录」按钮(那时游戏根本没开),所以从未命中。 OCR 的 ROI `[430, 360, 430, 95]` 和正则 `^\s*登\s*录\s*$` 是按真实截图定的 (按钮中心 640,406 落在 ROI 内),理论上命中,但**要等真的弹出登录记录页才能算数**。 ## 机器休眠会把整轮吃掉(2026-09-30 定位) 11:00 那轮跑到 11:58 就没有下文:没有 `=== 结束 ===`,`last_run.json` 还停在 05:35:47, 模拟器和 MaaEnd 在同一刻一起消失。翻系统日志才看到: 2026/9/30 11:58:29 内核电源管理器已启动关闭转换。 (Kernel-Power,事件 ID 109) **笔记本睡了,整轮被连根拔掉。** 醒来后是计划任务的 StartWhenAvailable 把错过的 17:00 触发器补跑,所以下一轮记的是 `[2026-09-30 21:15:04] === 每日刷日常开始 ===`。两个后果: - 日志里的开始时间**不一定等于触发时间**,21:15 开始其实就是 17:00 那次的迟到运行; - 一轮被休眠打断时,日志里除了"少一行结束语"之外**没有任何痕迹**。 对策:`mark_started()` 每轮开头往 `last_run.json` 写 `startedAt`,`finish()` 再补 `finishedAt`。下一轮启动时若发现 `startedAt` 在、`finishedAt` 不在,就当场记一条 `!! 上一轮(<时间> 开始)没有正常结束,可能机器休眠或被强杀`。 这是**事后可见,不是自动续跑**——休眠期间的进度救不回来,只能等下一个触发点重跑。 真有不能丢的时段,得给计划任务加 `-WakeToRun`(代价是会把笔记本叫醒)。 ## 游戏进程整个没了(2026-09-30 21:15 那轮) `OpenGame` 连着 4 轮 `StuckRepairAction` —— 每次都是自己 `CloseGame` (`am force-stop com.hypergryph.endfield.bilibili`)+ `ResetStartUpGame` —— 仍然没能回到大世界,mxu 于是**静默放弃**,把后面的任务照旧往下发, 每个任务都停在 `SceneAnyEnterWorld` 空转,直到 60 分钟槽位烧光。 那一刻**游戏进程数是 0,前台是雷电桌面**(MaaEnd 的 OCR 正在读桌面上 「古龙群侠录」「江湖」这些别的应用名)。 `debug/maafw.log` 取证: 21:19:31 MaaTaskerPostTask [entry=OpenGame] task_id=200000001 21:20:47 MaaContextRunTask [entry=CloseGame] → am force-stop com.hypergryph.endfield.bilibili 21:20:47 MaaContextRunTask [entry=ResetStartUpGame] (21:19–21:23 窗口内:OpenGame 86 次、StuckRepairAction 4、CloseGame 4、ResetStartUpGame 4) **关键实测**:手动 `am start -n com.hypergryph.endfield.bilibili/com.u8.sdk.U8UnityContext` 把游戏拉起来之后,MaaEnd **45 秒内自己接上了**: SceneAnyEnterWorld → __ScenePrivateLogin → __ScenePrivateLoginConfirm → SceneWaitLoadingExit → __ScenePrivateAnyEnterWorld → DijiangRewards 它一直在等游戏回来,游戏一回来就继续。所以看门狗新增 `relaunch_dead_game()`: 连续 4 次采样(约 60s)读不到游戏进程就 `am start` 一次,一个阶段最多 3 次 (`MAX_RELAUNCH`);Activity 从 `GAME_ACTIVITY` 取,没登记就问 `cmd package resolve-activity --brief`。 顺带两条实测结论: - 游戏**冷启动必定**停在 B站 SDK 的 `com.gsc.login_record.LoginRecordActivity`, 所以 `GAME_TAP_TARGETS` 里那条自动点「登录」不是可选项而是必需项 (2026-09-30 21:31:25 确实命中过一次,日志里是 `watchdog 清场: {"dialog_tap": …}`)。 - 这台模拟器镜像里**没有 `monkey`**(`/system/bin/sh: monkey: inaccessible or not found`), 要拉 App 只能用 `am start -n 包名/Activity`。 ## 用法 python daily_grind.py 跑一次完整流程 python daily_grind.py --check 只校验依赖路径并打印执行顺序,不启动任何程序 ## 产物 logs\YYYY-MM-DD.log 逐行运行日志 logs\last_run.json 运行状态:startedAt / finishedAt / summary / steps / allFinished (startedAt 在、finishedAt 不在 = 上一轮被打断) ## 常用命令 schtasks /query /tn DailyGrind-LDPlayer /v /fo LIST 查看任务 schtasks /run /tn DailyGrind-LDPlayer 立即手动跑一次 schtasks /end /tn DailyGrind-LDPlayer 停掉正在跑的这一轮 pwsh -File D:\Desktop\DSH\daily-grind\install_task.ps1 重新注册 schtasks /delete /tn DailyGrind-LDPlayer /f 卸载任务 schtasks /delete /tn MaaEndOneOff /f 删掉临时拉起 MaaEnd 的一次性任务 ## 回滚到 Kimi 调度 1. 删除计划任务:schtasks /delete /tn DailyGrind-LDPlayer /f 2. 把 automation.json 里的 enabled 改回 true (备份:automation.json.bak-20260923-221641,与 automation.json 同目录) ## MaaEnd 会弹 UAC 提权,无窗口环境下永远卡住(2026-10-01 定位) 现象:`maaend -> launched` 之后 90 秒日志毫无进展 →「无进展,重启」→「依然无进展,放弃」, abort 之后连 m9a 也只跑 77 秒就退出(其实两个工具都没干活)。事后看进程:22MB / 0.1s CPU / `MainWindowHandle=0` / 不写任何日志。 真相:**MaaEnd.exe 启动时会请求提权**,Windows 弹出 UAC 对话框等人点「是」。计划任务是 无窗口环境(`LogonType=InteractiveToken`、默认 `LeastPrivilege`),没人能点,进程就一直挂着。 取证(每一步都排掉一个假设): - 屏幕上确实挂着 UAC 对话框:`用户账户控制(UAC) / 你要允许来自未知发布者的此应用对你的 设备进行更改吗? / MaaEnd.exe / 发布者: 未知`。抓屏见 `logs\screen-now.png`。 - `Get-Process consent`(consent.exe 就是 UAC 弹窗宿主)在每次启动 MaaEnd 后 **+1**; 启动 `m9a.exe` 完全不增加 → 不是系统级 UAC 策略变了,只针对 MaaEnd。 - 把 exe 复制成 `MaaEnd_test.exe` 再启动照样弹 → 不是按文件名/路径匹配的兼容性设置。 - exe 的 manifest 里只有 Common-Controls 依赖,**没有** `requestedExecutionLevel`; `AppCompatFlags\Layers` 里也没有当前路径(只有早被删掉的老路径 `D:\Desktop\MAA\MaaEnd-win-x86_64-v1.17.0\MaaEnd.exe => ~ RUNASADMIN`); 自定义 shim 库 `C:\WINDOWS\AppPatch\CustomSDB\{22221111-...}.sdb` 里也没有 MaaEnd。 → 提权是 exe 自己带的(二进制里有 `IsElevated` / `ShellExecute` / `runas` / `Verb` 字样, 与代码里早就记过的「MaaEnd.exe 是引导进程,起来后会再拉起一个同名进程」对得上)。 - 时间线:`MaaEnd.exe` 写于 **2026-09-26 12:11:55**(同批 `maafw` 12:12:05、`tasks` 12:12:09), 而「maaend 无进展」从 **09-27** 开始密集出现 → 是 v2.8.0 这次更新带进来的。 脚本侧加固:判定「无进展」时同时数 `consent.exe`,日志和 `last_run.json` 里直接写明 「有 N 个 UAC 弹窗待应答」,不再让人对着「无进展」瞎猜。 **治本要给它管理员权限**(三选一): 1. 任务计划程序 → `DailyGrind-LDPlayer` → 属性 → 常规 → 勾「使用最高权限运行」。 2. 管理员 PowerShell 执行:`schtasks /change /tn DailyGrind-LDPlayer /RL HIGHEST` (非提权 shell 会报 `ERROR: Access is denied.`)。 3. 换回不自动提权的旧版 MaaEnd。 **2026-10-01 起的状态**:PC 版 MaaEnd 停用(改用 MaaEnd 手机版),任务的 「使用最高权限运行」也一并取消 —— 只跑 m9a 用不着提权,而且取消之后改这个任务 (触发器、设置)不再需要管理员权限,`Set-ScheduledTask` 直接就能改。 **若哪天把 `PHASES` 里 maaend 的 `enabled` 改回 `True`,必须先把上面第 1 或第 2 步做回去**, 否则它会立刻退化成永远卡在 UAC 弹窗上。 ## 怎么判断工具"真干了活"(2026-10-02 定位) 日志在写 ≠ 在刷日常。工具起来后会先找设备,`AdbDeviceFinder::find` 一次十几秒, 日志写得欢但一个 pipeline 节点都没跑——脚本旧版只看"日志有没有动静", 于是这种情况一路白等到 30 分钟上限(`2026-10-02 10:39` 那轮), 而 02:00 那轮更糟:m9a 一个节点没跑就退出,脚本却把"进程退出"当成阶段成功。 现在都改成**数 `cur_node_`(MaaFramework 的 pipeline 节点标记)**: - 启动检查 `wait_tool_start(state, window)`:窗口内没出现节点就重启一次, 重启后还是没有就放弃本阶段;`window` 按负载自适应(`load>=90 → 300s`、 `>=70 → 180s`、否则 `90s`)。 - 收尾时 `log_mark_count(state) == 0` 一律记 `*_work: none` 并按失败算(退出的记 "本次没真刷",超时的记"这段时间里一个 pipeline 节点都没跑")。 - 计数是**按偏移量**数的(`mark_state()` 记下当前日志文件与已写字节数), 因为 m9a 的 `debug\maafw.log` 是追加的:从文件尾部数会拿上一轮的节点冒充这一轮。 - `debug\maafw.log` 写满约 17MB 会改名成 `maafw.bak.<时间>.log` 再新开一份 (2026-10-02 当天 05:04、05:09 各转过一次)。计数时会连带看刚轮转走的那份 (按 mtime 过滤,避免把几天前的老日志算进来),否则轮转前跑过的节点会被丢掉。 另外,`ensure_device()` 现在多了第三道门:除了 `adb devices` 有设备、`adb shell` 有响应, 还要求 `ldconsole list2` 能列出"正在运行"的实例(`wait_ld_ready`)。原因见 `logs\log-20261002.log`(MFAAvalonia 自己的日志):那一次 `ldconsole list2` 花了 7.5 秒, 把 MFAAvalonia 只有 60 秒的「启动后连接等待窗口」耗光,它打了一句「已放弃本次任务」 就退回 GUI 空转 —— 进程活着、日志也在写,就是一个节点都不跑。 ## 被强行结束的一轮长什么样(2026-10-02 14:00) 14:00 那轮只留下两行日志(`=== 每日刷日常开始 ===`、`emulator -> launched`),之后什么都没有。 脚本自己的 `try/except` 拦不到 —— 它不是异常退出,是**进程被连根拔掉**: - `(Get-ScheduledTaskInfo -TaskName DailyGrind-LDPlayer).LastTaskResult = 3221225786` (`0xC000013A`,STATUS_CONTROL_C_EXIT):任务的控制台窗口被关掉(或收到 Ctrl+C)就是这个码。 - 任务计划程序会给每个任务套一个 job 对象,任务一结束整棵树都被杀 —— 所以连它刚拉起来的 雷电模拟器也一起没了(`dnplayer` 消失、`Ld9BoxHeadless` 还在)。这也是「14:00 那轮看起来卡了 两小时」的真相:不是卡住,是进程早就没了,日志再也没有新行。 - 这种死法不会写 `=== 结束 ===`,也不会有 `last_run.json` 的收尾。排查入口就是上面那条 `LastTaskResult`。 - **关窗口是有意的叫停开关,不是故障**:用户打游戏时不想让模拟器起来,就直接关掉这个黑窗口 (2026-10-02 确认)。所以任务动作保持 `D:\miniconda3\python.exe`(可见窗口),**不要**改成 `pythonw.exe`。代价是关窗会把模拟器砍成半边(`dnplayer` 没了而 `Ld9BoxHeadless` 还在,或反过来), 下一轮的 `clear_stale_emulator()` 会自己清干净再重新拉起。 因此 `mark_started()` 现在开跑时会把 `finishedAt`/`artifact` 清成 `None`(否则上一轮的旧值会盖住 "这轮没收尾"),下一轮开工第一件事就往日志里写 `!! 上一轮(… 开始)没有正常结束,可能机器休眠或被强杀`。 `redirect_stdio()` 是给 `pythonw.exe` 启动方式准备的:没有控制台时(`sys.stdout is None`)把 stdout/stderr 接到 `logs\console-<日期>.log`,否则 `print` 和未捕获的回溯都会无声丢掉。 ## m9a 退出码 0 也可能是假的:虚拟机在跑的中途被关机(2026-10-04 定位) 2026-10-03 23:45 那轮日志全绿 —— `m9a_wait: exited`、`退出码 0`、`allFinished: true` —— 但游戏里一个日常都没做完。真相分两截: - 23:51:58 **虚拟机自己被关了**:`D:\leidian\LDPlayer14\vms\leidian0\Logs\VBox.log` 尾部 `fastpipe: deviceDestruct g_bGuestPowerOff=1` → `Changing the VM state from 'DESTROYING' to 'TERMINATED'` → `Console: Machine state changed to 'PoweredOff'` → `VBoxHeadless: exiting`。 - m9a 的实例配置 `D:\Desktop\2应用\MAA\M9A-win-x86_64-v4.5.3\config\instances\2128da40.json` 里写着 `"AfterTask": "CloseEmulatorAndMFA"` —— **无论成败,它跑完都关模拟器 + 关自己**。 所以「退出码 0」什么都不能证明(也解释了为什么每轮都得重新拉起模拟器)。 真话只在 MFAAvalonia 自己的日志里:`D:\Desktop\2应用\MAA\M9A-win-x86_64-v4.5.3\logs\log-<日期>.log` 23:52:28 子任务运行失败:index=3, task=WildernessProductTask 23:53:03 子任务运行失败:index=4, task=WildernessTradeTask 23:53:06 任务失败:收取荒原 / 连接状态变更:未连接。/ 截图超时,已断开连接 23:53:59 任务运行失败! 停止前状态:FAILED 现在的判定(`daily_grind.py`): - `mfa_task_result(log_dir, since_ts)` 解析这份日志,统计 `任务失败:`、`任务运行失败!`、 `截图超时,已断开连接` 三类行(按行首时间戳过滤 `since_ts` 之后的,避免拿上一轮的算)。 - `run_phase` 结尾:**有失败**就记 `