babalae/better-genshin-impact · error · InvalidOperationException

角色养成识别:当前角色尚未初始化。

Error message

角色养成识别:当前角色尚未初始化。

What it means

Thrown by the `CurrentTarget` property getter when `_currentTarget` is null. `_currentTarget` is populated by `PrepareCharacter(index)` (line 344), which `Start()` calls once at the beginning (line 312) and the state machine calls again when advancing to each subsequent character. It is null before the first `PrepareCharacter` runs and is conceptically reset between characters.

Source

Thrown at BetterGenshinImpact/GameTask/CharacterDevelopment/CharacterDevelopmentTask.cs:258

    private AvatarGridIconRecognizer? _recognizer;
    private int _characterIndex;
    private CharacterSelectionTarget? _currentTarget;
    private CharacterDevelopmentResult? _currentResult;
    private Queue<CharacterDevelopmentCategory> _pendingCategories = new();
    private CharacterDevelopmentCategory _currentCategory;
    private string? _pendingElementType;
    private string? _pendingWeaponType;
    private List<Point> _talentPoints = [];
    private int _talentIndex;
    private readonly HashSet<string> _readTalentTypes = new(StringComparer.Ordinal);

    protected override ILogger Logger => _logger;

    private AvatarGridIconRecognizer Recognizer =>
        _recognizer ?? throw new InvalidOperationException("角色养成识别:头像识别器尚未初始化。");

    private CharacterSelectionTarget CurrentTarget =>
        _currentTarget ?? throw new InvalidOperationException("角色养成识别:当前角色尚未初始化。");

    private CharacterDevelopmentResult CurrentResult =>
        _currentResult ?? throw new InvalidOperationException("角色养成识别:当前结果尚未初始化。");

    public CharacterDevelopmentStateMachineTask(IReadOnlyList<string> characterNames, CharacterDevelopmentCategory categories)
    {
        if (characterNames.Count == 0)
        {
            throw new ArgumentException("至少需要指定一个角色。", nameof(characterNames));
        }

        if (categories == CharacterDevelopmentCategory.None)
        {
            throw new ArgumentException("至少需要指定一个读取分类。", nameof(categories));
        }

        _categories = categories;
        _targets = characterNames.Select(CharacterSelectionHelper.CreateTarget).ToList();

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Enter the task exclusively via `Start()`, which calls `PrepareCharacter(0)` before running the state machine.
  2. Ensure any custom state transitions always go through `PrepareNextCharacter` → `PrepareCharacter` so `_currentTarget` is set before handlers read it.
  3. Avoid reading `CurrentTarget` from code outside the state-machine execution scope.

Example fix

// before
var t = new CharacterDevelopmentStateMachineTask(names, cats);
var name = t.CurrentTarget.Name; // throws

// after
await t.Start(ct); // CurrentTarget is valid only inside Start
Defensive patterns

Strategy: validation

Validate before calling

// CurrentTarget is set by PrepareCharacter, called inside Start().
// Caller code should not read it; rely on the returned results list instead.

Prevention

When it happens

Trigger: Accessing `CurrentTarget` before `Start()` has called `PrepareCharacter(0)`, or invoking a handler/detector that reads `CurrentTarget` outside an active run.

Common situations: Direct handler invocation in tests; a state-handler running before the initial `PrepareCharacter` due to a custom state-machine wiring; reading the property after the run completes.

Related errors


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