using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Animancer;
using BaseGames.Combat;
using BaseGames.Core.Events;
namespace BaseGames.Boss
{
///
/// 挂在 Boss GameObject 上,接收 BossOrchestrator 的指令执行指定 BossSkillSO。
/// 管理 VulnerabilityWindow 计时和 WeakPointSystem 激活。
///
public class BossSkillExecutor : MonoBehaviour
{
[SerializeField] private HitBox[] _hitBoxes;
[SerializeField] private WeakPointSystem _weakPointSystem;
[SerializeField] private AnimancerComponent _animancer;
[SerializeField] private string _bossId;
[SerializeField] private BossSkillEventChannelSO _onBossSkillStarted;
[SerializeField] private BossSkillEventChannelSO _onBossSkillEnded;
/// PlayerController 无 Instance(架构 05 §2),由 Inspector 指定。
[SerializeField] private Transform _playerTransform;
private BossSkillSO _currentSkill;
private bool _isExecuting;
private Coroutine _activeCoroutine;
public bool IsExecuting => _isExecuting;
///
/// 按 float 值复用 WaitForSeconds 实例,消除协程中每次 new WaitForSeconds 的 GC 分配。
/// Domain Reload 禁用时静态缓存跨 PlayMode 会话保留,但 WaitForSeconds 是幂等值对象,
/// 不会引发功能错误;[RuntimeInitializeOnLoadMethod] 确保每次进入 Play 时清空。
///
private static readonly Dictionary _wfsCache = new();
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)]
private static void ClearWFSCache() => _wfsCache.Clear();
private static WaitForSeconds GetWFS(float t)
{
if (!_wfsCache.TryGetValue(t, out var wfs))
_wfsCache[t] = wfs = new WaitForSeconds(t);
return wfs;
}
// ── 公共 API ───────────────────────────────────────────────────────────
///
/// 执行一个 Boss 技能。若当前已在执行中则直接返回。
///
public void ExecuteSkill(BossSkillSO skill)
{
if (_isExecuting || skill == null) return;
_activeCoroutine = StartCoroutine(ExecuteSkillCoroutine(skill));
}
///
/// 立即打断正在执行的技能(阶段切换时调用)。
///
public void InterruptCurrentSkill()
{
if (_activeCoroutine != null)
{
StopCoroutine(_activeCoroutine);
_activeCoroutine = null;
}
FinishExecution();
}
// ── 主协程 ─────────────────────────────────────────────────────────────
private IEnumerator ExecuteSkillCoroutine(BossSkillSO skill)
{
_isExecuting = true;
_currentSkill = skill;
_onBossSkillStarted?.Raise(new BossSkillEvent { BossId = _bossId, SkillId = skill.skillId });
// 播放技能动画
if (skill.skillAnimation != null)
_animancer.Play(skill.skillAnimation);
// 启动 VulnerabilityWindow 协程(与主序列并行)
Coroutine vulnCoroutine = null;
if (skill.vulnerabilityWindows != null && skill.vulnerabilityWindows.Length > 0)
vulnCoroutine = StartCoroutine(ActivateVulnerabilityWindowsCoroutine(skill));
// 执行攻击序列(优先 sequenceOnMiss 作为默认序列)
if (skill.sequenceOnMiss != null)
yield return ExecuteSequenceCoroutine(skill.sequenceOnMiss);
// 若弱点协程还在运行则等待其结束(避免孤立协程)
if (vulnCoroutine != null)
yield return vulnCoroutine;
FinishExecution();
}
private void FinishExecution()
{
_isExecuting = false;
if (_currentSkill != null)
{
_onBossSkillEnded?.Raise(new BossSkillEvent { BossId = _bossId, SkillId = _currentSkill.skillId });
_currentSkill = null;
}
}
// ── 序列协程 ────────────────────────────────────────────────────────────
private IEnumerator ExecuteSequenceCoroutine(SkillSequenceSO seq)
{
int repeatCount = 0;
do
{
foreach (var step in seq.steps)
{
if (step.delayBeforeStep > 0f)
yield return GetWFS(step.delayBeforeStep);
if (step.pattern != null)
yield return ExecutePatternCoroutine(step.pattern);
}
repeatCount++;
if (seq.RepeatIfPlayerInRange && seq.RepeatDelay > 0f)
yield return GetWFS(seq.RepeatDelay);
}
while (seq.RepeatIfPlayerInRange
&& (seq.MaxRepeatCount == 0 || repeatCount < seq.MaxRepeatCount)
&& IsPlayerInRange());
}
private IEnumerator ExecutePatternCoroutine(AttackPatternSO pattern)
{
// 预备
if (pattern.WindupDuration > 0f)
yield return GetWFS(pattern.WindupDuration);
// 激活 HitBox(架构 06 §4:Activate(DamageSourceSO, Transform))
foreach (var hb in _hitBoxes)
hb.Activate(pattern.DamageSource, transform);
if (pattern.ActiveDuration > 0f)
yield return GetWFS(pattern.ActiveDuration);
// 关闭 HitBox
foreach (var hb in _hitBoxes)
hb.Deactivate();
// 后摇
if (pattern.RecoveryDuration > 0f)
yield return GetWFS(pattern.RecoveryDuration);
}
// ── VulnerabilityWindow 协程 ─────────────────────────────────────────────
private IEnumerator ActivateVulnerabilityWindowsCoroutine(BossSkillSO skill)
{
foreach (var window in skill.vulnerabilityWindows)
{
if (window.TriggerDelay > 0f)
yield return GetWFS(window.TriggerDelay);
bool activateSpecific = window.ActivateWeakPointHurtBox;
_weakPointSystem?.SetActive(true, window.DamageMultiplier, activateSpecific);
window.OpenFeedback?.PlayFeedbacks();
yield return GetWFS(window.Duration);
_weakPointSystem?.SetActive(false, 1f, activateSpecific);
window.CloseFeedback?.PlayFeedbacks();
}
}
// ── 工具 ───────────────────────────────────────────────────────────────
private bool IsPlayerInRange() =>
_playerTransform != null &&
Vector2.Distance(transform.position, _playerTransform.position) < 8f;
}
}