babalae/better-genshin-impact · error · FormatException

原粹树脂上限 OCR 失败:{countText}

Error message

原粹树脂上限 OCR 失败:{countText}

What it means

RecognizeOriginalResinLimit 用 OcrWithoutDetector 读取 '当前/上限' 文本,剥离非数字后要求至少 3 位数字(用于取最后三位作为上限)。位数不足 3 说明 OCR 根本没读到完整的 'NNN/LLL' 结构,无法可靠得到上限,抛 FormatException。

Source

Thrown at BetterGenshinImpact/GameTask/AutoBoss/AutoBossTask.cs:348

        }

        var originalResin = resinLimit - missingResin;
        _logger.LogInformation("{Name}:剩余树脂 {Count}", Name, originalResin);
        return new OriginalResinInfo(originalResin, resinLimit);
    }

    /// <summary>
    /// 按原右上角 OCR 区域读取当前/上限文本,并取数字串最后三位作为树脂上限。
    /// </summary>
    private int RecognizeOriginalResinLimit(ImageRegion capture, int resinIconRight)
    {
        var countRect = new Rect(resinIconRight + ScaleX(25), ScaleY(37), ScaleX(120), ScaleY(24));
        using var countRegion = capture.DeriveCrop(countRect);
        var countText = OcrFactory.Paddle.OcrWithoutDetector(countRegion.SrcMat);
        var digits = Regex.Replace(StringUtils.ConvertFullWidthNumToHalfWidth(countText), @"\D", "");
        if (digits.Length < 3)
        {
            throw new FormatException($"原粹树脂上限 OCR 失败:{countText}");
        }

        var limitText = digits[^3..];
        if (!int.TryParse(limitText, NumberStyles.None, CultureInfo.InvariantCulture, out var resinLimit) || resinLimit <= 0)
        {
            throw new FormatException($"原粹树脂上限解析失败:{countText}");
        }

        _logger.LogDebug("{Name}:原粹树脂上限 OCR:{Text} -> {Limit}", Name, countText, resinLimit);
        return resinLimit;
    }

    /// <summary>
    /// 读取树脂详情弹窗中的全部恢复时间;已完全恢复时返回零时长。
    /// </summary>
    private TimeSpan RecognizeFullRecoveryTime(ImageRegion capture, int resinIconLeft, int resinIconBottom)
    {
        // 该偏移来自截图实际像素,不随 AssetScale 缩放。

View on GitHub (pinned to a7cb36712d)

Solutions

  1. 确认点击 resinIconRegion 后 Delay(500) 足够让弹窗稳定,必要时加大等待或轮询弹窗出现。
  2. 校准 countRect 相对 iconRight 的偏移与尺寸,确保覆盖整段 '当前/上限'。
  3. 检查 AssetScale / 截图分辨率(log debug 的 OCR 文本),调整区域或改用 OcrResult 多区域拼接。
  4. 在外层 catch(行 282)兜底,将 OCR 失败降级为预检跳过而非任务中止。

Example fix

// before
var countText = OcrFactory.Paddle.OcrWithoutDetector(countRegion.SrcMat);
var digits = Regex.Replace(StringUtils.ConvertFullWidthNumToHalfWidth(countText), @"\D", "");
if (digits.Length < 3)
{
    throw new FormatException($"原粹树脂上限 OCR 失败:{countText}");
}

// after
var countText = OcrFactory.Paddle.OcrWithoutDetector(countRegion.SrcMat);
_logger.LogDebug("{Name}:上限 OCR 原文:{Text}", Name, countText);
var digits = Regex.Replace(StringUtils.ConvertFullWidthNumToHalfWidth(countText), @"\D", "");
if (digits.Length < 3)
{
    throw new FormatException($"原粹树脂上限 OCR 失败:{countText}");
}
Defensive patterns

Strategy: retry

Validate before calling

// 调用 RecognizeOriginalResinLimit 前,可先确认弹窗已出现
// (无直接 API,建议在 RecognizeOriginalResinInfoFromBigMap 内重试截图)
for (int i = 0; i < 3; i++)
{
    using var c = CaptureToRectArea();
    try { return RecognizeOriginalResinLimit(c, iconRight); }
    catch (FormatException) when (i < 2) { await Delay(300, _ct); }
}

Try / catch

try { var limit = RecognizeOriginalResinLimit(capture, iconRight); }
catch (FormatException ex) { _logger.LogWarning("{Name}:上限 OCR 失败:{Msg}", Name, ex.Message); throw; }

Prevention

When it happens

Trigger: countRect 区域(resinIconRight+ScaleX(25), ScaleY(37), ScaleX(120)×ScaleY(24))落在空白或只有当前值的区域;OCR 返回空串、单字符或全角符号;图标定位 iconRight 偏移导致裁剪框错位。

Common situations: 树脂详情弹窗未弹出或被遮挡;游戏分辨率/缩放与 AssetScale 不匹配使 ScaleX/ScaleY 偏移;PaddleOCR 模型在该小字号下识别失败;图标模板匹配漂移。

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/6e392947e1b9f13a. Report an issue: GitHub.