using BetterGenshinImpact.GameTask.Model.Area;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace BetterGenshinImpact.GameTask.Common.StateMachine;
using static TaskControl;
///
/// 状态处理器返回结果,决定状态机如何处理当前状态
///
public enum StateHandlerResult
{
///
/// 成功:操作完成,状态机自动等待邻接状态转换
///
Success,
///
/// 等待:可预期的等待,状态机继续循环重新检测
///
Wait,
///
/// 重试:意外失败,状态机重试直到超过最大次数
///
Retry,
///
/// 失败:无法恢复的错误,状态机抛出异常
///
Fail
}
///
/// 状态处理器委托
///
public delegate Task StateHandlerDelegate(TContext context);
///
/// 有限状态机基类
///
/// 为什么使用状态机:
/// - 游戏自动化涉及大量界面切换,传统的 if-else 难以维护
/// - 状态机将每个界面抽象为状态,状态转换关系清晰可追踪
/// - 闭环确认机制确保操作真正生效,而不是盲目点击
///
/// 为什么使用注册模式:
/// - 将"状态图"与"状态处理逻辑"分离,便于修改和调试
/// - 状态图在一处定义,避免分散在代码各处难以维护
/// - 检测器注册使状态机能自动选择最优检测策略
///
/// 为什么 Handler 返回 StateHandlerResult:
/// - 状态机需要知道操作结果来决定下一步行为
/// - Success/Wait/Retry/Fail 四种结果覆盖所有场景
/// - 状态机统一处理等待和重试逻辑,Handler 只关注操作本身
///
/// 详细使用文档见 StateMachine/README.md
///
public abstract class StateMachineBase where TState : struct, Enum
{
///
/// 由子类实现以提供 Logger
///
protected abstract ILogger Logger { get; }
protected CancellationToken _ct;
///
/// 当前状态
///
public TState CurrentState { get; protected set; }
///
/// 状态处理器注册表
///
private readonly Dictionary> _stateHandlers = new();
///
/// 状态检测器注册表 - 每个状态对应一个检测函数
/// 检测函数接收截图,返回 true 表示匹配
///
private readonly Dictionary> _stateDetectors = new();
///
/// 状态邻接关系表 - 记录每个状态可能转换到的下一个状态
/// 用于优化状态检测:只检测当前状态可能到达的状态
///
private readonly Dictionary _stateTransitions = new();
///
/// 未知状态处理器
///
private StateHandlerDelegate? _unknownStateHandler;
///
/// 默认状态检测间隔(毫秒)
///
protected virtual int DefaultDetectionInterval => 300;
///
/// 默认状态转换超时(毫秒)
///
protected virtual int DefaultTransitionTimeout => 10000;
///
/// 默认最大重试次数
///
protected virtual int DefaultMaxRetries => 3;
///
/// 状态机循环间隔(毫秒)
///
protected virtual int StateMachineLoopInterval => 200;
#region 状态处理器注册
///
/// 注册状态处理器
///
/// 状态
/// 处理器
protected void RegisterStateHandler(TState state, StateHandlerDelegate handler)
{
_stateHandlers[state] = handler;
}
///
/// 注册多个状态处理器
///
protected void RegisterStateHandlers(params (TState state, StateHandlerDelegate handler)[] handlers)
{
foreach (var (state, handler) in handlers)
{
_stateHandlers[state] = handler;
}
}
///
/// 注册未知状态处理器(可选)
/// 当检测到 Unknown 状态或未注册处理器的状态时调用
///
protected void RegisterUnknownStateHandler(StateHandlerDelegate handler)
{
_unknownStateHandler = handler;
}
#endregion
#region 状态转换注册【推荐 - 有限状态机核心】
///
/// 注册状态转换关系【推荐】
/// 这是有限状态机的核心 - 定义每个状态可能转换到的下一个状态
///
/// 优势:
/// 1. 状态检测只检测邻接状态,大幅提升性能
/// 2. 状态流程清晰可见,便于维护
/// 3. 自动排除不可能的状态转换
///
/// 源状态
/// 可能的目标状态数组(邻接状态)
protected void RegisterStateTransition(TState fromState, params TState[] toStates)
{
_stateTransitions[fromState] = toStates;
}
///
/// 批量注册状态转换关系【推荐】
///
protected void RegisterStateTransitions(params (TState from, TState[] to)[] transitions)
{
foreach (var (from, to) in transitions)
{
_stateTransitions[from] = to;
}
}
///
/// 获取当前状态可能转换到的状态列表
/// 如果未注册,返回 null(表示需要检测所有状态)
///
protected TState[]? GetPossibleNextStates()
{
return _stateTransitions.TryGetValue(CurrentState, out var states) ? states : null;
}
#endregion
#region 状态机运行
///
/// 初始化状态机
///
protected void Initialize(CancellationToken ct, TState initialState = default)
{
_ct = ct;
CurrentState = initialState;
}
///
/// 运行状态机直到达到任一目标状态
/// 这是核心方法,封装了 switch-case 逻辑
///
/// 上下文对象
/// 目标状态(到达任一即停止)
/// 最大迭代次数(防止无限循环)
/// 单个状态最大重试次数(Retry 返回值触发)
protected async Task RunStateMachineUntil(TContext context, TState[] targetStates, int maxIterations = 1000, int maxRetries = 5)
{
Logger.LogInformation("========== 状态机启动,目标状态:{Targets} ==========",
string.Join(", ", targetStates));
int retryCount = 0;
TState lastRetryState = default;
for (int iteration = 0; iteration < maxIterations; iteration++)
{
_ct.ThrowIfCancellationRequested();
// 检测当前实际状态
RefreshCurrentState();
// 状态变化时重置重试计数
if (!EqualityComparer.Default.Equals(CurrentState, lastRetryState))
{
retryCount = 0;
lastRetryState = CurrentState;
}
// 检查是否到达目标状态
if (targetStates.Contains(CurrentState))
{
Logger.LogInformation("========== 状态机完成,到达目标状态:{State} ==========", CurrentState);
return;
}
Logger.LogDebug("状态机迭代 {Iteration},当前状态:{State}", iteration, CurrentState);
// 执行状态处理器
if (_stateHandlers.TryGetValue(CurrentState, out var handler))
{
var result = await handler(context);
switch (result)
{
case StateHandlerResult.Success:
// 成功:等待邻接状态转换
retryCount = 0; // 重置重试计数
var nextState = await EnsureNextStateTransition();
if (EqualityComparer.Default.Equals(nextState, default))
{
Logger.LogWarning("等待邻接状态转换超时");
}
break;
case StateHandlerResult.Wait:
// 可预期的等待:继续循环,重新检测状态
Logger.LogDebug("Handler 返回 Wait,状态机继续等待");
break;
case StateHandlerResult.Retry:
// 意外失败重试:检查重试次数
retryCount++;
if (retryCount >= maxRetries)
{
Logger.LogError("状态 {State} 重试次数达到上限 {Max},转为失败", CurrentState, maxRetries);
throw new InvalidOperationException($"状态 {CurrentState} 重试次数达到上限 {maxRetries}");
}
Logger.LogWarning("Handler 返回 Retry,将重试当前状态(第 {Count}/{Max} 次)", retryCount, maxRetries);
break;
case StateHandlerResult.Fail:
// 失败:抛出异常
throw new InvalidOperationException($"状态 {CurrentState} 的 Handler 返回失败");
}
}
else if (!EqualityComparer.Default.Equals(CurrentState, default) && _unknownStateHandler != null)
{
Logger.LogWarning("状态 {State} 无注册处理器,使用未知状态处理器", CurrentState);
await _unknownStateHandler(context);
}
else if (_unknownStateHandler != null)
{
await _unknownStateHandler(context);
}
else
{
Logger.LogWarning("状态 {State} 无注册处理器,跳过", CurrentState);
}
await Delay(StateMachineLoopInterval, _ct);
}
Logger.LogWarning("状态机达到最大迭代次数 {Max},强制退出", maxIterations);
}
///
/// 运行状态机直到达到单个目标状态
///
protected Task RunStateMachineUntil(TContext context, TState targetState, int maxIterations = 1000)
{
return RunStateMachineUntil(context, new[] { targetState }, maxIterations);
}
#endregion
#region 状态检测器注册
///
/// 注册状态检测器
/// 检测器接收截图区域,返回 true 表示当前处于该状态
///
/// 状态
/// 检测函数,接收 ImageRegion,返回 true 表示匹配
protected void RegisterStateDetector(TState state, Func detector)
{
_stateDetectors[state] = detector;
}
///
/// 批量注册状态检测器【推荐】
/// 注意:检测顺序影响性能,建议将快速检测的状态放在前面
///
protected void RegisterStateDetectors(params (TState state, Func detector)[] detectors)
{
foreach (var (state, detector) in detectors)
{
_stateDetectors[state] = detector;
}
}
#endregion
#region 核心状态检测方法
///
/// 检测当前UI状态(完整检测)
/// 基于注册的检测器,遍历所有注册的状态检测器
/// 只截图一次,复用给所有检测器
///
/// 检测到的状态,如果都不匹配返回 default
protected TState DetectCurrentState()
{
using var ra = CaptureToRectArea();
foreach (var (state, detector) in _stateDetectors)
{
if (detector(ra))
{
return state;
}
}
return default;
}
///
/// 在候选状态中检测当前状态
/// 只检测 candidateStates 中的状态,跳过其他状态
/// 只截图一次,复用给所有检测器
///
/// 候选状态列表
/// 检测到的状态,如果不在候选列表中则返回 default
protected TState DetectStateAmong(TState[] candidateStates)
{
using var ra = CaptureToRectArea();
foreach (var state in candidateStates)
{
if (_stateDetectors.TryGetValue(state, out var detector) && detector(ra))
{
return state;
}
}
return default;
}
///
/// 更新当前状态(通过检测)
/// 严格模式:只检测邻接状态,不回退到全状态检测
///
protected void RefreshCurrentState()
{
// 如果当前状态有注册邻接关系,只检测可能的下一个状态
var possibleStates = GetPossibleNextStates();
TState detected;
if (possibleStates != null && possibleStates.Length > 0)
{
// 严格 FSM:只检测邻接状态
detected = DetectStateAmong(possibleStates);
}
else
{
// 没有邻接状态定义时(如初始状态),回退到全状态检测
detected = DetectCurrentState();
}
if (!EqualityComparer.Default.Equals(detected, default))
{
CurrentState = detected;
}
}
///
/// 等待状态转换(内部方法)
/// 执行动作后,等待目标状态出现
///
/// 期望的目标状态
/// 超时时间(毫秒)
/// 是否成功转换到目标状态
private async Task EnsureStateTransition(TState expectedState, int? timeoutMs = null)
{
var timeout = timeoutMs ?? DefaultTransitionTimeout;
var stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < timeout)
{
_ct.ThrowIfCancellationRequested();
// 只检测期望的状态
var currentState = DetectStateAmong([expectedState]);
if (EqualityComparer.Default.Equals(currentState, expectedState))
{
CurrentState = currentState;
Logger.LogDebug("状态转换成功:{State}", expectedState);
return true;
}
await Delay(DefaultDetectionInterval, _ct);
}
Logger.LogWarning("状态转换超时,期望:{Expected},当前:{Current}", expectedState, DetectCurrentState());
return false;
}
///
/// 等待任一目标状态出现(内部方法)
///
/// 可接受的目标状态数组
/// 超时时间(毫秒)
/// 转换到的状态,如果超时则返回 default
private async Task EnsureAnyStateTransition(TState[] expectedStates, int? timeoutMs = null)
{
var timeout = timeoutMs ?? DefaultTransitionTimeout;
var stopwatch = Stopwatch.StartNew();
while (stopwatch.ElapsedMilliseconds < timeout)
{
_ct.ThrowIfCancellationRequested();
// 只检测期望的状态
var currentState = DetectStateAmong(expectedStates);
if (expectedStates.Contains(currentState))
{
CurrentState = currentState;
Logger.LogDebug("状态转换成功:{State}", currentState);
return currentState;
}
await Delay(DefaultDetectionInterval, _ct);
}
Logger.LogWarning("状态转换超时,期望任一:{Expected},当前:{Current}",
string.Join(",", expectedStates), DetectCurrentState());
return default;
}
///
/// 等待转换到邻接状态(使用状态转换关系)
/// 自动使用当前状态注册的邻接状态作为期望状态
///
/// 超时时间(毫秒)
/// 转换到的状态,如果没有注册邻接状态则返回 default
protected async Task EnsureNextStateTransition(int? timeoutMs = null)
{
var possibleStates = GetPossibleNextStates();
if (possibleStates == null || possibleStates.Length == 0)
{
Logger.LogWarning("当前状态 {State} 没有注册邻接状态,无法确定期望状态", CurrentState);
return default;
}
return await EnsureAnyStateTransition(possibleStates, timeoutMs);
}
#endregion
}