{"record":{"id":"143b464c340160d4","repo":"babalae/better-genshin-impact","slug":"error-143b46","errorCode":null,"errorMessage":"未能完整识别普通攻击、元素战技和元素爆发三个天赋。","messagePattern":"未能完整识别普通攻击、元素战技和元素爆发三个天赋。","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterDevelopmentTask.cs","lineNumber":820,"sourceCode":"        var (type, level, hasBonus) = await ReadTalentDetailWithRetry();\n\n        if (!_readTalentTypes.Add(type))\n        {\n            return StateHandlerResult.Retry;\n        }\n\n        ApplyTalentResult(CurrentResult, type, level, hasBonus);\n\n        _talentIndex++;\n        if (_talentIndex < _talentPoints.Count)\n        {\n            _workflowState = CharacterDevelopmentState.OpenTalent;\n        }\n        else\n        {\n            if (!_readTalentTypes.SetEquals([AttackTalentType, SkillTalentType, BurstTalentType]))\n            {\n                throw new InvalidOperationException(\"未能完整识别普通攻击、元素战技和元素爆发三个天赋。\");\n            }\n\n            Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_ESCAPE);\n            _workflowState = CharacterDevelopmentState.SwitchCategory;\n        }\n\n        return StateHandlerResult.Success;\n    }\n\n    [StateHandler(CharacterDevelopmentState.ReturnMainUi, RetryTimeout = 15000, RetryInterval = 500, TransitionTimeout = 7000)]\n    private async Task<StateHandlerResult> HandleReturnMainUi(BvPage page)\n    {\n        await _returnMainUiTask.Start(_ct);\n        _workflowState = CharacterDevelopmentState.Completed;\n        return StateHandlerResult.Success;\n    }\n\n    #endregion","sourceCodeStart":802,"sourceCodeEnd":838,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterDevelopmentTask.cs#L802-L838","documentation":"After iterating all talent points, the set of recognized talent types must equal exactly {普通攻击, 元素战技, 元素爆发}. If OCR/normalization missed one type or duplicated another, the trio is incomplete and the result would be wrong, so the handler throws rather than return partial data.","triggerScenarios":"`NormalizeTalentType` returned empty for one of the three points (OCR failed to read the talent name); a talent point's OCR resolved to the same type twice; `TryFindTalentPoints` picked a non-talent 'Lv' region.","commonSituations":"Low OCR confidence on the talent title region; UI animation/partial render during capture; a layout change shifting which 'Lv' text gets picked.","solutions":["Improve capture timing (wait for the talent detail panel to fully render before reading).","Adjust the talent-title OCR ROI or preprocessing if the UI layout changed.","Retry the talent sub-flow once on failure before aborting the whole character."],"exampleFix":"// before\nif (!_readTalentTypes.SetEquals([AttackTalentType, SkillTalentType, BurstTalentType]))\n    throw new InvalidOperationException(...);\n\n// after: retry the talent flow once, then fail\ncatch (InvalidOperationException) when (talentRetries++ < 1) { _workflowState = FindTalentEntries; return StateHandlerResult.Success; }","handlingStrategy":"retry","validationCode":"// Before declaring success, the handler already checks completeness;\n// reduce transient OCR failures by ensuring the panel is fully rendered.","typeGuard":null,"tryCatchPattern":"try { /* talent read loop */ }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"未能完整识别\"))\n{ /* retry the FindTalentEntries→OpenTalent→ReadTalent flow once */ }","preventionTips":["Wait for the talent detail panel to finish its open animation before reading.","Keep talent-title ROIs aligned with the current layout.","Retry the talent sub-flow once before aborting the character."],"tags":["state-machine","ocr","talent","data-completeness","character-development"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}