{"record":{"id":"6e392947e1b9f13a","repo":"babalae/better-genshin-impact","slug":"ocr-counttext","errorCode":null,"errorMessage":"原粹树脂上限 OCR 失败：{countText}","messagePattern":"原粹树脂上限 OCR 失败：(.+?)","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/AutoBoss/AutoBossTask.cs","lineNumber":348,"sourceCode":"        }\n\n        var originalResin = resinLimit - missingResin;\n        _logger.LogInformation(\"{Name}：剩余树脂 {Count}\", Name, originalResin);\n        return new OriginalResinInfo(originalResin, resinLimit);\n    }\n\n    /// <summary>\n    /// 按原右上角 OCR 区域读取当前/上限文本，并取数字串最后三位作为树脂上限。\n    /// </summary>\n    private int RecognizeOriginalResinLimit(ImageRegion capture, int resinIconRight)\n    {\n        var countRect = new Rect(resinIconRight + ScaleX(25), ScaleY(37), ScaleX(120), ScaleY(24));\n        using var countRegion = capture.DeriveCrop(countRect);\n        var countText = OcrFactory.Paddle.OcrWithoutDetector(countRegion.SrcMat);\n        var digits = Regex.Replace(StringUtils.ConvertFullWidthNumToHalfWidth(countText), @\"\\D\", \"\");\n        if (digits.Length < 3)\n        {\n            throw new FormatException($\"原粹树脂上限 OCR 失败：{countText}\");\n        }\n\n        var limitText = digits[^3..];\n        if (!int.TryParse(limitText, NumberStyles.None, CultureInfo.InvariantCulture, out var resinLimit) || resinLimit <= 0)\n        {\n            throw new FormatException($\"原粹树脂上限解析失败：{countText}\");\n        }\n\n        _logger.LogDebug(\"{Name}：原粹树脂上限 OCR：{Text} -> {Limit}\", Name, countText, resinLimit);\n        return resinLimit;\n    }\n\n    /// <summary>\n    /// 读取树脂详情弹窗中的全部恢复时间；已完全恢复时返回零时长。\n    /// </summary>\n    private TimeSpan RecognizeFullRecoveryTime(ImageRegion capture, int resinIconLeft, int resinIconBottom)\n    {\n        // 该偏移来自截图实际像素，不随 AssetScale 缩放。","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/AutoBoss/AutoBossTask.cs#L330-L366","documentation":"RecognizeOriginalResinLimit 用 OcrWithoutDetector 读取 '当前/上限' 文本，剥离非数字后要求至少 3 位数字（用于取最后三位作为上限）。位数不足 3 说明 OCR 根本没读到完整的 'NNN/LLL' 结构，无法可靠得到上限，抛 FormatException。","triggerScenarios":"countRect 区域（resinIconRight+ScaleX(25), ScaleY(37), ScaleX(120)×ScaleY(24)）落在空白或只有当前值的区域；OCR 返回空串、单字符或全角符号；图标定位 iconRight 偏移导致裁剪框错位。","commonSituations":"树脂详情弹窗未弹出或被遮挡；游戏分辨率/缩放与 AssetScale 不匹配使 ScaleX/ScaleY 偏移；PaddleOCR 模型在该小字号下识别失败；图标模板匹配漂移。","solutions":["确认点击 resinIconRegion 后 Delay(500) 足够让弹窗稳定，必要时加大等待或轮询弹窗出现。","校准 countRect 相对 iconRight 的偏移与尺寸，确保覆盖整段 '当前/上限'。","检查 AssetScale / 截图分辨率（log debug 的 OCR 文本），调整区域或改用 OcrResult 多区域拼接。","在外层 catch（行 282）兜底，将 OCR 失败降级为预检跳过而非任务中止。"],"exampleFix":"// before\nvar countText = OcrFactory.Paddle.OcrWithoutDetector(countRegion.SrcMat);\nvar digits = Regex.Replace(StringUtils.ConvertFullWidthNumToHalfWidth(countText), @\"\\D\", \"\");\nif (digits.Length < 3)\n{\n    throw new FormatException($\"原粹树脂上限 OCR 失败：{countText}\");\n}\n\n// after\nvar countText = OcrFactory.Paddle.OcrWithoutDetector(countRegion.SrcMat);\n_logger.LogDebug(\"{Name}：上限 OCR 原文：{Text}\", Name, countText);\nvar digits = Regex.Replace(StringUtils.ConvertFullWidthNumToHalfWidth(countText), @\"\\D\", \"\");\nif (digits.Length < 3)\n{\n    throw new FormatException($\"原粹树脂上限 OCR 失败：{countText}\");\n}","handlingStrategy":"retry","validationCode":"// 调用 RecognizeOriginalResinLimit 前，可先确认弹窗已出现\n// （无直接 API，建议在 RecognizeOriginalResinInfoFromBigMap 内重试截图）\nfor (int i = 0; i < 3; i++)\n{\n    using var c = CaptureToRectArea();\n    try { return RecognizeOriginalResinLimit(c, iconRight); }\n    catch (FormatException) when (i < 2) { await Delay(300, _ct); }\n}","typeGuard":null,"tryCatchPattern":"try { var limit = RecognizeOriginalResinLimit(capture, iconRight); }\ncatch (FormatException ex) { _logger.LogWarning(\"{Name}：上限 OCR 失败：{Msg}\", Name, ex.Message); throw; }","preventionTips":["点击树脂图标后等待弹窗动画完成再截图，必要时轮询。","记录 OCR 原文 debug 日志，快速定位区域偏移。","对关键 OCR 步骤加 1-2 次重试，吸收动画/卡顿抖动。"],"tags":["ocr","resin","paddleocr","genshin","autoboss"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}