{"record":{"id":"f0e2e94e6833f2c4","repo":"babalae/better-genshin-impact","slug":"error-f0e2e9","errorCode":null,"errorMessage":"角色名不能为空。","messagePattern":"角色名不能为空。","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterSelectionHelper.cs","lineNumber":64,"sourceCode":"/// </summary>\ninternal sealed record CharacterCardRect(Rect CardRect, Rect AvatarRect, Rect ElementRect);\n\n/// <summary>\n/// 角色列表筛选、卡片定位和头像匹配的专用实现，不与旧角色切换网格共享。\n/// </summary>\ninternal static class CharacterSelectionHelper\n{\n    /// <summary>头像 embedding 余弦相似度的最低接受分数。</summary>\n    internal const double MatchThreshold = 0.7;\n    private const int EmptyDetectionRetryCount = 3;\n    private static readonly Rect GridRoi1080 = new(40, 76, 641, 897);\n\n    public static CharacterSelectionTarget CreateTarget(string name)\n    {\n        var normalizedName = name?.Trim() ?? string.Empty;\n        if (string.IsNullOrWhiteSpace(normalizedName))\n        {\n            throw new ArgumentException(\"角色名不能为空。\", nameof(name));\n        }\n\n        var standardName = ToConfiguredAvatarName(normalizedName);\n        if (standardName == \"旅行者\")\n        {\n            return new CharacterSelectionTarget(\n                \"旅行者\",\n                [\"空\", \"荧\"],\n                true,\n                \"单手剑\",\n                true,\n                true);\n        }\n\n        if (standardName is \"空\" or \"荧\")\n        {\n            return new CharacterSelectionTarget(\n                standardName,","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterSelectionHelper.cs#L46-L82","documentation":"`CharacterSelectionHelper.CreateTarget` rejects a null/empty/whitespace character name with `ArgumentException`. A target with no name cannot be matched against the avatar grid or configured aliases, so it fails fast at target construction (called from the state-machine constructor for every name in the list).","triggerScenarios":"Passing `null`, `\"\"`, `\"   \"`, or a name that trims to empty to `CreateTarget`; a character list containing a blank entry; `GetCharacter(null)` where normalization yields empty.","commonSituations":"User input not trimmed/validated before building the character list; a config file with an empty name field; a stray empty string in a comma-split list.","solutions":["Trim and validate each character name before adding it to the list passed to the task.","Filter out empty entries when splitting user-provided name lists.","In `GetCharacter`, ensure `NormalizeCharacterName` never yields an empty string (or throw a clearer error there)."],"exampleFix":"// before\nvar names = userInput.Split(';'); // may contain \"\"\nvar targets = names.Select(CharacterSelectionHelper.CreateTarget); // throws\n\n// after\nvar names = userInput.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);\nvar targets = names.Select(CharacterSelectionHelper.CreateTarget);","handlingStrategy":"validation","validationCode":"var name = raw?.Trim() ?? string.Empty;\nif (string.IsNullOrWhiteSpace(name))\n    throw new ArgumentException(\"角色名不能为空。\", nameof(raw));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trim and validate each character name at the UI/script boundary.","Split user name lists with RemoveEmptyEntries | TrimEntries.","Ensure NormalizeCharacterName never yields an empty string."],"tags":["argument-validation","character-name","character-development"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}