babalae/better-genshin-impact · error · PartySetupFailedException

切换角色:点击逻辑槽位 的换下按钮后,未在 秒内确认操作生效

Error message

切换角色:点击逻辑槽位 {logicalSlot} 的换下按钮后,未在 {RemoveConfirmationTimeoutMilliseconds / 1000} 秒内确认操作生效

What it means

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.

Solutions

  1. Increase RemoveConfirmationTimeoutMilliseconds if the game's removal animation is known to be slow.
  2. Verify no blocking dialog appeared after the click (e.g. a 'are you sure' prompt) and dismiss it.
  3. Confirm the ROI Rect1080(382,994,87,51) and IsPartyConfigPage detector match the current game layout.
  4. Lower the poll interval or require a single disappearance instead of two if double-confirm is too strict for this game version.
Defensive patterns

Strategy: retry

Try / catch

try { await switchTask.Start(...); }
catch (PartySetupFailedException ex) when (ex.Message.Contains("确认操作生效"))
{ _logger.LogWarning(ex, "换下操作未生效,建议重试任务"); }

Prevention

When it happens

Trigger: After TryClickText('换下') succeeded, the loop runs until the deadline; consecutiveMissingCount never reaches 2 because ContainsText(capture,'换下',ROI) keeps returning true (or IsPartyConfigPage is false).

Common situations: 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.

Understand the failure class

Related errors


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

Appendix: source

Thrown at BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs:1355

            if (IsPartyConfigPage(capture) &&
                !ContainsText(capture, "换下", Rect1080(382, 994, 87, 51)))
            {
                consecutiveMissingCount++;
                if (consecutiveMissingCount >= 2)
                {
                    _logger.LogDebug("切换角色:已确认逻辑槽位 {Slot} 的换下操作生效", logicalSlot);
                    return;
                }
            }
            else
            {
                consecutiveMissingCount = 0;
            }

            await Delay(150, ct);
        }

        throw new PartySetupFailedException(
            $"切换角色:点击逻辑槽位 {logicalSlot} 的换下按钮后,未在 {RemoveConfirmationTimeoutMilliseconds / 1000} 秒内确认操作生效");
    }

    private async Task<List<TeamSlotSnapshot>> RecognizeTeamSlotsFromCharacterList(
        AvatarGridIconRecognizer recognizer,
        int expectedTeamCount,
        CancellationToken ct)
    {
        ClickFixedTeamSlot(1);
        var listOpened = await NewRetry.WaitForAction(() =>
        {
            using var capture = CaptureToRectArea();
            return IsCharacterList(capture);
        }, ct, 10, 300);
        if (!listOpened)
        {
            throw new PartySetupFailedException("切换角色:点击队伍槽位后未打开角色列表");
        }

View on GitHub (pinned to a7cb36712d)