lcy
4 天以前 2dd1841d03a730d3d369092c2a3ad656cee4bf64
Main/System/Battle/Skill/SkillBase.cs
@@ -1,52 +1,349 @@
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using Spine;
using System.Linq;
using System;
public class SkillBase
// SkillBase:技能运行时基类。
// 本类使用 partial 拆分为多个文件,按职责分组:
//   SkillBase.cs             字段、构造、公共入口(Cast/Run/OnSkillStart/各 Frame 回调 等)
//   SkillBase.Cast.cs        施法阶段:移动、动画、残影、高亮、攻击回合结束
//   SkillBase.Hit.cs         命中阶段:OnHit 分发到主目标 / 溅射目标 / 命中提示
//   SkillBase.SubSkill.cs    前置内嵌子技能的收集与投递
//   SkillBase.Death.cs       死亡包与掉落/经验分配
//   SkillBase.Buff.cs        Buff 包(HB428/HB429)的收集与分发
//   SkillBase.Finish.cs      完成判定与强制结束
public partial class SkillBase
{
   protected SkillConfig skillConfig;
    // ===== 常量 =====
    const float moveTime = 0.5f;
   protected bool isFinished = false;
    private static readonly Color colorGreen = new Color(33f / 255f,
                                                        133f / 255f,
                                                        6f / 255f);
    private static readonly Color colorBlue = new Color(40f / 255f,
                                                        87f / 255f,
                                                        189f / 255f);
   public SkillBase(SkillConfig _skillCfg)
   {
      skillConfig = _skillCfg;
   }
    // ===== 核心引用 =====
    public HB427_tagSCUseSkill tagUseSkillAttack;
    public SkillConfig skillConfig;
    public SkillSkinConfig skillSkinConfig;
    public BattleObject caster = null; // 施法者
    protected BattleField battleField = null; // 战场
    protected RectTransform targetNode = null; // 目标节点
    protected List<GameNetPackBasic> packList;
   public virtual void Run()
   {
   }
    // ===== 命中效果 =====
    protected SkillEffect skillEffect;
   public virtual void Cast(BattleObject _caster, BattleField battleField, List<Dictionary<int, List<int>>> damageList)
   {
      Debug.LogError("SkillBase Cast should be overridden by derived class");
   }
    // ===== 子技能/子动作等待列表 =====
    protected List<RecordAction> currentWaitingSkill = new List<RecordAction>();
   public virtual bool IsFinished()
   {
      return isFinished;
   }
    // ===== 死亡相关临时数据 =====
    protected List<H0704_tagRolePackRefresh> dropPackList = new List<H0704_tagRolePackRefresh>();
    protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>();
    private Dictionary<int, BattleDrops> tempDropList = new Dictionary<int, BattleDrops>();
    private Dictionary<int, BattleDeadPack> tempDeadPackList = new Dictionary<int, BattleDeadPack>();
   public virtual void ForceFinished()
   {
      isFinished = true;
   }
    // ===== Buff 相关包集合,支持 HB428(刷新) 和 HB429(删除) =====
    protected List<GameNetPackBasic> buffPackCollections = new List<GameNetPackBasic>();
    // ===== 生命周期状态(4 个并行里程碑位,合并到同一 Flags 字段) =====
    //   Started        : 已进入施法阶段(OnSkillStart 调用后)
    //   MoveCompleted  : 位移已收尾(OnAllAttackMoveFinished)
    //   MotionCompleted: 技能动画已播放完(OnFinalFrameEnd)
    //   Finished       : 包列表已处理完(OnSkillFinished / ForceFinished 结尾)
    //   4 个里程碑相互独立,非线性阶段,不能用单一 state 表达。
    [System.Flags]
    protected enum SkillStateFlags
    {
        None            = 0,
        Started         = 1 << 0,
        MoveCompleted   = 1 << 1,
        MotionCompleted = 1 << 2,
        Finished        = 1 << 3,
    }
    private SkillStateFlags _stateFlags = SkillStateFlags.None;
    /// <summary>当前技能状态位(只读,调试用)。</summary>
    protected SkillStateFlags StateFlags => _stateFlags;
#if UNITY_EDITOR
   public virtual List<BattleObject> GetTargetList(BattleObject _caster, BattleField battleField)
   {
      SkillTargetType targetType = SkillTargetType.Enemy;
      SkillTargetRangeType rangeType = SkillTargetRangeType.LowestHP;
      List<BattleObject> affectList = battleField.battleObjMgr.GetTargetList(_caster, targetType, rangeType);
      return affectList;
   }
   public virtual List<Dictionary<int, List<int>>> GetDamageList(BattleObject _caster, BattleField battleField)
   {
      Debug.LogError("SkillBase GetDamageList should be overridden by derived class");
      return null;
   }
    /// <summary>供外部调试/诊断打印用,非编辑器下不编译。</summary>
    public string StateFlagsForDebug => _stateFlags.ToString();
#endif
    /// <summary>是否已进入施法阶段(OnSkillStart 调用后为 true)。</summary>
    public bool isPlay
    {
        get => (_stateFlags & SkillStateFlags.Started) != 0;
        set => SetFlag(SkillStateFlags.Started, value);
    }
    /// <summary>包列表是否已全部处理完。</summary>
    protected bool isFinished
    {
        get => (_stateFlags & SkillStateFlags.Finished) != 0;
        set => SetFlag(SkillStateFlags.Finished, value);
    }
    /// <summary>位移是否已收尾。</summary>
    protected bool moveFinished
    {
        get => (_stateFlags & SkillStateFlags.MoveCompleted) != 0;
        set => SetFlag(SkillStateFlags.MoveCompleted, value);
    }
    /// <summary>技能动画是否已播放完。</summary>
    protected bool isMotionCompleted
    {
        get => (_stateFlags & SkillStateFlags.MotionCompleted) != 0;
        set => SetFlag(SkillStateFlags.MotionCompleted, value);
    }
    private void SetFlag(SkillStateFlags flag, bool value)
    {
#if UNITY_EDITOR
        //  记录状态变更:卡死/卡活的排查利器。
        //  编辑器下只在值真正发生改变时打印,避免刷屏。
        bool oldValue = (_stateFlags & flag) != 0;
        if (oldValue != value)
        {
            int skillId = skillConfig != null ? skillConfig.SkillID : 0;
            ulong casterId = tagUseSkillAttack != null ? tagUseSkillAttack.ObjID : 0UL;
            BattleDebug.LogError(
                $"SkillBase.StateFlags 变更:skillId={skillId} caster={casterId} " +
                $"{flag}: {oldValue} -> {value}  (before={_stateFlags})");
        }
#endif
        if (value) _stateFlags |= flag;
        else       _stateFlags &= ~flag;
    }
    // ===== 父子关系 =====
    public SkillBase fromSkill;
    //  父RecordAction(SkillRecordAction),用于子技能建立父子关系
    protected SkillRecordAction ownRecordAction;
    // ===== 移动速度(残影加速时会改变) =====
    private float MoveSpeed = 750f;
#if UNITY_EDITOR
    public static Dictionary<string, string> changeListDict = new Dictionary<string, string>();
#endif
    // 构造函数:初始化技能基础数据
    public SkillBase(BattleObject _caster, SkillConfig _skillCfg, HB427_tagSCUseSkill vNetData, List<GameNetPackBasic> _packList, BattleField _battleField = null)
    {
        caster = _caster;
        skillConfig = _skillCfg;
        tagUseSkillAttack = vNetData;
        battleField = _battleField;
        packList = _packList;
        if (_caster is HeroBattleObject heroBattleObject)
        {
            skillSkinConfig = skillConfig.GetSkillSkinConfig(heroBattleObject.teamHero.SkinID);
            if (null == skillSkinConfig)
            {
                Debug.LogError("找不到技能皮肤表 " + "skillId: " + skillConfig.SkillID + " skinId: " + heroBattleObject.teamHero.SkinID);
            }
        }
        else
        {
            skillSkinConfig = skillConfig.GetOriginSkinConfig();
        }
        // 注册正在释放的技能
        if (battleField != null && caster != null)
        {
            battleField.AddCastingSkill(caster.ObjID, this);
        }
        SafetyCheck();
    }
    public virtual void AfterAddToQueue()
    {
    }
    //  设置父RecordAction
    public void SetOwnRecordAction(SkillRecordAction recordAction)
    {
        ownRecordAction = recordAction;
    }
    private void PinrtHB427Hp()
    {
#if UNITY_EDITOR
        string skillDetail = "SkillCaster : " + tagUseSkillAttack.ObjID + " -> cast SkillID: " + skillConfig.SkillID + "\n";
        skillDetail += "------------------ HurtList ------------------\n";
        for (int i = 0; i < tagUseSkillAttack.HurtCount; i++)
        {
            var Hurt = tagUseSkillAttack.HurtList[i];
            BattleObject battleObject = caster.battleField.battleObjMgr.GetBattleObject((int)Hurt.ObjID);
            string targetName = battleObject != null ? battleObject.GetName() : "Unknown";
            long hurtHp = GeneralDefine.GetFactValue(Hurt.HurtHP, Hurt.HurtHPEx);
            long curHp = GeneralDefine.GetFactValue(Hurt.CurHP, Hurt.CurHPEx);
            skillDetail += $"  [{i}] Target: {targetName} (ObjID:{Hurt.ObjID})\n";
            skillDetail += $"      HurtHP: {hurtHp}\n";
            skillDetail += $"      CurHP: {curHp}\n";
            skillDetail += $"      SuckHP: {Hurt.SuckHP}\n";
            skillDetail += $"      BounceHP: {Hurt.BounceHP}\n";
            skillDetail += $"      AttackTypes: {Hurt.AttackTypes}\n";
            if (Hurt.HurtListEx != null && Hurt.HurtListEx.Length > 0)
            {
                skillDetail += $"      HurtListEx ({Hurt.HurtListEx.Length}):\n";
                for (int j = 0; j < Hurt.HurtListEx.Length; j++)
                {
                    var hurtEx = Hurt.HurtListEx[j];
                    long hurtExHp = GeneralDefine.GetFactValue(hurtEx.HurtHP, hurtEx.HurtHPEx);
                    long curExHp = GeneralDefine.GetFactValue(hurtEx.CurHP, hurtEx.CurHPEx);
                    skillDetail += $"        [{j}] ObjID:{hurtEx.ObjID} HurtHP:{hurtExHp} CurHP:{curExHp} SuckHP:{hurtEx.SuckHP} AttackTypes:{hurtEx.AttackTypes}\n";
                }
            }
        }
        skillDetail += "------------------ HurtListEx ------------------\n";
        if (tagUseSkillAttack.HurtListEx != null)
        {
            for (int i = 0; i < tagUseSkillAttack.HurtListEx.Length; i++)
            {
                var HurtEx = tagUseSkillAttack.HurtListEx[i];
                BattleObject battleObject = caster.battleField.battleObjMgr.GetBattleObject((int)HurtEx.ObjID);
                string targetName = battleObject != null ? battleObject.GetName() : "Unknown";
                long hurtHp = GeneralDefine.GetFactValue(HurtEx.HurtHP, HurtEx.HurtHPEx);
                long curHp = GeneralDefine.GetFactValue(HurtEx.CurHP, HurtEx.CurHPEx);
                skillDetail += $"  [{i}] Target: {targetName} (ObjID:{HurtEx.ObjID})\n";
                skillDetail += $"      HurtHP: {hurtHp}\n";
                skillDetail += $"      CurHP: {curHp}\n";
                skillDetail += $"      SuckHP: {HurtEx.SuckHP}\n";
                skillDetail += $"      AttackTypes: {HurtEx.AttackTypes}\n";
            }
        }
        skillDetail += "------------------ END ------------------\n";
        if (changeListDict.ContainsKey(caster.battleField.guid))
        {
            string origin = changeListDict[caster.battleField.guid];
            origin += skillDetail;
            changeListDict[caster.battleField.guid] = origin;
        }
        else
            changeListDict.Add(caster.battleField.guid, skillDetail);
        Debug.LogError("skillDetail : " + skillDetail);
#endif
    }
    private void SafetyCheck()
    {
#if UNITY_EDITOR
        if (Launch.Instance.isOpenSkillLogFile)
        {
            PinrtHB427Hp();
        }
#endif
        bool safety = caster != null
                        && skillConfig != null
                        && tagUseSkillAttack != null
                        && battleField != null;
        if (!safety)
        {
            Debug.LogError("SkillBase SafetyCheck failed! Caster or SkillConfig or TagUseSkillAttack or BattleField is null, or Caster is dead.");
            ForceFinished();
        }
    }
    // 技能运行主逻辑:处理技能效果和其他技能动作
    public virtual void Run()
    {
        if (skillEffect != null)
        {
            if (skillEffect.IsFinished())
            {
                skillEffect = null;
                OnSkillFinished();
            }
            else
            {
                skillEffect.Run();
            }
            return;
        }
    }
    // 技能开始回调:处理死亡、子技能、技能效果初始化
    public void OnSkillStart()
    {
        if (isPlay)
        {
            Debug.LogError(" play twice OnSkillStart skillId :" + skillConfig.SkillID);
            return;
        }
        //  先把死亡包收集了
        HandleDead();
        //  再处理 内嵌技能
        ProcessSubSkill();
        skillEffect = SkillEffectFactory.CreateSkillEffect(this, caster, skillConfig, skillSkinConfig, tagUseSkillAttack);
        skillEffect.Play(OnHitTargets);
        isPlay = true;
    }
    // ===== 技能节拍回调 =====
    // 技能前摇结束回调
    public virtual void OnStartSkillFrameEnd() { }
    // 技能中摇开始回调:通知技能效果处理中摇开始
    public virtual void OnMiddleFrameStart(int times)
    {
        skillEffect?.OnMiddleFrameStart(times); // 修复:添加空值检查
    }
    // 技能中摇结束回调:通知技能效果处理中摇结束
    public virtual void OnMiddleFrameEnd(int times, int hitIndex)
    {
        skillEffect?.OnMiddleFrameEnd(times, hitIndex); // 修复:添加空值检查
    }
    // 技能后摇开始回调:通知技能效果处理后摇开始
    public virtual void OnFinalFrameStart()
    {
        skillEffect?.OnFinalFrameStart(); // 修复:添加空值检查
    }
    // 技能后摇结束回调:通知技能效果处理后摇结束
    public virtual void OnFinalFrameEnd()
    {
        //  标记动画播放完成
        isMotionCompleted = true;
        BattleDebug.LogError($"SkillBase.OnFinalFrameEnd: 技能 {skillConfig?.SkillID} 动画播放完成");
        skillEffect?.OnFinalFrameEnd(); // 修复:添加空值检查
    }
}