{"record":{"id":"6a718c3cdf60dbd0","repo":"babalae/better-genshin-impact","slug":"logicalslot-removeconfirm","errorCode":null,"errorMessage":"切换角色：点击逻辑槽位 {logicalSlot} 的换下按钮后，未在 {RemoveConfirmationTimeoutMilliseconds / 1000} 秒内确认操作生效","messagePattern":"切换角色：点击逻辑槽位 (.+?) 的换下按钮后，未在 (.+?) 秒内确认操作生效","errorType":"exception","errorClass":"PartySetupFailedException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs","lineNumber":1355,"sourceCode":"            if (IsPartyConfigPage(capture) &&\n                !ContainsText(capture, \"换下\", Rect1080(382, 994, 87, 51)))\n            {\n                consecutiveMissingCount++;\n                if (consecutiveMissingCount >= 2)\n                {\n                    _logger.LogDebug(\"切换角色：已确认逻辑槽位 {Slot} 的换下操作生效\", logicalSlot);\n                    return;\n                }\n            }\n            else\n            {\n                consecutiveMissingCount = 0;\n            }\n\n            await Delay(150, ct);\n        }\n\n        throw new PartySetupFailedException(\n            $\"切换角色：点击逻辑槽位 {logicalSlot} 的换下按钮后，未在 {RemoveConfirmationTimeoutMilliseconds / 1000} 秒内确认操作生效\");\n    }\n\n    private async Task<List<TeamSlotSnapshot>> RecognizeTeamSlotsFromCharacterList(\n        AvatarGridIconRecognizer recognizer,\n        int expectedTeamCount,\n        CancellationToken ct)\n    {\n        ClickFixedTeamSlot(1);\n        var listOpened = await NewRetry.WaitForAction(() =>\n        {\n            using var capture = CaptureToRectArea();\n            return IsCharacterList(capture);\n        }, ct, 10, 300);\n        if (!listOpened)\n        {\n            throw new PartySetupFailedException(\"切换角色：点击队伍槽位后未打开角色列表\");\n        }","sourceCodeStart":1337,"sourceCodeEnd":1373,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs#L1337-L1373","documentation":"WaitForRoleRemoved polls up to RemoveConfirmationTimeoutMilliseconds (3000ms) for the '换下' text to disappear from the fixed ROI on two consecutive captures after a remove click. If the button never disappears twice, the game did not register/commit the removal and the teardown is aborted.","triggerScenarios":"After TryClickText('换下') succeeded, the loop runs until the deadline; consecutiveMissingCount never reaches 2 because ContainsText(capture,'换下',ROI) keeps returning true (or IsPartyConfigPage is false).","commonSituations":"The remove click landed but the game is lagging/loading; a confirmation dialog appeared blocking the removal; the slot was already empty so the button state is ambiguous; capture scale/ROI mismatch makes '换下' persistently detected; game animation keeps the text visible across the 150ms poll interval.","solutions":["Increase RemoveConfirmationTimeoutMilliseconds if the game's removal animation is known to be slow.","Verify no blocking dialog appeared after the click (e.g. a 'are you sure' prompt) and dismiss it.","Confirm the ROI Rect1080(382,994,87,51) and IsPartyConfigPage detector match the current game layout.","Lower the poll interval or require a single disappearance instead of two if double-confirm is too strict for this game version."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await switchTask.Start(...); }\ncatch (PartySetupFailedException ex) when (ex.Message.Contains(\"确认操作生效\"))\n{ _logger.LogWarning(ex, \"换下操作未生效，建议重试任务\"); }","preventionTips":["Tune RemoveConfirmationTimeoutMilliseconds to the game's removal animation speed.","Ensure no blocking dialog follows the remove click.","Keep the '换下' ROI and IsPartyConfigPage detector current."],"tags":["party-setup","ui-automation","ocr","timeout","fixed-roi","switch-character"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}