babalae/better-genshin-impact · critical · PartySetupFailedException

切换角色:无法为 {_multiGamePlayerCount} 人联机的 {_playerIndex}P 生成可控槽位

Error message

切换角色:无法为 {_multiGamePlayerCount} 人联机的 {_playerIndex}P 生成可控槽位

What it means

ConfigureOperableSlots maps the (playerCount, playerIndex) pair to the controllable physical slots via a switch expression covering only the documented co-op configurations. The default arm throws when the pair is outside that set — i.e. an unrecognized or impossible co-op combination that the slot-mapping table cannot handle.

Source

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

        throw new PartySetupFailedException(
            $"切换角色:等待单机图标、联机状态及 top_left 玩家标记超时({timeoutMilliseconds / 1000} 秒),最后结果:{lastResult}");
    }

    private void ConfigureOperableSlots()
    {
        int[] physicalSlots = (_multiGamePlayerCount, _playerIndex) switch
        {
            (1, _) => [1, 2, 3, 4],
            (2, 1) => [1, 2],
            (2, 2) => [3, 4],
            (3, 1) => [1, 2],
            (3, 2) => [3],
            (3, 3) => [4],
            (4, 1) => [1],
            (4, 2) => [2],
            (4, 3) => [3],
            (4, 4) => [4],
            _ => throw new PartySetupFailedException(
                $"切换角色:无法为 {_multiGamePlayerCount} 人联机的 {_playerIndex}P 生成可控槽位")
        };

        _maxControlAvatarCount = physicalSlots.Length;
        _logicalToPhysicalSlot = physicalSlots
            .Select((physical, index) => (Logical: index + 1, Physical: physical))
            .ToDictionary(pair => pair.Logical, pair => pair.Physical);

        _logger.LogInformation("切换角色:{PlayerCount} 人队伍,{PlayerIndex}P 可控物理槽位 {Slots}",
            _multiGamePlayerCount, _playerIndex, string.Join(",", physicalSlots));
    }

    private void EnsureSlotIsOperable(int logicalSlot)
    {
        if (!_logicalToPhysicalSlot.ContainsKey(logicalSlot))
        {
            throw new PartySetupFailedException($"切换角色:{logicalSlot} 号位超出当前账号可操作角色数 {_maxControlAvatarCount}");
        }

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Ensure DetectPlayerIndex succeeds (see error 387) before ConfigureOperableSlots; do not call ConfigureOperableSlots with _playerIndex==0.
  2. Clamp/validate _multiGamePlayerCount to 1..4 and _playerIndex to 1.._multiGamePlayerCount before the switch.
  3. If a new co-op configuration ships, add its case to the switch expression with the correct physical slots.

Example fix

// before
int[] physicalSlots = (_multiGamePlayerCount, _playerIndex) switch { ... };

// after
if (_playerIndex < 1 || _playerIndex > _multiGamePlayerCount || _multiGamePlayerCount is < 1 or > 4)
{
    throw new PartySetupFailedException($"切换角色:无法为 {_multiGamePlayerCount} 人联机的 {_playerIndex}P 生成可控槽位");
}
int[] physicalSlots = (_multiGamePlayerCount, _playerIndex) switch { ... };
Defensive patterns

Strategy: validation

Validate before calling

if (_playerIndex < 1 || _playerIndex > _multiGamePlayerCount || _multiGamePlayerCount is < 1 or > 4)
{
    throw new PartySetupFailedException($"切换角色:无效联机参数 count={_multiGamePlayerCount} index={_playerIndex}");
}

Type guard

static bool IsValidCoopPair(int count, int index)
    => count is >= 1 and <= 4 && index is >= 1 and <= count;

Try / catch

try { await switchTask.Start(...); }
catch (PartySetupFailedException ex) when (ex.Message.Contains("生成可控槽位"))
{ _logger.LogError(ex, "联机参数超出已支持范围,请确认玩家检测正确"); }

Prevention

When it happens

Trigger: (_multiGamePlayerCount, _playerIndex) is none of the listed cases: commonly _playerIndex == 0 (never resolved), _playerIndex > _multiGamePlayerCount, or _multiGamePlayerCount > 4.

Common situations: DetectPlayerIndex left _playerIndex at 0 (detection partially failed then ConfigureOperableSlots ran anyway); a co-op mode with >4 players the code does not model; _multiGamePlayerCount was set from a noisy MultiGameStatus to a value >4; logic invoked ConfigureOperableSlots before player detection completed.

Related errors


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