babalae/better-genshin-impact · error · InvalidOperationException

武器名称 OCR 结果为空。

Error message

武器名称 OCR 结果为空。

What it means

`WeaponNameMatcher.MatchClosest` trims the OCR text and throws `InvalidOperationException` if it is null/empty/whitespace. Matching an empty string against the weapon table is meaningless (every distance equals the name length), so it refuses rather than return a garbage 'nearest'. The public `Match` delegates here after the lazy name table loads.

Source

Thrown at BetterGenshinImpact/GameTask/CharacterDevelopment/WeaponNameMatcher.cs:51

    private static readonly Lazy<IReadOnlyList<string>> WeaponNames = new(LoadWeaponNames);

    /// <summary>
    /// 将 OCR 文本匹配为标准武器名称。名称表延迟加载且在进程内复用。
    /// </summary>
    public static WeaponNameMatch Match(string ocrText)
    {
        return MatchClosest(ocrText, WeaponNames.Value);
    }

    /// <summary>
    /// 在给定名称表中选择编辑距离最小的名称,并判断该候选是否足够可信。
    /// </summary>
    internal static WeaponNameMatch MatchClosest(string ocrText, IReadOnlyList<string> weaponNames)
    {
        var normalizedText = ocrText.Trim();
        if (string.IsNullOrWhiteSpace(normalizedText))
        {
            throw new InvalidOperationException("武器名称 OCR 结果为空。");
        }

        if (weaponNames.Count == 0)
        {
            throw new InvalidDataException("武器名称表中没有可用的武器。");
        }

        var candidates = weaponNames
            .Select(name =>
            {
                var distance = LevenshteinDistance(normalizedText, name);
                var maximumLength = Math.Max(normalizedText.Length, name.Length);
                var similarity = 1d - (double)distance / maximumLength;
                return new WeaponNameMatch(name, distance, similarity, false);
            })
            .OrderBy(match => match.Distance)
            .ThenBy(match => match.Name, StringComparer.Ordinal)
            .Take(2)

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Check `string.IsNullOrWhiteSpace(ocrText)` before calling `Match`, and retry/skip when empty (as `ReadWeaponNameWithRetry` already does).
  2. Ensure the weapon-name ROI actually contains the weapon name line at the current resolution.
  3. In tests, pass a non-empty OCR string or assert the throw explicitly.

Example fix

// before
var match = WeaponNameMatcher.Match(ocrText); // throws if ocrText is empty

// after
if (string.IsNullOrWhiteSpace(ocrText)) { /* retry / skip */ return; }
var match = WeaponNameMatcher.Match(ocrText);
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrWhiteSpace(ocrText))
    return; // or retry; ReadWeaponNameWithRetry already does this
var match = WeaponNameMatcher.Match(ocrText);

Try / catch

try { var m = WeaponNameMatcher.Match(text); }
catch (InvalidOperationException ex) when (ex.Message.Contains("武器名称 OCR 结果为空"))
{ /* ROI captured blank; retry or realign weapon-name ROI */ }

Prevention

When it happens

Trigger: Calling `Match(null)`, `Match("")`, or `Match(" ")`; upstream OCR returning empty for the weapon-name region and that empty value reaching the matcher without a null/empty guard.

Common situations: The weapon-name ROI captured a blank region (misaligned, not yet rendered); a test calls `Match` with empty input; `ReadWeaponNameWithRetry`'s empty-text branch is bypassed by a direct call.

Related errors


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