using System.Collections;
using UnityEngine;
using Animancer;
using BaseGames.Core;
using BaseGames.Core.Pool;
namespace BaseGames.Enemies.Abilities
{
///
/// 敌人能力抽象基类(架构 07_EnemyModule §8.4)。
/// 责任:生命周期管理、冷却计时、中断分发。子类只实现 。
///
/// 设计要点:
/// - 单一执行实例:同一能力同时只有一个协程在跑。
/// - 协程内 yield WaitForSeconds 复用 (无 GC)。
/// - 受击/死亡时由 调用 。
///
[DisallowMultipleComponent]
public abstract class EnemyAbilityBase : MonoBehaviour
{
[Header("配置 SO")]
[SerializeField] protected EnemyAbilitySO _config;
// 缓存依赖(Awake 填入,热路径无 GetComponent)
protected EnemyBase _enemy;
protected AnimancerComponent _animancer;
protected Transform _transform;
private Coroutine _runner;
private float _cooldownEndTime = -1f;
private bool _isRunning;
// ── 公共状态 ─────────────────────────────────────────────────────
public EnemyAbilitySO Config => _config;
public bool IsRunning => _isRunning;
public AbilityRunState Phase { get; protected set; } = AbilityRunState.Idle;
public float CooldownRemaining => Mathf.Max(0f, _cooldownEndTime - Time.time);
public bool IsOnCooldown => CooldownRemaining > 0f;
/// 能力被外部中断时触发(BD Task / 状态机订阅用)。
public event System.Action Interrupted;
/// BD 任务统一查询入口:当前是否可用(冷却完毕且未执行中)。
public virtual bool CanUse => !_isRunning && !IsOnCooldown && _enemy != null && _enemy.IsAlive;
protected virtual void Awake()
{
_enemy = GetComponentInParent();
_animancer = _enemy != null ? _enemy.Animancer : GetComponentInParent();
_transform = transform;
if (_enemy == null)
Debug.LogError($"[EnemyAbilityBase] {GetType().Name} 找不到 EnemyBase。", this);
if (_animancer == null)
Debug.LogWarning($"[EnemyAbilityBase] {GetType().Name} 找不到 AnimancerComponent,动画能力将无法播放动画。", this);
}
protected virtual void OnDisable()
{
if (_isRunning) Interrupt(InterruptReason.ExternalRequest);
}
// ── 执行 ─────────────────────────────────────────────────────────
///
/// 启动能力。重复调用、冷却中或已运行将返回 false。
/// 若 非空,会先中断同组其他能力(互斥)。
///
public bool Execute()
{
if (!CanUse) return false;
// 互斥组:启动前中断同组正在运行的其他能力
if (_config != null && !string.IsNullOrEmpty(_config.exclusionGroup))
_enemy?.Abilities.InterruptGroup(_config.exclusionGroup, InterruptReason.ExternalRequest);
_runner = StartCoroutine(RunInternal());
return true;
}
///
/// 强制启动能力,忽略冷却检查(连段语义:外部组合技调用子能力时使用)。
/// 若能力正在运行则先中断再重启。
///
public bool ForceExecute()
{
if (_enemy == null || !_enemy.IsAlive) return false;
if (_isRunning) Interrupt(InterruptReason.ExternalRequest);
_runner = StartCoroutine(RunInternal());
return true;
}
private IEnumerator RunInternal()
{
_isRunning = true;
Phase = AbilityRunState.Telegraph;
try
{
if (_config != null && _config.telegraphDuration > 0f)
yield return TelegraphRoutine();
Phase = AbilityRunState.Windup;
yield return ExecuteCoroutine();
Phase = AbilityRunState.Recovery;
}
finally
{
_isRunning = false;
_runner = null;
_cooldownEndTime = Time.time + (_config != null ? _config.cooldown : 0f);
if (Phase != AbilityRunState.Interrupted) Phase = AbilityRunState.Idle;
OnAbilityEnded();
}
}
/// 子类实现:能力主体。可分多段、含 HitBox 激活/弹幕生成/物理推进等。
protected abstract IEnumerator ExecuteCoroutine();
/// 预警阶段(默认生成 VFX 后等待 telegraphDuration)。子类可重写。
protected virtual IEnumerator TelegraphRoutine()
{
if (!string.IsNullOrEmpty(_config.telegraphVfxKey))
{
var pool = ServiceLocator.GetOrDefault();
pool?.Spawn(_config.telegraphVfxKey, _transform.position, Quaternion.identity);
}
yield return EnemyAbilityWaits.Get(_config.telegraphDuration);
}
/// 能力结束钩子(被中断或正常结束都会调用)。
protected virtual void OnAbilityEnded() { }
/// 中断当前执行。冷却仍会按配置计入。
public void Interrupt(InterruptReason reason)
{
if (!_isRunning) return;
if (_config != null)
{
if (reason == InterruptReason.Hurt && !_config.interruptOnHurt) return;
if (reason == InterruptReason.Stagger && !_config.interruptOnStagger) return;
}
if (_runner != null) StopCoroutine(_runner);
_runner = null;
_isRunning = false;
Phase = AbilityRunState.Interrupted;
OnInterrupted(reason);
Interrupted?.Invoke(reason);
OnAbilityEnded();
_cooldownEndTime = Time.time + (_config != null ? _config.cooldown * 0.5f : 0f);
}
protected virtual void OnInterrupted(InterruptReason reason) { }
/// 子类辅助:朝向目标(写入输入信号,下一 FixedUpdate 由 EnemyMovement 消费)。
protected void FaceTarget(Transform target)
{
if (target == null || _enemy == null) return;
_enemy.FaceTarget(target.position);
}
}
/// WaitForSeconds 池(架构 §10 GC 优化)。能力协程统一通过此获取等待指令。
internal static class EnemyAbilityWaits
{
private const int MaxCacheSize = 64;
private static readonly System.Collections.Generic.Dictionary _cache
= new System.Collections.Generic.Dictionary(32);
public static WaitForSeconds Get(float seconds)
{
if (seconds <= 0f) return null;
if (!_cache.TryGetValue(seconds, out var w))
{
if (_cache.Count < MaxCacheSize)
{
w = new WaitForSeconds(seconds);
_cache[seconds] = w;
}
else
{
return new WaitForSeconds(seconds);
}
}
return w;
}
}
}