{"record":{"id":"85e23b713bd18093","repo":"babalae/better-genshin-impact","slug":"error-85e23b","errorCode":null,"errorMessage":"切换角色：未指定角色或同一实际角色被指定到多个槽位","messagePattern":"切换角色：未指定角色或同一实际角色被指定到多个槽位","errorType":"exception","errorClass":"PartySetupFailedException","httpStatus":null,"severity":"warning","filePath":"BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs","lineNumber":226,"sourceCode":"    /// 3 人联机时 1P 可操作 1、2 号槽位，2P 可操作 3 号槽位，3P 可操作 4 号槽位；\n    /// 4 人联机时各玩家可操作与玩家编号相同的槽位。当前玩家不可操作的槽位参数会被忽略。\n    /// </remarks>\n    public async Task<bool> Start(\n        string slot1,\n        string slot2,\n        string slot3,\n        string slot4,\n        bool usePhysicalSlots,\n        CancellationToken ct)\n    {\n        Initialize(ct, SwitchCharacterState.Unknown);\n        var page = new BvPage(ct);\n        string[] slots = [slot1, slot2, slot3, slot4];\n\n        var roles = ParseRoles(slots);\n        if (roles.Count == 0 || HasConflictingRoleTargets(roles))\n        {\n            throw new PartySetupFailedException(\"切换角色：未指定角色或同一实际角色被指定到多个槽位\");\n        }\n\n        ResetWorkflow(roles, usePhysicalSlots);\n        using var recognizer = new AvatarGridIconRecognizer();\n        _recognizer = recognizer;\n\n        try\n        {\n            await RunStateMachineUntil(page, SwitchCharacterState.Completed);\n            return true;\n        }\n        finally\n        {\n            _recognizer = null;\n        }\n    }\n\n    /// <summary>","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs#L208-L244","documentation":"Thrown by SwitchCharacterStateMachineTask.Start when ParseRoles yields zero target roles, or when HasConflictingRoleTargets detects that two slots resolve to the same underlying character (overlap in ConflictNames). It is an input-validation guard before any UI work begins.","triggerScenarios":"slots = [slot1..slot4]; after trimming, no non-empty names remain (roles.Count == 0), OR two roles share a ConflictNames entry — e.g. slot1='空' and slot2='荧' both map to the Traveler whose ConflictNames are [PlayerBoyName, PlayerGirlName], so Intersect is non-empty.","commonSituations":"Caller passed all-empty/whitespace slots; caller assigned the Traveler (or a '空'/'荧' alias pair) to two slots; an alias resolves (via AvatarAliasToStandardName) to the same standard name across slots; a misconfigured combat avatar map aliases two names to one character.","solutions":["Ensure at least one slot is a non-empty role name.","Do not place the Traveler (空/荧/旅行者) in more than one slot — they are one underlying character.","Validate slots up front: distinct standard names, at least one non-empty.","Check AvatarAliasToStandardName / CombatAvatarMap for alias collisions if a custom alias set is configured."],"exampleFix":"// before\nvar roles = ParseRoles(slots);\nif (roles.Count == 0 || HasConflictingRoleTargets(roles))\n{\n    throw new PartySetupFailedException(\"切换角色：未指定角色或同一实际角色被指定到多个槽位\");\n}\n\n// after: report which condition failed for faster diagnosis\nvar roles = ParseRoles(slots);\nif (roles.Count == 0)\n    throw new PartySetupFailedException(\"切换角色：未指定任何角色\");\nif (HasConflictingRoleTargets(roles))\n    throw new PartySetupFailedException(\"切换角色：同一实际角色被指定到多个槽位\");","handlingStrategy":"validation","validationCode":"string[] slots = [slot1, slot2, slot3, slot4];\nvar names = slots.Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList();\nif (names.Count == 0)\n    throw new ArgumentException(\"至少需要指定一个角色槽位\");\n// reject Traveler placed in two slots\nvar travelerCount = slots.Count(s => ToConfiguredAvatarName(s.Trim()) == TravelerAliasName);\nif (travelerCount > 1)\n    throw new ArgumentException(\"旅行者只能占据一个槽位\");","typeGuard":"static bool IsValidPartySetup(string s1, string s2, string s3, string s4)\n{\n    var names = new[] { s1, s2, s3, s4 }.Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList();\n    return names.Count > 0 && names.Distinct().Count() == names.Count;\n}","tryCatchPattern":"null","preventionTips":["Never place the Traveler (空/荧/旅行者) in more than one slot.","Pass at least one non-empty slot.","Validate distinct resolved standard names before calling Start."],"tags":["party-setup","validation","input","state-machine"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}