using System;
using System.Collections.Generic;
using Games.AnimationModule;
using Games.Events;
using Games.GlobeDefine;
using Games.LogicObj;
using Games.Scene;
using GCGame.Table;
using Module.Log;
using UnityEngine;
using UnityEngine.Events;
using Object = UnityEngine.Object;

/// <inheritdoc />
/// <summary>
///     最基本的特效管理器
/// </summary>
public abstract class BaseEffectLogic : MonoBehaviour
{
    /// <summary>
    ///     最小加载容忍时间,加载时间超过该值会忽略特效
    /// </summary>
    public const float minLoadTolerance = 0.5f;

    /// <summary>
    ///     最小加载容忍时间比例,加载时间超过特效总时长比例会忽略特效
    /// </summary>
    public const float minLoadRatio = 0.3f;

    private bool _enable;
    public List<BaseEffectReference> ActiveList { get; private set; }
    public List<DelayEffectReference> DelayList { get; private set; }

    public bool IsInited { get; private set; }

    /// <summary>
    ///     获得特效后,如果是需要延迟出现的情况,特效将会延迟出现
    /// </summary>
    /// <param name="effect">特效物体</param>
    /// <param name="loadData">加载数据</param>
    public void OnCreateEffect(Transform effect, EffectLoadData loadData)
    {
        // 加载超过容忍时间后,直接忽略当前特效
        var loadDelay = Time.time - loadData.startTime;
        var effectDelay = Mathf.Max(0f, loadData.data.DelayTime + loadData.delayModifier);
        var tolerance = effectDelay + Mathf.Max(minLoadTolerance, minLoadRatio * loadData.data.Duration);
        if (loadDelay > tolerance)
        {
            IndependentEffectManager.PushEffect(loadData.data, effect);
        }
        else
        {
            // 从加载开始所计算的延迟时间
            effectDelay = Mathf.Max(0f, effectDelay - loadDelay);
            if (effectDelay > 0)
            {
                effect.gameObject.SetActive(false);
                DelayList.Add(new DelayEffectReference(loadData, effect, Time.time + effectDelay));
            }
            else
            {
                ActiveEffect(effect, loadData);
            }
        }
    }

    public virtual Transform GetBindPoint(string pointName, out Vector3 offset)
    {
        // 故意保留的强制报错,实际只有角色的需要拥有获取绑定点的功能,其他的只保留一个编译接口
        throw new InvalidOperationException(string.Format("{0}未实现获取绑定点的功能,不应该使用绑定类型特效!", GetType()));
    }

    public virtual Obj_Character GetOwnerCharacter()
    {
        // 故意保留的强制报错,实际只有角色才能获得拥有者,其他的只保留一个编译接口
        throw new InvalidOperationException(string.Format("{0}未实现获取拥有者角色的功能,不应该使用神像类型特效!", GetType()));
    }

    private void ActiveEffect(Transform effect, EffectLoadData loadData)
    {
        CommonUtility.SetLayersRecursively(effect, loadData.layer);
        var activeResult = ActiveEffectInherited(effect, loadData);
        if (loadData.playCallback != null)
            loadData.playCallback(activeResult ? effect.gameObject : null, loadData.playParameter);
    }

    protected bool ActiveEffectInherited(Transform effect, EffectLoadData loadData)
    {
        var result = false;
        var customData = (CustomEffectLoadData) loadData.customData;
        switch (customData.EffectType)
        {
            case CommonEffectType.Bound:
            {
                var duration = loadData.data.Duration;
                if (duration < 0)
                    duration = float.PositiveInfinity;
                var activeEffectData = new CommonEffectReference(effect, loadData.data, loadData.handle,
                    Time.time + duration);
                Vector3 offset;
                var bindPoint = GetBindPoint(loadData.data.ParentName, out offset);
                activeEffectData.SetBindPoint(bindPoint,
                    offset + new Vector3(loadData.data.OffsetX, loadData.data.OffsetY, loadData.data.OffsetZ));
                ActiveList.Add(activeEffectData);
                // Hack:给预警圈的特别处理
                SetWarningData(effect, loadData.data);
                result = true;
            }
                break;
            case CommonEffectType.Position:
            {
                var effectData = (NormalEffectCustomData) customData;
                var duration = effectData.duration > 0f ? effectData.duration : loadData.data.Duration;
                if (duration < 0)
                    duration = float.PositiveInfinity;
                var activeEffectData =
                    new CommonEffectReference(effect, loadData.data, loadData.handle, Time.time + duration);
                effect.position = effectData.position;
                // NoRotation不需要旋转
                var rotation = loadData.data.RotationType == EffectRotationType.noRotation
                    ? Quaternion.identity
                    : effectData.rotation;
                if (loadData.data.Yaw > 0)
                    rotation = rotation * Quaternion.Euler(0f, loadData.data.Yaw, 0f);
                effect.rotation = rotation;
                effect.localScale = loadData.data.Scale > 0 ? Vector3.one * loadData.data.Scale : Vector3.one;
                ActiveList.Add(activeEffectData);
                // Hack:给预警圈的特别处理
                SetWarningData(effect, loadData.data);
                result = true;
            }
                break;
            case CommonEffectType.Bullet:
            {
                var effectData = (BulletCustomData) customData;
                var source = Singleton<ObjManager>.Instance.FindObjCharacterInScene(effectData.sourceId);
                if (source != null)
                {
                    var activeBulletData = new BulletEffectReference(effect, effectData.targetId, source,
                        effectData.bulletData, loadData.data, loadData.handle);
                    effect.position = source.transform.position +
                                      source.transform.rotation * activeBulletData.GetStartOffset();
                    var delay = Mathf.Max(0f, Time.time - loadData.startTime - loadData.data.DelayTime);
                    // 模拟子弹加载期间的位移
                    if (activeBulletData.InitBullet(delay))
                    {
                        ActiveList.Add(activeBulletData);
                        result = true;
                    }
                }

                if (!result)
                    IndependentEffectManager.PushEffect(loadData.data, effect);
            }
                break;
            case CommonEffectType.BulletToPos:
            {
                var effectData = (BulletToPosData) customData;
                var activeBulletData = new BulletToPosReference(effect, effectData.startPos, effectData.endPos,
                    effectData.bulletData, loadData.data, loadData.handle);
                ActiveList.Add(activeBulletData);
                result = true;
            }
                break;
            case CommonEffectType.Chain:
            {
                var effectData = (ChainCustomData) customData;
                var activeChainData = new ChainEffectReference(effect, effectData, loadData.data, loadData.handle);
                ActiveList.Add(activeChainData);
                result = true;
            }
                break;
            case CommonEffectType.Stamp:
            {
                var effectData = (StampCustomData) customData;
                var activeEffectData =
                    new StampEffectReference(effect, loadData.data, effectData.stampCount, loadData.handle);
                Vector3 offset;
                var bindPoint = GetBindPoint(loadData.data.ParentName, out offset);
                activeEffectData.SetBindPoint(bindPoint,
                    offset + new Vector3(loadData.data.OffsetX, loadData.data.OffsetY, loadData.data.OffsetZ));
                ActiveList.Add(activeEffectData);
                result = true;
            }
                break;
            case CommonEffectType.WuChangLink:
            {
                var effectData = (WuChangLinkData) customData;
                var activeLinkRef = new WuChangLinkReference(effect, effectData, loadData.data, loadData.handle);
                ActiveList.Add(activeLinkRef);
                result = true;
            }
                break;
            case CommonEffectType.WuChangAirport:
            {
                var effectData = (WuChangAirportData) customData;
                var airportReference = new WuChangAirportReference(effect, effectData, loadData.data, loadData.handle);
                ActiveList.Add(airportReference);
                result = true;
            }
                break;
            case CommonEffectType.Meteor:
            {
                var effectData = (MeteorEffectData) customData;
                var meteorRef = new MeteorEffectReference(effect, effectData, loadData.data, loadData.handle);
                ActiveList.Add(meteorRef);
                result = true;
            }
                break;
            case CommonEffectType.Avatar:
            {
                var character = GetOwnerCharacter();
                if (character != null)
                {
                    var duration = loadData.data.Duration;
                    if (duration < 0)
                        duration = float.PositiveInfinity;
                    var activeEffectData = new AvatarEffectReference(effect, loadData.data, loadData.handle,
                        Time.time + duration);
                    activeEffectData.Init(character);
                    ActiveList.Add(activeEffectData);
                    result = true;
                }
            }
                break;
            default:
                LogModule.ErrorLog(string.Format("未处理类型为{0}的特效!", customData.EffectType));
                break;
        }

        return result;
    }

    protected void Init()
    {
        IsInited = true;
        ActiveList = new List<BaseEffectReference>();
        DelayList = new List<DelayEffectReference>();
        TryAddEvent();
    }

    protected virtual void OnEnable()
    {
        _enable = true;
        TryAddEvent();
    }

    protected virtual void OnDisable()
    {
        _enable = false;
        TryAddEvent();
    }

    private void SetWarningData(Transform effect, Tab_Effect data)
    {
        // 特殊处理技能警告指示器 - 暂时简单做法是用普通加载流程,然后只在配置位置时配置效果
        var effectType = (EffectLogic.EffectType) data.Type;
        switch (effectType)
        {
            case EffectLogic.EffectType.TYPE_CIRCLE:
                effect.GetComponent<WarningCircle>().SetEffectData(data);
                break;
            case EffectLogic.EffectType.TYPE_RECTANGLE:
                effect.GetComponent<WarningRect>().SetEffectData(data);
                break;
            case EffectLogic.EffectType.TYPE_SECTOR:
                effect.GetComponent<WarningSector>().SetEffectData(data);
                break;
        }
    }

    private void OnDestroy()
    {
        if (GameManager.gameManager != null && GameManager.gameManager.effectPool != null)
            GameManager.gameManager.effectPool.DestroyEffectLogic(this);
    }

    private void TryAddEvent()
    {
        if (IsInited && _enable)
            EventDispatcher.Instance.Add(Games.Events.EventId.PostMainCameraMove, AfterCameraMovement);
        else
            EventDispatcher.Instance.Remove(Games.Events.EventId.PostMainCameraMove,
                AfterCameraMovement);
    }

    protected virtual void AfterCameraMovement(object args)
    {
        for (var i = DelayList.Count - 1; i >= 0; i--)
            try
            {
                if (DelayList[i].effect == null)
                {
#if UNITY_EDITOR
                    LogModule.ErrorLog(string.Format("一个于{1}的特效{0}被使用不正常的方式删除!", DelayList[i].loadData.data.EffectID,
                        transform.GetHierarchyName()));
#endif
                    DelayList.RemoveAt(i);
                }
                // 处于延迟发布的状态
                else if (DelayList[i].CheckActive())
                {
                    var delayReference = DelayList[i];
                    DelayList.RemoveAt(i);
                    // 可能某个主角模型在Delay阶段被析构,导致绑定的特效被析构
                    if (delayReference.effect != null)
                    {
                        delayReference.effect.gameObject.SetActive(true);
                        ActiveEffect(delayReference.effect, delayReference.loadData);
                    }
                }
            }
            catch (Exception e)
            {
                LogModule.ErrorLog(e.ToString());
            }

        for (var i = ActiveList.Count - 1; i >= 0; i--)
            try
            {
                // 处于延迟回收状态
                if (ActiveList[i].effect == null)
                {
#if UNITY_EDITOR
                    LogModule.ErrorLog(string.Format("一个于{1}的特效{0}被使用不正常的方式删除!", ActiveList[i].data.EffectID,
                        transform.GetHierarchyName()));
#endif
                    ActiveList.RemoveAt(i);
                }
                else if (ActiveList[i].DelayRecovery)
                {
                    if (!ActiveList[i].UpdateForDelayRecovery())
                        RemoveEffectAt(i);
                }
                else
                {
                    if (!ActiveList[i].Update())
                        if (!ActiveList[i].CheckDelayRecovery())
                            RemoveEffectAt(i);
                }
            }
            catch (Exception e)
            {
                LogModule.ErrorLog(e.ToString());
            }
    }

    public void RemoveEffectByHandle(int handleId)
    {
        if (handleId != 0)
        {
            IndependentEffectManager.CancelLoadByHandleId(handleId);
            for (var i = ActiveList.Count - 1; i >= 0; i--)
                try
                {
                    if (ActiveList[i].effectHandle == handleId)
                        RemoveEffectAt(i);
                }
                catch (Exception e)
                {
                    LogModule.ErrorLog(e.ToString());
                }

            for (var i = DelayList.Count - 1; i >= 0; i--)
                try
                {
                    if (DelayList[i].loadData.handle == handleId)
                        RemoveDelayAt(i);
                }
                catch (Exception e)
                {
                    LogModule.ErrorLog(e.ToString());
                }
        }
    }

    public void RemoveEffectByEffectId(int effectId)
    {
        IndependentEffectManager.CancelLoad(a => a.data.EffectID == effectId);
        for (var i = ActiveList.Count - 1; i >= 0; i--)
            try
            {
                if (ActiveList[i].data.EffectID == effectId)
                    RemoveEffectAt(i);
            }
            catch (Exception e)
            {
                LogModule.ErrorLog(e.ToString());
            }

        for (var i = DelayList.Count - 1; i >= 0; i--)
            try
            {
                if (DelayList[i].loadData.data.EffectID == effectId)
                    RemoveDelayAt(i);
            }
            catch (Exception e)
            {
                LogModule.ErrorLog(e.ToString());
            }
    }

    /// <summary>
    ///     清除全部播放中的特效
    /// </summary>
    public void CleanEffect()
    {
        // 清除加载中的特效
        IndependentEffectManager.CleanEffectLogic(this);
    }

    protected void RemoveEffectAt(int index)
    {
        var item = ActiveList[index];
        ActiveList.RemoveAt(index);
        IndependentEffectManager.PushEffect(item);
    }

    protected void RemoveDelayAt(int index)
    {
        var delayReference = DelayList[index];
        DelayList.RemoveAt(index);
        IndependentEffectManager.PushEffect(delayReference.loadData.data, delayReference.effect);
    }

    /// <summary>
    ///     从延迟列表获得HandleId符合条件的物体
    /// </summary>
    // 特殊处理HandleId为0的情况 - 0视为不可用id
    public DelayEffectReference GetDelayByHandle(int? handleId)
    {
        if (handleId == null)
            return null;
        return DelayList.Find(a => a.loadData.handle == handleId);
    }

    /// <summary>
    ///     从激活列表获得HandleId符合条件的物体
    /// </summary>
    // 延迟回收的特效不允许获得
    public BaseEffectReference GetReferenceByHandle(int? handleId)
    {
        return handleId == null ? null : ActiveList.Find(a => a.effectHandle == handleId && !a.DelayRecovery);
    }

    /// <summary>
    ///     从激活列表获得EffectId符合条件的物体
    /// </summary>
    // 延迟回收的特效不允许获得
    public BaseEffectReference GetReferenceByEffectId(int effectId)
    {
        var result = ActiveList.Find(a => a.data.EffectID == effectId && !a.DelayRecovery);
        return result;
    }

    public static bool ValidEffectByCount(Tab_Effect data, GameDefine_Globe.OBJ_TYPE objType)
    {
        var result = true;
        if (objType == GameDefine_Globe.OBJ_TYPE.OBJ_OTHER_PLAYER || //其他玩家
            objType == GameDefine_Globe.OBJ_TYPE.OBJ_NPC || //NPC
            objType == GameDefine_Globe.OBJ_TYPE.OBJ_FELLOW || //伙伴
            objType == GameDefine_Globe.OBJ_TYPE.OBJ_ZOMBIE_PLAYER || //僵尸玩家
            objType == GameDefine_Globe.OBJ_TYPE.OBJ_DROP_ITEM)//掉落包
        {
            result = false;
            if (data.CountLimit >= EffectLimitLevel.unlimit)
                result = true;
            // 原始逻辑,一般认为unlimit的是非技能特效
            else if (PlayerPreferenceData.SystemSkillEffectEnable)
            {
                var limit = data.CountLimit < EffectLimitLevel.important
                    ? PlayerPreferenceData.effectCountLimit.commonCount
                    : PlayerPreferenceData.effectCountLimit.importantCount;
                if (limit > GameManager.gameManager.effectPool.inUseCount)
                    result = true;
            }
        }
        return result;
    }
}

public class DelayEffectReference
{
    public readonly Transform effect;
    public readonly EffectLoadData loadData;
    public readonly float startTime;

    public DelayEffectReference(EffectLoadData loadData, Transform effect, float startTime)
    {
        this.loadData = loadData;
        this.effect = effect;
        this.startTime = startTime;
    }

    public bool CheckActive()
    {
        return Time.time > startTime;
    }
}

public abstract class BaseEffectReference
{
    public readonly Tab_Effect data;
    public readonly Transform effect;
    public readonly int? effectHandle;

    protected BaseEffectReference(Tab_Effect data, Transform effect, int? effectHandle)
    {
        this.data = data;
        this.effect = effect;
        this.effectHandle = effectHandle;
    }

    // 特效是否需要延迟回收 - 有拖尾等特效效果等待效果结束
    public bool DelayRecovery { get; private set; }

    // 特效延迟回收时间
    public float DelayRecoveryTime { get; private set; }

    /// <summary>
    ///     更新特效状态
    /// </summary>
    /// <returns>特效是否继续存在</returns>
    public virtual bool Update()
    {
        return effect != null;
    }

    /// <summary>
    ///     检查特效是否需要延迟回收
    /// </summary>
    public bool CheckDelayRecovery()
    {
        var cleaner = effect.GetComponent<IParticleCleaner>();
        if (cleaner == null)
        {
            LogModule.ErrorLog(string.Format("特效{0}上没有ParticleCleaner!", effect.GetHierarchyName()));
        }
        else if (cleaner.DelayRecoveryTime > 0f)
        {
            DelayRecovery = true;
            DelayRecoveryTime = Time.time + cleaner.DelayRecoveryTime;
            cleaner.StartDelayRecovery();
        }

        return DelayRecovery;
    }

    /// <summary>
    ///     检查特效是否延迟回收尚未结束
    /// </summary>
    public virtual bool UpdateForDelayRecovery()
    {
        return Time.time < DelayRecoveryTime;
    }

    /// <summary>
    ///     特效播放结束时统一处理
    /// </summary>
    public virtual void EndEffect()
    {
    }
}

public delegate void PlayEffectDelegate(GameObject effectObj, object param);

#region 特效物品通用管理池

public class EffectPool : AutoLoadPool<Transform, EffectLoadData, EffectLoadTask>
{
    public EffectPool(Transform root, UnityAction<Transform> createAction) : base(root, true, createAction)
    {
    }

    public static string GetBundleName(string assetPath)
    {
        return LoadAssetBundle.FixBundleName(LoadAssetBundle.BUNDLE_PATH_EFFECT + assetPath);
    }

    public void PreloadEffect(Tab_Effect data)
    {
        var bundleName = GetBundleName(data.Path);
        Preload(bundleName, data.Path);
    }

    public void PullEffect(EffectLoadData taskStarter)
    {
        var bundleName = GetBundleName(taskStarter.data.Path);
        PullItem(taskStarter, bundleName, taskStarter.data.Path);
    }

    public void PushEffect(BaseEffectReference effect)
    {
        PushEffect(effect.data, effect.effect);
    }

    public void PushEffect(Tab_Effect data, Transform effect)
    {
        var bundleName = GetBundleName(data.Path);
        if (data.IsOnlyDeactive)
        {
            PushItem(bundleName, data.Path, effect);
        }
        else
        {
            // 不退回物体,但是要求减少使用记录
            ReduceCount(bundleName, data.Path);
            Object.Destroy(effect.gameObject);
        }
    }

    /// <summary>
    ///     按照特效句柄取消一个特效加载任务
    /// </summary>
    /// <param name="handleId">特效句柄</param>
    // 注:主要用于特效在完成加载前,服务器要求停止播放的情况
    public void CancelLoadByHandleId(int handleId)
    {
        //if (!Killed)
        for (var i = loadTaskList.Count - 1; i >= 0; i--)
            loadTaskList[i].CancelByHandle(handleId);
    }
}


/// <summary>
///     全局唯一的特效管理池,统一处理所有特效GameObject的回收和再利用
/// </summary>
public class CentralEffectPool : EffectPool
{
    public CentralEffectPool(Transform root) : base(root, EnsureParticleCleaner)
    {
    }

    private static void EnsureParticleCleaner(Transform child)
    {
        // 如果没有自定义粒子回收器,就添加通用回收器
        var cleaner = child.GetComponent<IParticleCleaner>();
        if (cleaner == null)
            child.gameObject.AddComponent<ParticleCleaner>();
    }

    /// <summary>
    ///     EffectLogic被销毁时,通知池子取消加载注册
    /// </summary>
    public void CleanEffectLogic(BaseEffectLogic effectLogic)
    {
//        if (!Killed)
//        {
        // 移除对加载事件的监听
        for (var i = 0; i < loadTaskList.Count; i++)
            try
            {
                loadTaskList[i].RemoveListener(a => a.callback == effectLogic.OnCreateEffect);
            }
            catch (Exception e)
            {
                LogModule.ErrorLog(e.ToString());
            }

        // 回收使用中的特效
        for (var i = 0; i < effectLogic.ActiveList.Count; i++)
            if (effectLogic.ActiveList[i].effect != null)
                PushEffect(effectLogic.ActiveList[i]);
        for (var i = 0; i < effectLogic.DelayList.Count; i++)
            if (effectLogic.DelayList[i].effect != null)
            {
                var delayItem = effectLogic.DelayList[i];
                PushEffect(delayItem.loadData.data, delayItem.effect);
            }
        effectLogic.ActiveList.Clear();
        effectLogic.DelayList.Clear();
    }

    public void DestroyEffectLogic(BaseEffectLogic effectLogic)
    {
        if (!GameManager.applicationQuit)
        {
            // 移除对加载事件的监听
            for (var i = 0; i < loadTaskList.Count; i++)
                try
                {
                    loadTaskList[i].RemoveListener(a => a.callback == effectLogic.OnCreateEffect);
                }
                catch (Exception e)
                {
                    LogModule.ErrorLog(e.ToString());
                }

            // 回收会导致报错,因此跳过回收流程
            for (var i = 0; i < effectLogic.ActiveList.Count; i++)
                if (effectLogic.ActiveList[i].effect != null)
                {
                    var assetName = effectLogic.ActiveList[i].data.Path;
                    var bundleName = GetBundleName(assetName);
                    ReduceCount(bundleName, assetName);
                }

            for (var i = 0; i < effectLogic.DelayList.Count; i++)
                if (effectLogic.DelayList[i].effect != null)
                {
                    var assetName = effectLogic.DelayList[i].loadData.data.Path;
                    var bundleName = GetBundleName(assetName);
                    ReduceCount(bundleName, assetName);
                }
        }
    }

    // 主角技能特效预加载
    // 预加载方式为在这个地方添加一次引用防止成为Unused

    #region MainCharacter Preload Effect

    // 注:其他角色的技能表信息是无法获得的,因此只能预加载主角特效
    private readonly List<string> _holdEffects = new List<string>();

    public void SetMainPlayerPreload()
    {
        var preloadList = new HashSet<string>();
        var playerDataPool = GameManager.gameManager.PlayerDataPool;
        foreach (var ownSkill in playerDataPool.OwnSkillInfo)
        {
            if (ownSkill.SkillExTable != null)
            {
                var preload = ownSkill.SkillExTable.PreloadEffect;
                if (!string.IsNullOrEmpty(preload) && !"-1".Equals(preload) && !"0".Equals(preload))
                {
                    var preloads = preload.Split(';');
                    for (var i = 0; i < preloads.Length; i++)
                    {
                        int effectId;
                        if (int.TryParse(preloads[i], out effectId))
                        {
                            if (effectId > GlobeVar.INVALID_ID)
                            {
                                var effectData = TableManager.GetEffectByID(effectId, 0);
                                if (effectData != null)
                                    preloadList.Add(effectData.Path);
                            }
                        }
                    }
                }
            }
        }
        SetHoldPreload(preloadList);
    }

    public void SetHoldPreload(ICollection<string> effects)
    {
        for (var i = _holdEffects.Count - 1; i >= 0; i--)
        {
            if (!effects.Contains(_holdEffects[i]))
            {
                var assetName = _holdEffects[i];
                var bundleName = GetBundleName(assetName);
                ReduceCount(bundleName, assetName, true);
                _holdEffects.RemoveAt(i);
            }
        }
        foreach (var effect in effects)
            if (!_holdEffects.Contains(effect))
            {
                _holdEffects.Add(effect);
                var assetName = effect;
                var bundleName = GetBundleName(assetName);
                // 如果已经有池,就直接添加数量
                if (!Preload(bundleName, assetName))
                    AddCount(bundleName, assetName, true);
            }
    }

    // 只有Kill会清空Pool;Kill后也不会重用池,因此不需要额外调用这个。
    public void CleanHoldPreload()
    {
        for (var i = 0; i < _holdEffects.Count; i++)
        {
            var assetName = _holdEffects[i];
            var bundleName = GetBundleName(assetName);
            ReduceCount(bundleName, assetName, true);
        }
        _holdEffects.Clear();
    }

    // 底层锁死Pool只在资源加载完成才构造,因此只能监听加载完成后,再执行Hold;
    // 修改底层风险过高,因此采用加载完成加Token的流程
    protected override void OnLoadTaskFinished(EffectLoadTask loadTask)
    {
        base.OnLoadTaskFinished(loadTask);
        if (_holdEffects.Contains(loadTask.PrefabName))
            AddCount(loadTask.BundleName, loadTask.PrefabName, true);
    }

    #endregion
}

public class EffectLoadTask : BaseLoadTask<Transform, EffectLoadData, EffectLoadTask>
{
    /// <summary>
    ///     按照特效句柄Id取消一个加载需求
    /// </summary>
    /// <param name="handle">特效句柄Id</param>
    /// <returns>是否加载任务已空</returns>
    public void CancelByHandle(int handle)
    {
        for (var i = taskListeners.Count - 1; i >= 0; i--)
            if (taskListeners[i].handle == handle)
                taskListeners.RemoveAt(i);
    }
}

public class EffectLoadData : BaseLoadData<Transform, EffectLoadData>
{
    public readonly Tab_Effect data;

    /// <summary>
    ///     特效播放延迟的修正数值
    /// </summary>
    public readonly float delayModifier;

    public readonly int? handle;
    public readonly int layer;
    public readonly PlayEffectDelegate playCallback;
    public readonly object playParameter;
    public readonly float startTime;
    public object customData;

    public EffectLoadData(BaseEffectLogic effectLogic, int layer, Tab_Effect data, int? handle,
        PlayEffectDelegate playCallback, object playParameter, object customData, float delayModifier = 0f) : base(
        effectLogic.transform, effectLogic.OnCreateEffect)
    {
        this.layer = layer;
        this.data = data;
        this.handle = handle;
        this.playCallback = playCallback;
        this.playParameter = playParameter;
        this.customData = customData;
        this.delayModifier = delayModifier;
        startTime = Time.time;
    }
}

#endregion

#region 特效物品自定义参数

public class BulletCustomData : CustomEffectLoadData
{
    public readonly Tab_Bullet bulletData;
    public readonly int sourceId;
    public readonly int targetId;

    public BulletCustomData(Tab_Bullet bulletData, int sourceId, int targetId)
    {
        this.bulletData = bulletData;
        this.sourceId = sourceId;
        this.targetId = targetId;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Bullet; }
    }
}

public class BulletToPosData : CustomEffectLoadData
{
    public readonly Tab_Bullet bulletData;
    public readonly Vector3 endPos;
    public readonly Vector3 startPos;

    public BulletToPosData(Tab_Bullet bulletData, Vector3 startPos, Vector3 endPos)
    {
        this.bulletData = bulletData;
        this.startPos = startPos;
        this.endPos = endPos;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.BulletToPos; }
    }
}

public class NormalEffectCustomData : CustomEffectLoadData
{
    public readonly float duration;
    public readonly Vector3 position;
    public readonly Quaternion rotation;

    public NormalEffectCustomData(Vector3 position, Quaternion rotation, float duration = -1f)
    {
        this.position = position;
        this.rotation = rotation;
        this.duration = duration;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Position; }
    }
}

public class ChainCustomData : CustomEffectLoadData
{
    public readonly float duration;

    public readonly int sourceId;
    public readonly float speed;

    public ChainCustomData(int sourceId, int targetId, float duration, float speed)
    {
        this.sourceId = sourceId;
        TargetId = targetId;
        this.duration = duration;
        this.speed = speed;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Chain; }
    }

    public int TargetId { get; private set; }

    public void ResetTarget(int targetId)
    {
        TargetId = targetId;
    }
}

public class BoundCustomData : CustomEffectLoadData
{
    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Bound; }
    }
}

public class StampCustomData : CustomEffectLoadData
{
    public readonly int stampCount;

    public StampCustomData(int stampCount)
    {
        this.stampCount = stampCount;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Stamp; }
    }
}

public class WuChangLinkData : CustomEffectLoadData
{
    public readonly int sourceId;
    public readonly int targetId;

    public WuChangLinkData(int sourceId, int targetId)
    {
        this.sourceId = sourceId;
        this.targetId = targetId;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.WuChangLink; }
    }
}

public class WuChangAirportData : CustomEffectLoadData
{
    public readonly int count;
    public readonly int sourceId;

    public WuChangAirportData(int sourceId, int count)
    {
        this.sourceId = sourceId;
        this.count = count;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.WuChangAirport; }
    }
}

public class MeteorEffectData : CustomEffectLoadData
{
    public readonly Vector3 fallPosition;
    public readonly float fallTime;
    public readonly Vector3 holdPosition;
    public readonly float holdTime;
    public readonly Vector3 rollPosition;
    public readonly float rollTime;

    public MeteorEffectData(float offsetY, float holdTime, float fallTime, float rollTime, Vector2 holdPos,
        Vector2 fallPos, Vector2 rollPos)
    {
        this.holdTime = holdTime;
        this.fallTime = fallTime + this.holdTime;
        this.rollTime = rollTime + this.fallTime;
        holdPosition = ActiveScene.GetTerrainPosition(holdPos.InsertY());
        fallPosition = ActiveScene.GetTerrainPosition(fallPos.InsertY());
        rollPosition = ActiveScene.GetTerrainPosition(rollPos.InsertY());
        holdPosition.y += offsetY;
    }

    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Meteor; }
    }
}

public class AvatarEffectData : CustomEffectLoadData
{
    public override CommonEffectType EffectType
    {
        get { return CommonEffectType.Avatar; }
    }
}

public abstract class CustomEffectLoadData
{
    public abstract CommonEffectType EffectType { get; }
}

#endregion

#region 特效物品引用参数

/// <summary>
///     标准绑定位置的特效基类
/// </summary>
public abstract class BoundEffectReferenceBase : BaseEffectReference
{
    private readonly Quaternion _localRotation;

    public BoundEffectReferenceBase(Transform effect, Tab_Effect data, int? effectHandle) : base(data, effect,
        effectHandle)
    {
        _localRotation = data.Yaw > 0 ? Quaternion.Euler(0f, data.Yaw, 0f) : Quaternion.identity;
    }

    // 特效绑定点
    public Transform BindPoint { get; private set; }

    // 特效绑定偏移值
    public Vector3 Offset { get; private set; }

    public void SetBindPoint(Transform bindPoint, Vector3 offset)
    {
        BindPoint = bindPoint;
        Offset = offset;
        effect.SetParent(bindPoint, false);
        effect.transform.localPosition = offset;
        effect.transform.localRotation = _localRotation;
        var scale = data.Scale > 0 ? data.Scale * Vector3.one : Vector3.one;
        effect.transform.localScale = scale;
    }

    public override bool Update()
    {
        if (base.Update())
        {
            SetRotation();
            return true;
        }

        return false;
    }

    private void SetRotation()
    {
        switch (data.RotationType)
        {
            case EffectRotationType.noRotation:
                // 需要校正LocalPosition到世界类型
                effect.rotation = _localRotation;
                break;
            case EffectRotationType.faceCamera:
                // 暂时使用UiManager上面那个安全接口
                var mainCamera = UIManager.Instance().GetWorldCamera();
                if (mainCamera != null)
                {
                    var rotation = Quaternion.LookRotation(mainCamera.transform.position - effect.position);
                    rotation = rotation * _localRotation;
                    effect.rotation = rotation;
                }

                break;
        }
    }
}


/// <summary>
///     载入中特效数据,用于存放动态加载的特效实例
/// </summary>
public class CommonEffectReference : BoundEffectReferenceBase
{
    private readonly float _endTime;

    public CommonEffectReference(Transform effect, Tab_Effect data, int? effectHandle, float endTime) : base(effect,
        data,
        effectHandle)
    {
        _endTime = endTime;
    }

    public override bool Update()
    {
        if (Time.time < _endTime)
            return base.Update();
        return false;
    }
}

/// <summary>
///     子弹数据记录
/// </summary>
public class BulletEffectReference : BaseEffectReference
{
    private readonly Quaternion _localRotation;
    private readonly BulletSimulator _simulator;

    // 用于在Target析构后,重新恢复Target
    private readonly int _targetId;

    public readonly Tab_Bullet bulletData;

    // 抛物线子弹最大偏移位置
    private Vector3 _maxPathOffset;

    private Vector3 _targetOffset;
    private Transform _targetTransform;

    public BulletEffectReference(Transform effect, int targetId, Obj source, Tab_Bullet bulletData, Tab_Effect data,
        int? effectHandle) : base(data, effect, effectHandle)
    {
        this.bulletData = bulletData;
        _localRotation = data.Yaw > 0 ? Quaternion.Euler(0f, data.Yaw, 0f) : Quaternion.identity;
        _targetId = targetId;
        // 提前推送目标无法获得时的攻击位置
        _simulator = new BulletSimulator
        {
            targetPoint = source.transform.position + source.transform.rotation * GetStartOffset() +
                          source.transform.forward * bulletData.MinDistance
        };
    }

    public Vector3 GetStartOffset()
    {
        return new Vector3(bulletData.StartPosX, bulletData.StartPosY, bulletData.StartPosZ);
    }

    public override bool Update()
    {
        var valid = base.Update() && MoveBullet();
        // 子弹消散特效
        if (!valid)
            if (bulletData.EndEffectId > 0 && bulletData.EndEffectId != bulletData.EffectId)
                if (IndependentEffectManager.Instance != null)
                    IndependentEffectManager.Instance.ShowEffect(bulletData.EndEffectId, effect.gameObject.layer, GameDefine_Globe.OBJ_TYPE.OBJ,
                        effect.position, Quaternion.Euler(0f, effect.eulerAngles.y, 0f));
        return valid;
    }

    public bool InitBullet(float delay)
    {
        ResetAttackPoint();
        _simulator.duration = (_simulator.targetPoint - effect.position).RemoveY().magnitude / bulletData.Speed;
        var result = delay < _simulator.duration;
        if (result)
        {
            _simulator.startTime = Time.time - delay;
            _maxPathOffset = 0.5f * new Vector3(bulletData.BulletDirectionX, bulletData.BulletDirectionY, 0f) *
                             _simulator.duration;
            _simulator.logicPoint = effect.position;
            var scale = data.Scale > 0 ? data.Scale * Vector3.one : Vector3.one;
            effect.localScale = scale;
            result = MoveBullet();
        }

        return result;
    }

    /// <summary>
    ///     移动子弹位置
    /// </summary>
    /// <returns>子弹尚未飞行到目标位置</returns>
    private bool MoveBullet()
    {
        var result = true;
        ResetAttackPoint();
        // 计算子弹飞行时间百分比
        var direction = _simulator.UpdateBullet().normalized;
        if (_simulator.lastRatio >= 1f)
            result = false;
        var logicPoint = _simulator.logicPoint;
        if (_maxPathOffset == Vector3.zero || direction == Vector3.zero)
        {
            effect.position = logicPoint;
        }
        else
        {
            var x = Vector3.Cross(Vector3.up, direction).normalized;
            effect.position = logicPoint + (_maxPathOffset.x * x + _maxPathOffset.y * Vector3.up) *
                              (1f - Mathf.Abs(_simulator.lastRatio * 2 - 1f).ToSquare());
        }

        // 调节子弹面对方向
        if (direction != Vector3.zero)
        {
            var rotationType = data.RotationType;
            // 如果没有摄像机就统一回退到最基础方式
            var cameraTrans = SceneLogic.CameraController != null && SceneLogic.CameraController.MainCamera != null
                ? SceneLogic.CameraController.MainCamera.transform
                : null;
            if (cameraTrans == null)
                rotationType = EffectRotationType.byEffectType;
            switch (rotationType)
            {
                case EffectRotationType.faceCamera:
                    // 忽略这个Null警告,这个位置不可能是Null
                    var y = cameraTrans.position - effect.position;
                    var x = Vector3.Cross(y, direction);
                    y = Vector3.Cross(direction, x);
                    if (y == Vector3.zero)
                        y = Vector3.up;
                    effect.rotation = Quaternion.LookRotation(direction, y) * _localRotation;
                    break;
                case EffectRotationType.byEffectType:
                    effect.rotation = Quaternion.LookRotation(direction, Vector3.up) * _localRotation;
                    break;
            }
        }

        return result;
    }

    /// <summary>
    ///     获得子弹攻击目标位置
    /// </summary>
    private void ResetAttackPoint()
    {
        // 试图恢复目标绑定
        if (_targetId != 0 && _targetTransform == null)
        {
            var targetObj = Singleton<ObjManager>.Instance.FindObjCharacterInScene(_targetId);
            if (targetObj != null)
                if (targetObj.ObjEffectLogic == null)
                {
                    _targetTransform = targetObj.transform;
                    _targetOffset = Vector3.zero;
                }
                else
                {
                    _targetTransform = targetObj.ObjEffectLogic.GetBindPoint(bulletData.AttackPoint, out _targetOffset);
                }
        }

        // 如果目标没有丢失,使用目标校正攻击位置
        if (_targetTransform != null)
            _simulator.targetPoint = _targetTransform.rotation * _targetOffset + _targetTransform.position;
    }
}

/// <summary>
///     对位置飞行子弹引用记录
/// </summary>
public class BulletToPosReference : BaseEffectReference
{
    private readonly float _duration;
    private readonly Vector3 _endPos;
    private readonly Quaternion _localRotation;
    private readonly Vector3 _offsetDir;
    private readonly Vector3 _startPos;
    private readonly float _startTime;

    public readonly Tab_Bullet bulletData;

    public BulletToPosReference(Transform effect, Vector3 startPos, Vector3 endPos, Tab_Bullet bulletData,
        Tab_Effect data,
        int? effectHandle) : base(data, effect, effectHandle)
    {
        this.bulletData = bulletData;
        _startPos = startPos;
        _endPos = endPos;
        _startTime = Time.time;
        _localRotation = data.Yaw > 0 ? Quaternion.Euler(0f, data.Yaw, 0f) : Quaternion.identity;
        var delta = endPos - startPos;
        delta.y = 0f;
        if (delta == Vector3.zero)
        {
            _startTime = float.NegativeInfinity;
            _duration = 0f;
            effect.position = startPos;
        }
        else
        {
            _duration = Mathf.Min(60f, delta.magnitude / bulletData.Speed);
            var rotation = Quaternion.LookRotation(delta, Vector3.up) * _localRotation;
            _offsetDir = rotation * new Vector3(bulletData.BulletDirectionX, bulletData.BulletDirectionY, 0f);
            MoveBullet();
        }
    }

    public override bool Update()
    {
        var valid = base.Update() && MoveBullet();
        // 子弹消散特效
        if (!valid)
            if (bulletData.EndEffectId > 0 && bulletData.EndEffectId != bulletData.EffectId)
                if (IndependentEffectManager.Instance != null)
                    IndependentEffectManager.Instance.ShowEffect(bulletData.EndEffectId, effect.gameObject.layer, GameDefine_Globe.OBJ_TYPE.OBJ,
                        effect.position, Quaternion.Euler(0f, effect.eulerAngles.y, 0f));
        return valid;
    }

    /// <summary>
    ///     移动子弹位置
    /// </summary>
    /// <returns>子弹尚未飞行到目标位置</returns>
    private bool MoveBullet()
    {
        var result = Time.time < _startTime + _duration;
        if (result)
        {
            var time = Time.time - _startTime;
            var ratio = time / _duration;
            var direction = (_endPos - _startPos).normalized;
            if (_offsetDir == Vector3.zero)
            {
                effect.position = Vector3.Lerp(_startPos, _endPos, ratio);
            }
            else
            {
                var currentOffsetDir = _offsetDir * (1f - ratio * 2f);
                effect.position = Vector3.Lerp(_startPos, _endPos, ratio) +
                                  (_offsetDir + currentOffsetDir) * 0.5f * bulletData.Speed * time;
                direction += currentOffsetDir;
            }
            var rotationType = data.RotationType;
            // 如果没有摄像机就统一回退到最基础方式
            var cameraTrans = SceneLogic.CameraController != null && SceneLogic.CameraController.MainCamera != null
                ? SceneLogic.CameraController.MainCamera.transform
                : null;
            if (cameraTrans == null)
                rotationType = EffectRotationType.byEffectType;
            switch (rotationType)
            {
                case EffectRotationType.faceCamera:
                    // 忽略这个Null警告,这个位置不可能是Null
                    var y = cameraTrans.position - effect.position;
                    var x = Vector3.Cross(y, direction);
                    y = Vector3.Cross(direction, x);
                    if (y == Vector3.zero)
                        y = Vector3.up;
                    effect.rotation = Quaternion.LookRotation(direction, y) * _localRotation;
                    break;
                case EffectRotationType.byEffectType:
                    effect.rotation = Quaternion.LookRotation(direction, Vector3.up) * _localRotation;
                    break;
            }
        }
        else
        {
            effect.position = _endPos;
            // 特殊处理结束不消失的流程
            if (bulletData.EffectId > 0 && bulletData.EffectId == bulletData.EndEffectId &&
                _startTime + data.Duration > Time.time)
                result = true;
        }
        return result;
    }
}

/// <summary>
///     锁链特效引用记录
/// </summary>
public class ChainEffectReference : BaseEffectReference
{
    // 用于在Source或者Target析构后,重新恢复效果
    private readonly LinkFxController _controller;

    // 如果锁链拥有消散时间和飞行速度,需要做子弹效果
    private BulletSimulator _bulletSimulator;

    private ChainCustomData _chainData;

    private float _endTime;

    private Obj_Character _source;
    private Obj_Character _target;

    public ChainEffectReference(Transform effect, ChainCustomData chainData, Tab_Effect data, int? effectHandle) : base(
        data, effect, effectHandle)
    {
        _chainData = chainData;
        _controller = effect.GetComponent<LinkFxController>();
        if (_controller == null)
            LogModule.ErrorLog(string.Format("特效物体{0}上不存在锁链控制器", data.Path));
        ResetEndTime();
    }

    public override bool Update()
    {
        var result = base.Update() && Time.time < _endTime;
        if (result && _controller != null)
        {
            if (_source == null || _source.ServerID != _chainData.sourceId)
                _source = ObjManager.Instance.FindObjCharacterInScene(_chainData.sourceId);
            if (_target == null || _target.ServerID != _chainData.TargetId)
                _target = ObjManager.Instance.FindObjCharacterInScene(_chainData.TargetId);
            // 需要动态初始化子弹的情况
            if (_bulletSimulator == null && _source != null && _target != null)
            {
                var sourcePoint = GetChainPoint(_source, data.ParentName);
                var targetPoint = GetChainPoint(_target, EffectLogic.centerName);
                _bulletSimulator = new BulletSimulator(sourcePoint,
                    targetPoint,
                    _chainData.speed > 0f ? Vector3.Distance(sourcePoint, targetPoint) / _chainData.speed : 0f);
            }

            if (_bulletSimulator != null)
            {
                // 如果目标存在,刷新目标位置
                if (_target != null)
                    _bulletSimulator.targetPoint = GetChainPoint(_target, EffectLogic.centerName);
                _bulletSimulator.UpdateBullet();
                if (_source != null)
                {
                    var sourcePoint = GetChainPoint(_source, data.ParentName);
                    _controller.sourcePoint = sourcePoint;
                }

                _controller.targetPoint = _bulletSimulator.logicPoint;
                _controller.TryUpdateLink();
            }
        }

        return result;
    }

    public void ResetParameters(ChainCustomData chainData)
    {
        // 检查,如果Src或者Target有改变,就重置锁链
        // 否则仅仅修改参数
        if (chainData.sourceId != _chainData.sourceId
            || chainData.TargetId != _chainData.TargetId)
        {
            _source = null;
            _target = null;
            _bulletSimulator = null;
            ResetEndTime();
        }

        _chainData = chainData;
        Update();
    }

    private void ResetEndTime()
    {
        _endTime = _chainData.duration > 0 ? Time.time + _chainData.duration : float.PositiveInfinity;
        if (_controller != null)
            _controller.ResetEndTime(_endTime);
    }

    /// <summary>
    ///     恢复锁链攻击目标
    /// </summary>
    private Vector3 GetChainPoint(Obj_Character target, string bindName)
    {
        if (target.ObjEffectLogic != null)
            return target.ObjEffectLogic.GetBindPointPosition(bindName);
        return target.Position;
    }
}

public class StampEffectReference : BoundEffectReferenceBase
{
    private readonly MarkSfxController _controller;

    public StampEffectReference(Transform effect, Tab_Effect data, int initCount, int? effectHandle) : base(effect,
        data, effectHandle)
    {
        _controller = effect.GetComponent<MarkSfxController>();
        if (_controller == null)
            LogModule.ErrorLog(string.Format("特效物体{0}上不存在印记控制器", data.Path));
        else
            _controller.TargetCount = initCount;
    }

    public void SetCurrentCount(int count)
    {
        _controller.TargetCount = count;
    }

    public void Detonate()
    {
        _controller.Detonate(true);
    }

    public override bool Update()
    {
        var result = base.Update();
        if (result)
            result = !_controller.IsDetonated;
        return result;
    }
}

public class WuChangLinkReference : BaseEffectReference
{
    // 用于在Source或者Target析构后,重新恢复效果
    private readonly WuChangLinkController _controller;

    public readonly WuChangLinkData linkData;
    private bool _isBreak;

    public WuChangLinkReference(Transform effect, WuChangLinkData linkData, Tab_Effect data, int? effectHandle) : base(
        data, effect, effectHandle)
    {
        this.linkData = linkData;
        _controller = effect.GetComponent<WuChangLinkController>();
        if (_controller == null)
            LogModule.ErrorLog(string.Format("特效物体{0}上不存在锁链控制器", data.Path));
        else
            _controller.Init(data);
    }

    public override bool Update()
    {
        var result = base.Update();
        if (result && _controller != null)
        {
            var sourceObj = ObjManager.Instance.FindObjInScene(linkData.sourceId);
            var targetObj = ObjManager.Instance.FindObjInScene(linkData.targetId);
            if (sourceObj != null && targetObj != null)
            {
                var sourcePos = sourceObj.ObjEffectLogic == null
                    ? sourceObj.Position
                    : sourceObj.ObjEffectLogic.GetBindPointPosition(EffectLogic.centerName);
                var targetPos = targetObj.ObjEffectLogic == null
                    ? targetObj.Position
                    : targetObj.ObjEffectLogic.GetBindPointPosition(EffectLogic.centerName);
                _controller.gameObject.SetActive(true);
                result = _controller.SetLinkPosition(sourcePos, targetPos, _isBreak);
            }
            else
            {
                _controller.gameObject.SetActive(false);
                result = false;
            }

            // 如果没有断开,则不回收;否则等待断开动画结束
            result = result || !_isBreak;
        }

        return result;
    }

    public void BreakLink()
    {
        _isBreak = true;
    }
}

public class WuChangAirportReference : BaseEffectReference
{
    // 用于在Source或者Target析构后,重新恢复效果
    private readonly WuChangGhostAuraController _controller;

    public readonly WuChangAirportData airportData;
    private bool _active;

    public WuChangAirportReference(Transform effect, WuChangAirportData airportData, Tab_Effect data,
        int? effectHandle) : base(
        data, effect, effectHandle)
    {
        this.airportData = airportData;
        _active = true;
        _controller = effect.GetComponent<WuChangGhostAuraController>();
        if (_controller == null)
            LogModule.ErrorLog(string.Format("特效物体{0}上不存在幽灵机场控制器", data.Path));
        else
            _controller.Init(airportData.count, data);
    }

    public override bool Update()
    {
        var result = base.Update();
        if (result && _controller != null)
        {
            var sourceObj = ObjManager.Instance.FindObjInScene(airportData.sourceId);
            _active = sourceObj != null;
            _controller.gameObject.SetActive(_active);
            if (_active)
                _controller.ownerPos = sourceObj.ObjEffectLogic == null
                    ? sourceObj.Position
                    : sourceObj.ObjEffectLogic.GetBindPointPosition(data.ParentName);
        }

        return result;
    }

    public void AttackTarget(Transform target, Vector3 offset, float impactTime)
    {
        if (_active)
            _controller.AttackTarget(target, offset, impactTime);
    }
}

/// <summary>
///     陨石轨迹模拟器
/// </summary>
// 陨石实际为一个三段式的子弹,三阶段都是匀速移动流程
public class MeteorEffectReference : BaseEffectReference
{
    private readonly MeteorEffectController _meteorController;

    private readonly MeteorEffectData _meteorData;
    private readonly BulletSimulator _simulator;
    private readonly float _startTime;
    private int _groundEffectCount;
    private MeteorState _meteorState;

    public MeteorEffectReference(Transform effect, MeteorEffectData meteorData, Tab_Effect data,
        int? effectHandle) : base(data, effect, effectHandle)
    {
        _groundEffectCount = 0;
        _meteorData = meteorData;
        _startTime = Time.unscaledTime;
        _meteorState = MeteorState.Wait;
        var z = _meteorData.fallPosition - _meteorData.holdPosition;
        var x = Vector3.Cross(Vector3.up, z);
        var y = Vector3.Cross(z, x);
        if (y == Vector3.zero)
            y = Vector3.up;
        effect.rotation = Quaternion.LookRotation(z, y);
        _meteorController = effect.GetComponent<MeteorEffectController>();
        var collider = effect.GetComponentInChildren<Collider>();
        if (collider != null)
            collider.gameObject.layer = ActiveScene.obstacleLayer;
        if (_meteorController != null)
            Move();
    }

    public override bool Update()
    {
        // 只通过句柄删除
        var valid = base.Update() && _meteorController != null;
        if (valid)
            Move();
        return valid;
    }

    private void Move()
    {
        MeteorState nextState;
        if (Time.unscaledTime < _startTime + _meteorData.holdTime)
            nextState = MeteorState.Wait;
        else if (Time.unscaledTime < _startTime + _meteorData.fallTime)
            nextState = MeteorState.Fall;
        else if (Time.unscaledTime < _startTime + _meteorData.rollTime)
            nextState = MeteorState.Roll;
        else
            nextState = MeteorState.End;
        if (_meteorState != nextState)
        {
            _meteorState = nextState;
            //if (_meteorState == MeteorState.End)
            //{
            //    var distance = Vector3.Distance(_meteorData.rollPosition, _meteorData.fallPosition);
            //    var pitch = distance * _distanceToPitch;
            //    effect.rotation = _startQuaternion * Quaternion.Euler(pitch, 0f, 0f);
            //}
            if (_meteorState == MeteorState.Roll)
                _meteorController.SetOnGround(true);
        }

        switch (_meteorState)
        {
            case MeteorState.Wait:
            {
                effect.position = _meteorData.holdPosition;
            }
                break;
            case MeteorState.Fall:
            {
                var ratio = (Time.unscaledTime - _startTime - _meteorData.holdTime) /
                            (_meteorData.fallTime - _meteorData.holdTime);
                effect.position = Vector3.Lerp(_meteorData.holdPosition,
                    _meteorData.fallPosition + Vector3.up * _meteorController.radius, ratio);
            }
                break;
            case MeteorState.Roll:
            {
                var ratio = (Time.unscaledTime - _startTime - _meteorData.fallTime) /
                            (_meteorData.rollTime - _meteorData.fallTime);
                var effectPos = Vector3.Lerp(_meteorData.fallPosition, _meteorData.rollPosition, ratio);
                var distance = Vector3.Distance(effect.position, _meteorData.fallPosition);
                _meteorController.SetRotationByDistance(distance);
                effect.position = effectPos + _meteorController.radius * Vector3.up;

                CreateGroundEffect(distance);
            }
                break;
            default:
                effect.position = _meteorData.rollPosition + _meteorController.radius * Vector3.up;
                break;
        }
    }

    private void CreateGroundEffect(float distance)
    {
        if (distance > _groundEffectCount)
        {
            // 制造第一个地面特效
            var groundEffectId = data.GetParamValuebyIndex(1);
            if (groundEffectId >= 0)
            {
                var time = Time.unscaledDeltaTime - _startTime - _meteorData.fallTime;
                var groundData = CommonUtility.TryGetTable(groundEffectId, a => TableManager.GetEffectByID(a, 0));
                if (groundData != null && groundData.Duration > time)
                    IndependentEffectManager.Instance.ShowEffect(groundEffectId, effect.gameObject.layer, GameDefine_Globe.OBJ_TYPE.OBJ,
                        effect.position - _meteorController.radius * Vector3.up,
                        Quaternion.identity, groundData.Duration - time);
            }

            _groundEffectCount = Mathf.FloorToInt(distance) + 1;
        }
    }

    private enum MeteorState
    {
        Wait, // 下落前
        Fall, // 下落中
        Roll, // 落地后
        End // 停止滚动后
    }
}

// 背后神像效果
public class AvatarEffectReference : CommonEffectReference
{
    private readonly AnimationLogic _effectAnim;
    private AnimationLogic _characterAnim;

    public AvatarEffectReference(Transform effect, Tab_Effect data, int? effectHandle, float endTime) : base(effect,
        data, effectHandle, endTime)
    {
        _effectAnim = effect.gameObject.EnsureComponent<AnimationLogic>();
        _effectAnim.InitAnimLogicData(effect.GetComponentInChildren<Animator>(), null);
        _effectAnim.enabled = true;
    }

    public void Init(Obj_Character objCharacter)
    {
        // 注:Obj本身必然会在特效执行前执行事件绑定,因此特效监听到的时机必然在Obj执行过模型初始化
        objCharacter.ModelNode.onModelCreate += OnCharacterModelCreate;
        objCharacter.ModelNode.onModelDestroy += OnCharacterModelRemove;
        if (objCharacter.ModelNode.model != null)
            OnCharacterModelCreate(objCharacter.ModelNode.model, null);
        effect.SetParent(objCharacter.ObjTransform);
        effect.localPosition = new Vector3(data.OffsetX, data.OffsetY, data.OffsetZ);
        effect.localScale = Vector3.one * (data.Scale > 0 ? data.Scale : 1f);
        effect.localRotation = Quaternion.identity;
    }

    private void OnCharacterModelCreate(ObjPartRoot partRoot, object args)
    {
        _characterAnim = partRoot.GetComponent<AnimationLogic>();
        if (_characterAnim != null)
            _characterAnim.onPlayAnim += OnCharacterPlayAnim;
    }

    private void OnCharacterModelRemove(ObjPartRoot partRoot)
    {
        if (_characterAnim != null)
        {
            _characterAnim.onPlayAnim -= OnCharacterPlayAnim;
            _characterAnim = null;
        }
    }

    public override void EndEffect()
    {
        base.EndEffect();
        if (_characterAnim != null)
            _characterAnim.onPlayAnim -= OnCharacterPlayAnim;
    }

    private void OnCharacterPlayAnim(Tab_Animation animData, string transitionName)
    {
        if (_effectAnim != null)
            _effectAnim.Play(animData);
    }
}

/// <summary>
///     模拟子弹运动轨迹的模拟器
/// </summary>
public class BulletSimulator
{
    // 子弹预期命中目标时间
    public float duration;

    // 子弹在上一帧的行走时间记录
    public float lastRatio;

    // 子弹逻辑位置记录 - 抛物线子弹逻辑位置和显示位置不一致
    public Vector3 logicPoint;

    // 子弹飞行开始时间
    public float startTime;

    // 子弹目标位置
    public Vector3 targetPoint;

    public BulletSimulator()
    {
    }

    public BulletSimulator(Vector3 startPoint, Vector3 targetPoint, float duration, float startTime = -1f)
    {
        this.startTime = startTime < 0f ? Time.time : startTime;
        this.duration = duration;
        logicPoint = startPoint;
        this.targetPoint = targetPoint;
        lastRatio = 0f;
    }

    public Vector3 UpdateBullet()
    {
        // 计算子弹飞行时间百分比
        var ratio = duration > 0f ? (Time.time - startTime) / duration : 1f;
        var lastPoint = logicPoint;
        var direction = Vector3.zero;
        if (ratio >= 1f)
        {
            logicPoint = targetPoint;
            if (lastRatio < 1f)
                direction = logicPoint - lastPoint;
        }
        else
        {
            var deltaRatio = (ratio - lastRatio) / (1f - lastRatio);
            logicPoint = Vector3.Lerp(logicPoint, targetPoint, deltaRatio);
            direction = logicPoint - lastPoint;
        }

        lastRatio = ratio;
        return direction;
    }
}

#endregion

/// <summary>
///     特效逻辑类型
/// </summary>
public enum CommonEffectType
{
    Bound, // 绑定在节点上面的类型
    Position, // 按照位置特效播放的特效类型
    Bullet, // 子弹类型
    Chain, // 闪电链类型特效
    Stamp, // 印记类型特效
    WuChangLink, // 无常锁链特效
    WuChangAirport, // 无常幽灵机场特效
    Meteor, // 陨石类型特效
    Avatar, // 背后神象效果
    BulletToPos // 对位置攻击的子弹
}

/// <summary>
///     特效旋转策略类型
/// </summary>
public static class EffectRotationType
{
    public const int noRotation = 0;
    public const int faceCamera = 1;
    public const int byEffectType = 2;
}