{"record":{"id":"953afb997b286d4f","repo":"babalae/better-genshin-impact","slug":"error-953afb","errorCode":null,"errorMessage":"未检测到合法角色卡片。","messagePattern":"未检测到合法角色卡片。","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterSelectionHelper.cs","lineNumber":244,"sourceCode":"            for (var attempt = 1; attempt <= EmptyDetectionRetryCount; attempt++)\n            {\n                using var capture = CaptureToRectArea();\n                using var gridRegion = capture.DeriveCrop(gridRoi);\n                var cards = DetectCharacterCards(\n                    gridRegion.SrcMat, assetScale, out var rejectedCount, out var connectedComponentCount);\n                logger.LogDebug(\n                    \"角色养成识别：白色底栏连通域 {ConnectedComponentCount} 个，生成 {CardCount} 个合法卡片，边界丢弃 {RejectedCount} 个（第 {Attempt}/{RetryCount} 次）\",\n                    connectedComponentCount, cards.Count, rejectedCount, attempt, EmptyDetectionRetryCount);\n\n                if (cards.Count == 0)\n                {\n                    if (attempt < EmptyDetectionRetryCount)\n                    {\n                        await Delay(200, ct);\n                        continue;\n                    }\n\n                    throw new InvalidOperationException(\"未检测到合法角色卡片。\");\n                }\n\n                foreach (var card in cards.OrderBy(card => card.CardRect.Y).ThenBy(card => card.CardRect.X))\n                {\n                    using var cardRegion = gridRegion.DeriveCrop(card.CardRect);\n                    using var avatar = gridRegion.SrcMat.SubMat(card.AvatarRect);\n                    using var element = gridRegion.SrcMat.SubMat(card.ElementRect);\n                    var candidate = recognizer.Recognize(avatar, element, target.RecognizeElementType);\n                    logger.LogDebug(\"角色养成识别：识别头像 {CharacterName}，元素={ElementType}，score={Score:0.000}\",\n                        candidate.CharacterName, candidate.ElementType, candidate.Score);\n                    if (target.Matches(candidate.CharacterName) && candidate.Score >= MatchThreshold)\n                    {\n                        cardRegion.Click();\n                        await Delay(300, ct);\n                        return candidate;\n                    }\n                }\n","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterSelectionHelper.cs#L226-L262","documentation":"`FindAndClickAvatar` runs `DetectCharacterCards` (white-bar connected-component detection) up to `EmptyDetectionRetryCount` (3) times per grid page. If no valid card is produced on all three attempts it throws, because the avatar model cannot run without candidate cards. This usually means the grid ROI doesn't actually contain the character list (wrong screen, overlay, or detection threshold).","triggerScenarios":"The grid ROI (`GridRoi1080 = (40,76,641,897)`) covers an empty/non-list area; the character list panel failed to open; an overlay (notification, toast) covers the grid; detection thresholds reject all connected components; resolution mismatch shrinks the effective ROI.","commonSituations":"State machine thinks it's on the character list but isn't (filter panel still open, animation in progress); capture scale wrong so card sizes fall outside the detector; UI theme/event overlay changing the white-bar appearance.","solutions":["Confirm the task is actually on the character list screen when this handler runs (fix upstream state detection).","Verify capture resolution and `_assetScale` match the 1080p-based grid ROI and card-size constants.","Tune `FixedSizeGridCardDetector` thresholds if the white-bar styling changed.","Increase `EmptyDetectionRetryCount` and the inter-retry delay if the panel opens slowly."],"exampleFix":"// before: handler runs while filter panel still open → no cards\n// after: strengthen IsCharacterList detector so FindAndClickAvatar only runs on the real list\nif (!CharacterSelectionHelper.IsFilterPanel(capture, scale)) { /* proceed */ }","handlingStrategy":"retry","validationCode":"// Ensure FindAndClickAvatar only runs on the real character list:\nif (!IsCharacterList(capture) || CharacterSelectionHelper.IsFilterPanel(capture, scale))\n    return StateHandlerResult.Wait;","typeGuard":null,"tryCatchPattern":"try { await FindAndClickAvatar(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"未检测到合法角色卡片\"))\n{ /* verify screen state, capture scale, and card detector thresholds */ }","preventionTips":["Strengthen IsCharacterList detection so the handler only runs on the real list.","Verify capture resolution/_assetScale match the 1080p grid ROI and card-size constants.","Tune FixedSizeGridCardDetector thresholds when the white-bar styling changes."],"tags":["state-machine","card-detection","opencv","grid-roi","character-development"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}