babalae/better-genshin-impact · error · InvalidOperationException
计算缺失树脂 {missingResin} 超过树脂上限 {resinLimit}
Error message
计算缺失树脂 {missingResin} 超过树脂上限 {resinLimit} What it means
在 RecognizeOriginalResinInfoFromBigMap 中,缺失树脂数 missingResin = ⌈全部恢复秒数 / 480s⌉ 与 OCR 读到的树脂上限 resinLimit 做一致性校验。正常情况下 missingResin 永远 ≤ resinLimit(满上限约 160×8min≈21.3h),一旦超出说明两者之一被读错,任务以 InvalidOperationException 中止以免用错误的树脂数驱动后续补充逻辑。
Source
Thrown at BetterGenshinImpact/GameTask/AutoBoss/AutoBossTask.cs:329
if (resinIconRegion.IsEmpty())
{
throw new InvalidOperationException("未找到原粹树脂图标");
}
var iconLeft = resinIconSearchRegion.X + resinIconRegion.Left;
var iconRight = resinIconSearchRegion.X + resinIconRegion.Right;
var iconBottom = resinIconSearchRegion.Y + resinIconRegion.Bottom;
resinIconRegion.Click();
await Delay(500, _ct);
using var clickedCapture = CaptureToRectArea();
var resinLimit = RecognizeOriginalResinLimit(clickedCapture, iconRight);
var fullRecoveryTime = RecognizeFullRecoveryTime(clickedCapture, iconLeft, iconBottom);
var missingResin = (int)Math.Ceiling(fullRecoveryTime.TotalSeconds / OriginalResinRecoveryInterval.TotalSeconds);
if (missingResin > resinLimit)
{
throw new InvalidOperationException($"计算缺失树脂 {missingResin} 超过树脂上限 {resinLimit}");
}
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)
{View on GitHub (pinned to a7cb36712d)
Solutions
- 在 RecognizeOriginalResinInfoFromBigMap 外层已有 catch(行 282)做兜底,确认该兜底生效;将本次失败计入日志后让领奖界面逻辑接管,不要直接中止整个任务。
- 增加树脂上限识别的鲁棒性:当 digits 同时含 '/' 时优先按 '/' 拆分取右段作为 limit,而非盲目取最后三位。
- 对 fullRecoveryTime 做合理性校验(如 > 24h 则判定 OCR 异常并重试一次截图)。
- 校准 countRect 偏移(resinIconRight + ScaleX(25))与图标模板,确保区域覆盖 '当前/上限' 整段文本。
Example fix
// before
var missingResin = (int)Math.Ceiling(fullRecoveryTime.TotalSeconds / OriginalResinRecoveryInterval.TotalSeconds);
if (missingResin > resinLimit)
{
throw new InvalidOperationException($"计算缺失树脂 {missingResin} 超过树脂上限 {resinLimit}");
}
// after
var missingResin = (int)Math.Ceiling(fullRecoveryTime.TotalSeconds / OriginalResinRecoveryInterval.TotalSeconds);
if (missingResin > resinLimit)
{
_logger.LogWarning("{Name}:缺失树脂 {Missing} 超过上限 {Limit},判定为 OCR 异常并跳过预检", Name, missingResin, resinLimit);
throw new InvalidOperationException($"计算缺失树脂 {missingResin} 超过树脂上限 {resinLimit}");
} Defensive patterns
Strategy: validation
Validate before calling
// 在 RecognizeOriginalResinInfoFromBigMap 内、抛出前校验恢复时间合理性
var maxPlausibleRecovery = TimeSpan.FromHours(24);
if (fullRecoveryTime > maxPlausibleRecovery)
{
throw new FormatException($"恢复时间 {fullRecoveryTime} 超出合理范围,疑似 OCR 异常");
}
// resinLimit 来自 RecognizeOriginalResinLimit,已保证 >0;这里只兜底上限合理性
if (resinLimit is < 60 or > 200)
{
_logger.LogWarning("{Name}:树脂上限 {Limit} 异常,跳过预检", Name, resinLimit);
throw new FormatException($"树脂上限 {resinLimit} 超出常见范围");
} Try / catch
// 调用方(PreCheckResin 等)已用 catch (Exception e) when (e is not OperationCanceledException) 兜底, // 将树脂预检失败降级为返回 null,由领奖界面逻辑接管。保持该兜底即可。
Prevention
- 对 OCR 派生值(恢复时间、上限)做范围合理性校验后再做一致性比较。
- 保留外层 catch 将预检失败降级,不要让预检失败中止整个 Boss 任务。
- 在 debug 日志输出 OCR 原文,便于定位是时间还是上限读错。
When it happens
Trigger: 全部恢复时间被 OCR 读得过大(例如把其他界面文本里的时间误识别为恢复时间),或树脂上限被读得过小(例如 '120/160' 只识别到 '120',limitText 取最后三位得到 120 而非 160),导致 ceil(recovery/480) 超过 resinLimit。
Common situations: 大地图右上角树脂弹窗未完全展开就截图;OCR 区域偏移导致 limit 段丢失;游戏 UI 文案/字号变化使 'XXX/160' 被截断;图标模板定位漂移使 iconRight 偏移、countRect 落在错误位置。
Related errors
AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13).
Data as JSON: /api/errors/6eb33c52b4cb575e.
Report an issue: GitHub.