using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.Zone;
using CommonAI.Zone.Helper;
using CommonLang;
using System;
using System.Collections.Generic;
using CommonAI.Zone.Attributes;
using CommonAI.ZoneClient.Agent;
using CommonLang.Log;



namespace CommonAI.ZoneClient
{

    public class ZoneActor : ZoneUnit
    {
        protected Logger log = LoggerFactory.GetLogger("CommonAI");
        public override float X { get { return mLocalPos.X; } }
        public override float Y { get { return mLocalPos.Y; } }
        public override bool TouchObj
        {
            get
            {
                if (Parent.Templates.CFG.PLAYER_NONE_TOUCH)
                    return false;
                return base.TouchObj;
            }
        }

        /// <summary>
        /// 单位释放技能时,自动朝向锁定敌人
        /// </summary>
        public bool IsSkillAutoFocusTarget { get; set; }

        /// <summary>
        /// 当前是否为自动战斗
        /// </summary>
        public bool IsGuard { get; set; }
        /// <summary>
        /// 当前是否为自动跟随
        /// </summary>
        public bool IsFollow { get; set; }

        //标识是否处于被嘲讽中
        protected bool mIsMocking = false;

        //标识点击了技能按钮,等待服务器下发的DoForceSyncPosEvent中
		//此期间会停止响应移动操作
        //protected int mIsWaittingSkillLaunch = 0;

        /// <summary>
        /// 选中的目标单位
        /// </summary>
        public uint TargetUnitID { get { return (mFocusTarget != null) ? mFocusTarget.targetUnitID : 0; } }

        public PlayerFocuseTargetEvent LastFocusTarget { get { return mFocusTarget; } }
        /// <summary>
        /// 进入场景推送过来的数据
        /// </summary>
        public LockActorEvent LoginData { get { return mLoginData; } }

        public UnitActionStatus RemoteStatus
        {
            get { return mRemoteState.UnitMainState; }
        }


        private readonly LockActorEvent mLoginData;
        // private TimeInterval<int> mCheckGuard;
        private SyncMode mCurrentSyncMode;
        private SyncPosEvent.UnitPos mRemoteSyncPos;
        //private SyncPosEvent.UnitState mRemoteSyncState;
        private UnitAxisAction mSendAxis;
        private bool mSendAxisSmoothTurn = false;
        private Vector2 mSendFaceTo;
        private UnitUpdatePosAction mSendPos;
        private readonly UnitUpdatePosAction mLastSendPos = new UnitUpdatePosAction();
        private readonly float mMinStepSEC;
        private PlayerFocuseTargetEvent mFocusTarget;

        public ZoneActor(UnitInfo unit, LockActorEvent info, ZoneLayer parent)
            : base(unit, info.UnitData, parent, null)
        {
            this.mMinStepSEC = Templates.CFG.OBJECT_MOVE_TO_MIN_STEP_SEC;
            //this.mCheckGuard = new TimeInterval<int>(Templates.CFG.AI_VIEW_TRIGGER_CHECK_TIME_MS);
            this.mLoginData = info;
            this.ResetItems();
            if (info.CurrentPlayerVars != null)
            {
                foreach (CommonAI.ZoneClient.ClientStruct.ZoneEnvironmentVar var in info.CurrentPlayerVars)
                {
                    mEnvironmentVarMap[var.Key] = var.Value;
                }
            }
        }
        protected override void Disposing()
        {
            this.clearAgents();
            this.clearSkillAction();
            base.Disposing();
            //this.mOnGuardFocusTarget = null;
        }
        public override void InitSkills()
        {
            //actor有单独的消息推送,不读配置
        }
        protected internal override void OnAdded()
        {
            base.OnAdded();
            /*if (mLoginData.Skills != null)    //稍后有消息推送,重复了
            {
                this.DoEvent(mLoginData.Skills);
            }*/
            SyncBuffStatus(mLoginData.UnitData.CurrentBuffStatus);
            SyncSkillStatus(mLoginData.CurrentSkillStatus);
            SyncItems(mLoginData.CurrentItemStatus);
            this.mCurrentSyncMode = Parent.ActorSyncMode;
            Parent.SendAction(new UnitSetSyncModeAction(this.ObjectID, Parent.ActorSyncMode));
        }

        //-------------------------------------------------------------------------------------------

        /// <summary>
        /// 截获后端发送的事件
        /// </summary>
        /// <param name="e"></param>
        internal protected override void DoEvent(ObjectEvent e)
        {
            if (Parent.ActorSyncMode == SyncMode.MoveByClient_PreSkillByClient)
            {
                //忽略Jump,客户端本地PreSkillClient已经处理位移//
                if (e is UnitJumpEvent)
                {
                    return;
                }
            }
            
            if (e is PlayerSkillStopEvent)
            {
                doPlayerSkillStopEvent(e as PlayerSkillStopEvent);
            }
            else if (e is UnitForceSyncPosEvent)
            {
                doForceSyncPosEvent(e as UnitForceSyncPosEvent);
            }
            else if (e is UnitSkillActionChangeEvent)
            {
                doUnitSkillActionChangeEvent(e as UnitSkillActionChangeEvent);
            }
            else if (e is UnitSyncInventoryItemEvent)
            {
                DoSyncItem(e as UnitSyncInventoryItemEvent);
            }
            else if (e is UnitUseItemEvent)
            {
                DoUseItem(e as UnitUseItemEvent);
            }

            if (e is UnitForceSyncPosEvent &&
                mCurrentSkillAction is PreSkillByClient)
            {
                var action = mCurrentSkillAction as PreSkillByClient;
                if (action.SkillData.ActionPriority == 0)
                    return;
            }

            base.DoEvent(e);
        }
        //-------------------------------------------------------------------------------------
        #region __Agents__

        private List<AbstractAgent> mAgents = new List<AbstractAgent>(1);
        private List<AbstractAgent> mUpdateAgents = new List<AbstractAgent>(1);

        public int AgentCount { get { return mAgents.Count; } }

        public AbstractAgent AddAgent(AbstractAgent agent)
        {
            if (!agent.IsDuplicate)
            {
                for (int i = mAgents.Count - 1; i >= 0; --i)
                {
                    var ag = mAgents[i];
                    if (agent.GetType() == ag.GetType())
                    {
                        ag.Abort();
                        RemoveAgent(ag);
                    }
                }
            }
            mAgents.Add(agent);
            agent.InternalInit(this);
            //Parent.QueueTask((z) =>
            //{
            //    agent.InternalStart();
            //});
            agent.InternalStart();
            return agent;
        }
        public bool RemoveAgent(AbstractAgent agent)
        {
            if (mAgents.Remove(agent))
            {
                //Parent.QueueTask((z) =>
                //{
                //    agent.InternalEnd();
                //    agent.Dispose();
                //});
                agent.InternalEnd();
                agent.Dispose();
                return true;
            }
            return false;
        }
        public T GetAgentByType<T>() where T : AbstractAgent
        {
            for (int i = 0; i < mAgents.Count; i++)
            {
                if (mAgents[i] is T)
                {
                    return mAgents[i] as T;
                }
            }
            return null;
        }

        private void ForEachAgent(Action<AbstractAgent> action)
        {
            mUpdateAgents.AddRange(mAgents);
            try
            {
                mUpdateAgents.ForEach(action);
            }
            finally
            {
                mUpdateAgents.Clear();
            }
        }

        private void MAgents_OnBeginUpdate(AbstractAgent obj)
        {
            if (obj.IsEnd)
            {
                RemoveAgent(obj);
            }
            else
            {
                obj.InternalBeginUpdate(Parent.CurrentIntervalMS);
            }
        }

        private void MAgents_OnEndUpdate(AbstractAgent obj)
        {
            if (obj.IsEnd)
            {
                RemoveAgent(obj);
            }
            else
            {
                obj.InternalEndUpdate(Parent.CurrentIntervalMS);
            }
        }

        private void ForEachAgentOnBeginUpdate()
        {
            mUpdateAgents.AddRange(mAgents);
            try
            {
                for (int i = 0, n = mUpdateAgents.Count; i < n; i++)
                {
                    MAgents_OnBeginUpdate(mUpdateAgents[i]);
                }
            }
            finally
            {
                mUpdateAgents.Clear();
            }
        }

        private void ForEachAgentOnEndUpdate()
        {
            mUpdateAgents.AddRange(mAgents);
            try
            {
                for (int i = 0, n = mUpdateAgents.Count; i < n; i++)
                {
                    MAgents_OnEndUpdate(mUpdateAgents[i]);
                }
            }
            finally
            {
                mUpdateAgents.Clear();
            }
        }

        private void clearAgents()
        {
            foreach (var agt in mAgents)
            {
                agt.Dispose();
            }
            mAgents.Clear();
        }

        #endregion
        //-------------------------------------------------------------------------------------------
        internal protected override void Update()
        {
            base.Update();
            UpdateItems(Parent.CurrentIntervalMS);
            //ForEachAgent(MAgents_OnEndUpdate);
            ForEachAgentOnEndUpdate();
        }
        //-------------------------------------------------------------------------------------------

        #region __update_预处理__

        internal protected override void UpdateAI()
        {
            ForEachAgentOnBeginUpdate();
            int intervalMS = Parent.CurrentIntervalMS;
            if (IsGuard)
            {
                update_ai_Guard(intervalMS);
            }
            else if (IsFollow)
            {

            }
            else
            {
                if (mCurrentSyncMode != Parent.ActorSyncMode)
                {
                    mCurrentSyncMode = Parent.ActorSyncMode;
                    Parent.SendAction(new UnitSetSyncModeAction(this.ObjectID, Parent.ActorSyncMode));
                }
                switch (Parent.ActorSyncMode)
                {
                    case SyncMode.ForceByServer:
                        update_ai_ForceByServer(intervalMS);
                        break;
                    case SyncMode.MoveByClient_PreSkillByClient:
                        update_ai_MoveByClient_PreSkillByClient(intervalMS);
                        break;
                }
            }
            updateServerSkillAction(intervalMS);
            mSendFaceTo = null;
            mSendPos = null;

        }

        private void update_ai_Guard(int intervalMS)
        {
            base.UpdateAI();
        }

        // 服务端强同步 //
        private void update_ai_ForceByServer(int intervalMS)
        {
            if (mSendAxis != null)
            {
                //请求服务端移动//
                Parent.SendAction(mSendAxis);
            }
            else if (mSendPos != null)
            {
                Parent.SendAction(mSendPos);
            }
        }

        // 客户端本地处理移动,实时上传自己坐标位置,技能预先本地表现 //
        private void update_ai_MoveByClient_PreSkillByClient(int intervalMS)
        {
            UnitAxisAction axis = mSendAxis;

            //有摇杆动作//
            if (axis != null && !axis.IsZero)
            { 
                // 处理技能以及控制位移 //
                if (mCurrentSkillAction is PreSkillByClient)
                {
                    var action = mCurrentSkillAction as PreSkillByClient;
                    
                    //客户端预先技能动作//
                    if (action.IsDone)
                    {
                        base.mDirection = base.mDirectionChange;
                        clearSkillAction();
                        Parent.SendAction(axis);
                        SetCurrentState(UnitActionStatus.Move);
                    }
                    else
                    {
                        if (IsCanControlMove)
                        {
                            Parent.SendAction(axis);
                            if (action.SkillData.ActionPriority == -1 || 
                                action.SkillData.ID == 110500 || 
                                action.SkillData.ID == 110510 ||
                                action.SkillData.ID == 110520 || 
                                action.SkillData.ID == 110530 ||
                                action.SkillData.ID == 110540 ||
                                action.SkillData.ID == 110550 ||
                                action.SkillData.ID == 110560)
                            {
                                action.setMoveTo(axis);
                                SkillState state = action.State;
                                if (state.ActionType == ActionEnum.chargeAtk && state.CurrentActionID == 1)
                                {
                                    this.SetCurrentState(UnitActionStatus.ChargeAtkMove, 0, null);
                                }
                            }
                        }
                    }
                }
                else if (mCurrentSkillAction is PreSkillByServer)
                {
                    float direction = MathVector.getDegree(axis.dx, axis.dy);
                    if (IsCanControlMove)
                    {
                        float ispeed = MoveHelper.GetDistance(intervalMS, base.MoveSpeedSEC);
                        float addX = (float)(Math.Cos(direction) * ispeed);
                        float addY = (float)(Math.Sin(direction) * ispeed);
                        var action = mCurrentSkillAction as PreSkillByServer;
                        if (action != null && action.State != null && action.State.ActionType == ActionEnum.chargeAtk)
                        {
                            this.SetCurrentState(UnitActionStatus.ChargeAtkMove);
                        }

                        this.PreBlockMove(ref addX, ref addY);
                        this.PreMove(addX, addY);
                    }
                    if (IsCanControlFaceTo)
                    {
                        if (mSendAxisSmoothTurn)
                        {
                            base.mDirectionChange = direction;
                            base.mDirection = MoveHelper.DirectionChange(
                                mDirectionChange,
                                mDirection,
                                this.TurnSpeedSEC,
                                intervalMS);
                        }
                        else
                        {
                            base.mDirection = direction;
                            base.mDirectionChange = direction;
                        }
                    }
                }
                else
                {
                    //if (mCurrentSkillAction == null && mIsWaittingSkillLaunch > 0)
                    //{
                    //    launchSkill消息还没下发,暂停移动,解决移动--》普攻的位移抖动
                    //    --mIsWaittingSkillLaunch;
                    //    YXJDebug.logWarning(">>ignore moving, when waitting launching skill:{0}", mIsWaittingSkillLaunch);
                    //}
                    //else
                    {
                        float ispeed = MoveHelper.GetDistance(intervalMS, base.MoveSpeedSEC);
                        float direction = MathVector.getDegree(axis.dx, axis.dy);
                        float addX = (float)(Math.Cos(direction) * ispeed);
                        float addY = (float)(Math.Sin(direction) * ispeed);
                        if (IsCanControlMove)
                        {
                            this.PreBlockMove(ref addX, ref addY);
                            this.PreMove(addX, addY);
                            this.SetCurrentState(UnitActionStatus.Move);
                        }
                        if (IsCanControlFaceTo)
                        {
                            if (mSendAxisSmoothTurn)
                            {
                                base.mDirectionChange = direction;
                                base.mDirection = MoveHelper.DirectionChange(
                                    mDirectionChange,
                                    mDirection,
                                    this.TurnSpeedSEC,
                                    intervalMS);
                            }
                            else
                            {
                                base.mDirection = direction;
                                base.mDirectionChange = direction;
                            }
                        }
                    }
                }
            }
            else
            {
                //停止技能移动//
                if (mCurrentSkillAction is PreSkillByClient)
                {
                    var action = mCurrentSkillAction as PreSkillByClient;
                    action.setMoveTo(null);

                    SkillState state = action.State;
                    if (state.ActionType == ActionEnum.chargeAtk && state.CurrentActionID > 0)
                    {
                        this.SetCurrentState(UnitActionStatus.ChargeAtkIdle);
                    }
                }
                //处理UpdatePos移动//
                else if (mSendPos != null)
                {
                    if (IsCanControlFaceTo)
                    {
                        base.mDirection = mSendPos.d;
                        base.mDirectionChange = mSendPos.d;
                    }
                    if (IsCanControlMove)
                    {
                        SetCurrentState(mSendPos.st);
                        this.PreSetPos(mSendPos.x, mSendPos.y);
                    }
                }
                else
                {
                    if (!mIsMocking && CurrentState == UnitActionStatus.Move)
                    {
                        SetCurrentState(UnitActionStatus.Idle);
                    }

                    //嘲讽时间到了后,服务器没有置状态,客户端强制置回(有隐患)
                    if (CurrentState == UnitActionStatus.ServerSyncMove && (CurrentSubState & (byte)UnitActionSubStatus.Mocking) == 0)
                    {
                        SetCurrentState(UnitActionStatus.Idle);
                    }
                }
                if (mSendFaceTo != null)
                {
                    if (mCurrentSkillAction is PreSkillByClient)
                    {
                        var action = mCurrentSkillAction as PreSkillByClient;
                        //客户端预先技能动作//
                        if (!action.IsDone)
                        {
                            action.setFaceTo(mSendFaceTo);
                        }
                        else
                        {
                            this.PreFaceTo(mSendFaceTo.X, mSendFaceTo.Y);
                        }
                    }
                    else if (CurrentState == UnitActionStatus.Move || CurrentState == UnitActionStatus.Idle)
                    {
                        this.PreFaceTo(mSendFaceTo.X, mSendFaceTo.Y);
                    }
                }
            }

            //有主动控制位移状态//
            if (CurrentState == UnitActionStatus.Move || CurrentState == UnitActionStatus.Idle || mCurrentSkillAction != null)
            {
                if (mSkillMove != null && mSkillMove.Update(intervalMS))
                {
                    mIsSkillMove = false;
                    mSkillMove = null;
                }
            }
            else
            {
                FixPos(intervalMS, mLocalPos, mPos);
                if (mSkillMove != null)
                {
                    mSkillMove.Stop();
                    mSkillMove = null;
                }
            }
            //客户端预先技能动作//
            if (mCurrentSkillAction is PreSkillByClient)
            {
                var action = mCurrentSkillAction as PreSkillByClient;
                action.onUpdate(intervalMS);
                if (mCurrentSkillAction.IsDone)
                {
                    clearSkillAction();
                }
            }
            updatePosActionCache.object_id = this.ObjectID;
            updatePosActionCache.isHalf = Parent.IsHalfSync;
            updatePosActionCache.x = mLocalPos.X;
            updatePosActionCache.y = mLocalPos.Y;
            updatePosActionCache.d = mDirection;
            updatePosActionCache.st = CurrentState;
            if (!updatePosActionCache.DataEquals(mLastSendPos))
            {
                //YXJDebug.logWarning(">>>>>>>>>>>>>>>SendServerPos:{0},{1}", updatePosActionCache.x, updatePosActionCache.y);
                Parent.SendAction(updatePosActionCache);
            }
            mLastSendPos.Set(updatePosActionCache);
        }
        private readonly UnitUpdatePosAction updatePosActionCache = new UnitUpdatePosAction();
        #endregion

        //-----------------------------------------------------------------------------------------------------------
        #region __sync_pos_同步服务器坐标__

        //-------------------------------------------------------------------------------------------

        private void doForceSyncPosEvent(UnitForceSyncPosEvent e)
        {
            //YXJDebug.logError(">>Player_DoForceSyncPosEvent:{0},{1}, state:{2},{3}", e.X, e.Y, e.UnitMainState, e.UnitSubState);
            if (this.Parent != null && this.Parent.IsSceneDujie() && e.UnitMainState == (byte)UnitActionStatus.Move)
            {
                //YXJDebug.logWarning(">IgnoreForceSyncPos_p@move: {0}{1}, state:{2},{3}", ObjectID, Name, e.UnitMainState, e.UnitSubState);
                return;
            }
            //技能移动本地做预演,坐标修正在update中去做(服务器协议发错,应该是syncpos,之前已经告知服务器)
            if ((UnitActionStatus)e.UnitMainState != UnitActionStatus.Skill)
            {
                ForceSyncPos(e.X, e.Y);
            }
            //else if ((e.UnitSubState & (byte)UnitActionSubStatus.ChargeAtkIdle) != 0)
            //{
            //    mIsWaittingSkillLaunch = 0;
            //}
            this.mDirection = mDirectionChange = mRemoteSyncPos.Direction = e.Direction;
            this.mRemoteState.UnitMainState = (UnitActionStatus)e.UnitMainState;
            this.mRemoteState.UnitSubState = e.UnitSubState;
            base.SetCurrentState(ref mRemoteState);

            if (mCurrentSkillAction != null)
            {
                if (RemoteStatus != UnitActionStatus.Skill)
                {
                    clearSkillAction();
                }
                else if(mCurrentSkillAction.SkillData.ID == 603064) //成魔3技能,要支持Blink,,,暂时先这么着
                {
                    ForceSyncPos(e.X, e.Y);
                }
            }
        }

        protected internal override void UpdatePos(int intervalMS)
        {
            if (IsGuard || IsFollow || mIsMocking)
            {
                base.UpdatePos(intervalMS);
            }
        }

        public override void SyncPos(ref SyncPosEvent.UnitState pos)
        {
            //if(mIsWaittingSkillLaunch > 0)
            //{
            //    if(pos.UnitMainState != UnitActionStatus.Skill)
            //    {
            //        mIsWaittingSkillLaunch = 0;
            //    }
            //}
            //更新被嘲讽状态
            mIsMocking = (pos.UnitSubState & (byte)UnitActionSubStatus.Mocking) != 0;
            this.mRemoteState = pos;
            if (IsGuard || IsFollow)
            {
                this.SetCurrentState(ref mRemoteState);
            }
            else
            {
                switch (Parent.ActorSyncMode)
                {
                    case SyncMode.ForceByServer:
                        sync_pos_ForceByServer(ref pos);
                        break;
                    case SyncMode.MoveByClient_PreSkillByClient:
                        sync_pos_MoveByClient_PreSkillByClient(ref pos);
                        break;
                }
                if (pos.UnitSubState != this.CurrentSubState)
                {
                    base.SetCurrentSubState(pos.UnitSubState);
                }
            }
        }
        public override void SyncPos(ref SyncPosEvent.UnitPos pos)
        {
            this.mRemoteSyncPos = pos;
            if (IsGuard || IsFollow)
            {
                base.mDirection = pos.Direction;
                base.mDirectionChange = pos.Direction;
                base.SyncPos(ref pos);
            }
            else
            {
                base.mPos.SetX(pos.X);
                base.mPos.SetY(pos.Y);
                switch (Parent.ActorSyncMode)
                {
                    case SyncMode.ForceByServer:
                        sync_pos_ForceByServer(ref pos);
                        break;
                    case SyncMode.MoveByClient_PreSkillByClient:
                        sync_pos_MoveByClient_PreSkillByClient(ref pos);
                        break;
                }
                //YXJDebug.logWarning(">>{0}>PlayersyncPos, curState:{1}/{2}-->{3}/{4}, x:{5},y:{6}", Name, (int)CurrentState, (int)CurrentSubState, (int)mRemoteState.UnitMainState, (int)mRemoteState.UnitSubState, pos.X, pos.Y);
                if (mIsMocking)
                {
                    this.mDirectionChange = pos.Direction;
                    this.mDirection = MoveHelper.DirectionChange(mDirectionChange, mDirection, mTurnSpeedSEC, Parent.CurrentIntervalMS);
                    if (CurrentState == UnitActionStatus.Idle && mRemoteState.UnitMainState == UnitActionStatus.Move)
                    {
                        this.SetCurrentState(ref mRemoteState);
                    }
                }
            }
        }

        private void sync_pos_ForceByServer(ref SyncPosEvent.UnitState pos)
        {
            this.SetCurrentState(ref pos);
        }
        private void sync_pos_ForceByServer(ref SyncPosEvent.UnitPos pos)
        {
            // 强同步 //
            base.mLocalPos.SetX(pos.X);
            base.mLocalPos.SetY(pos.Y);
            base.mDirection = pos.Direction;
            base.mDirectionChange = pos.Direction;
            if (Parent.IsSyncZ) { this.Z = pos.Z; }
        }

        private void sync_pos_MoveByClient_PreSkillByClient(ref SyncPosEvent.UnitState pos)
        {
            if (CurrentState == UnitActionStatus.Idle || CurrentState == UnitActionStatus.Move || CurrentState == UnitActionStatus.ServerSyncMove)
            {
                if (RemoteStatus == UnitActionStatus.Skill)
                {
                    this.SetCurrentState(ref mRemoteState);
                }
                else if (RemoteStatus != UnitActionStatus.Idle && RemoteStatus != UnitActionStatus.Move && RemoteStatus != UnitActionStatus.ServerSyncMove)
                {
                    this.SetCurrentState(ref mRemoteState);
                }
                //不能移动切入,状态置成Idle(不应该有互斥状态存在 跑和不能移动)
                else if (pos.UnitMainState == UnitActionStatus.Move && (pos.UnitSubState & (byte)UnitActionSubStatus.CanNotMove) != 0)
                {
                    this.SetCurrentState(ref mRemoteState);
                }
            }
            else
            {
                this.SetCurrentState(ref mRemoteState);
            }
            if (mCurrentSkillAction != null)
            {
                if (RemoteStatus != UnitActionStatus.Skill)
                {
                    clearSkillAction();
                }
            }

            //if (SetStealtState != null)
            //{
            //    log.Error("SetStealtState :" + ((pos.UnitSubState & (byte)UnitActionSubStatus.Stealth) != 0).ToString());
            //    SetStealtState((pos.UnitSubState & (byte)UnitActionSubStatus.Stealth) != 0);
            //}
        }

        private void sync_pos_MoveByClient_PreSkillByClient(ref SyncPosEvent.UnitPos pos)
        {
            if (CurrentState == UnitActionStatus.Idle || CurrentState == UnitActionStatus.Move || CurrentState == UnitActionStatus.ServerSyncMove)
            {
                if (RemoteStatus == UnitActionStatus.Skill)
                {

                }
                else if (RemoteStatus != UnitActionStatus.Idle && RemoteStatus != UnitActionStatus.Move && RemoteStatus != UnitActionStatus.ServerSyncMove)
                {
                    base.mDirection = pos.Direction;
                    base.mDirectionChange = pos.Direction;
                }
            }
            else
            {
                // 强同步 //
                if (RemoteStatus != UnitActionStatus.Skill &&
                    RemoteStatus != UnitActionStatus.Idle &&
                    RemoteStatus != UnitActionStatus.Move)
                {
                    base.mDirection = pos.Direction;
                    base.mDirectionChange = pos.Direction;
                    //UnityEngine.Debug.Log("syncpos ID = " + pos.ID + "  D = " + pos.Direction);
                }
            }
        }

        #endregion


        //-------------------------------------------------------------------------------------------
        #region __Item__

        private HashMap<int, TimeExpire<ItemTemplate>> mCoolDownItems = new HashMap<int, TimeExpire<ItemTemplate>>();

        internal void SyncItems(ClientStruct.UnitItemStatus[] items)
        {
            if (items != null)
            {
                mItemSlots = new List<ItemSlot>(items.Length);
                foreach (ClientStruct.UnitItemStatus st in items)
                {
                    ItemSlot slot = new ItemSlot(this);
                    if (st.Count > 0)
                    {
                        slot.Sync(st);
                    }
                    mItemSlots.Add(slot);
                }
            }
        }

        private void ResetItems()
        {
            mItemSlots = new List<ItemSlot>(Info.InventorySize);
            for (int i = 0; i < Info.InventorySize; i++)
            {
                mItemSlots.Add(new ItemSlot(this));
            }
        }

        private void UpdateItems(int intervalMS)
        {
            if (mCoolDownItems.Count > 0)
            {
                using (var removed = ListObjectPool<TimeExpire<ItemTemplate>>.AllocAutoRelease())
                {
                    foreach (TimeExpire<ItemTemplate> expire in mCoolDownItems.Values)
                    {
                        if (expire.Update(intervalMS))
                        {
                            removed.Add(expire);
                        }
                    }
                    if (removed.Count > 0)
                    {
                        foreach (TimeExpire<ItemTemplate> expire in removed)
                        {
                            if (expire.IsEnd)
                            {
                                mCoolDownItems.RemoveByKey(expire.Tag.ID);
                            }
                        }
                    }
                }
            }
        }

        protected virtual void DoSyncItem(UnitSyncInventoryItemEvent me)
        {
            ItemSlot slot = GetItem(me.Index);
            if (slot != null)
            {
                slot.Set(me);
            }
        }

        protected virtual void DoUseItem(UnitUseItemEvent me)
        {
            ItemTemplate item = Templates.getItem(me.ItemTemplateID);
            if (item != null)
            {
                if (item.UseCoolDownTimeMS > 0)
                {
                    mCoolDownItems.Put(item.ID, new TimeExpire<ItemTemplate>(item, item.UseCoolDownTimeMS));
                }
            }
        }

        public TimeExpire<ItemTemplate> GetCoolDownItem(int itemTemplateID)
        {
            return mCoolDownItems.Get(itemTemplateID);
        }

        internal List<ItemSlot> mItemSlots = new List<ItemSlot>();

        public class ItemSlot
        {
            public ZoneUnit Owner { get; private set; }
            private ItemTemplate data;
            private int count;

            public bool IsEmpty { get { return count == 0 || data == null; } }
            public ItemTemplate Data { get { return data; } }
            public int Count { get { return count; } }

            public ItemSlot(ZoneUnit unit)
            {
                this.Owner = unit;
            }

            internal void Sync(ClientStruct.UnitItemStatus syn)
            {
                ItemTemplate item = Owner.Templates.getItem(syn.ItemTemplateID);
                if (item != null)
                {
                    this.data = item;
                    this.count = syn.Count;
                }
            }

            internal void Set(UnitSyncInventoryItemEvent me)
            {
                if (this.data != null && this.data.ID == me.ItemTemplateID)
                {
                    this.count = me.Count;
                    return;
                }
                ItemTemplate item = Owner.Templates.getItem(me.ItemTemplateID);
                if (item != null)
                {
                    this.data = item;
                    this.count = me.Count;
                }
            }
        }

        [Obsolete]
        public List<ItemSlot> GetItemSlots()
        {
            return new List<ItemSlot>(mItemSlots);
        }
        public void GetItemSlots(List<ItemSlot> ret)
        {
            ret.AddRange(mItemSlots);
        }

        public ItemSlot GetItem(int index)
        {
            if (index >= 0 && index < mItemSlots.Count)
            {
                return mItemSlots[index];
            }
            return null;
        }

        public ItemSlot GetItemByTemplateID(int itemTemplateID)
        {
            for (int i = mItemSlots.Count - 1; i >= 0; --i)
            {
                ItemSlot slot = mItemSlots[i];
                if (!slot.IsEmpty && slot.Data.TemplateID == itemTemplateID)
                {
                    return slot;
                }
            }
            return null;
        }

        #endregion

        //-----------------------------------------------------------------------------------------------------------
        #region __SEND_ACTION_TO_SERVER__

        public void SendAction(ObjectAction act)
        {
            Parent.SendAction(act);
        }
        public void SendRequest(ActorRequest req, ZoneLayer.OnResponseHandler handler, ZoneLayer.OnRequestTimeoutHandler timeout = null, int timeOutMS = 15000)
        {
            Parent.SendRequest(req, handler, timeout, timeOutMS);
        }

        public void SendReady()
        {
            Parent.SendAction(new UnitReadAction(base.ObjectID));
        }
        
        public void SendUnitAxis(float angle, bool smooth_turn = false)
        {
            this.mSendPos = null;
            if (IsGuard || IsFollow) return;
            UnitAxisAction ma = new UnitAxisAction(base.ObjectID);
            ma.dx = (float)Math.Cos(angle);
            ma.dy = (float)Math.Sin(angle);
            mSendAxis = ma;
            mSendAxisSmoothTurn = smooth_turn;
        }

        public void SendUnitAxis(float dx, float dy, bool smooth_turn = false)
        {
            this.mSendPos = null;
            if (IsGuard || IsFollow) return;
            UnitAxisAction ma = new UnitAxisAction(base.ObjectID);
            ma.dx = dx;
            ma.dy = dy;
            mSendAxis = ma;
            mSendAxisSmoothTurn = smooth_turn;
        }

        public void SendUpdatePos(float x, float y, float direction, UnitActionStatus st)
        {
            mSendAxis = null;
            if (IsGuard || IsFollow)
            {
                return;
            }
            if (Parent.ActorSyncMode != SyncMode.MoveByClient_PreSkillByClient)
            {
                return;
            }
            this.mSendPos = new UnitUpdatePosAction(this.ObjectID, Parent.IsHalfSync, x, y, direction, st);
        }

        public void SendUnitMove(float x, float y)
        {
            mSendAxis = null;
            mSendPos = null;
            if (!IsGuard) return;
            if (Parent.ActorSyncMode == SyncMode.MoveByClient_PreSkillByClient) return;
            UnitMoveAction ma = new UnitMoveAction(base.ObjectID, x, y);
            Parent.SendAction(ma);
        }

        public void SendUnitFaceTo(float d)
        {
            if (Parent.ActorSyncMode == SyncMode.MoveByClient_PreSkillByClient)
            {
                float dx = (float)Math.Cos(d) * 100;
                float dy = (float)Math.Sin(d) * 100;
                this.mSendFaceTo = new Vector2(dx + this.X, dy + this.Y);
            }
            UnitFaceToAction ma = new UnitFaceToAction(base.ObjectID, d);
            //UnityEngine.Debug.Log("SendUnitFaceTo d = " + d);
            Parent.SendAction(ma);
        }

        public void SendUnitFaceTo(float wx, float wy)
        {
            float d = (float)Math.Atan2(wy - this.Y, wx - this.X);
            if (Parent.ActorSyncMode == SyncMode.MoveByClient_PreSkillByClient)
            {
                this.mSendFaceTo = new Vector2(wx, wy);
            }
            UnitFaceToAction ma = new UnitFaceToAction(base.ObjectID, d);
            Parent.SendAction(ma);
        }

        public void SendUnitStopMove()
        {
            mSendAxis = null;
            mSendPos = null;
            UnitStopMoveAction ma = new UnitStopMoveAction(base.ObjectID);
            Parent.SendAction(ma);
        }


        public void SendUnitSlip(float x, float y)
        {
            mSendAxis = null;
            mSendPos = null;
            if (Parent.ActorSyncMode == SyncMode.MoveByClient_PreSkillByClient) return;
            UnitSlipAction ma = new UnitSlipAction(base.ObjectID, x, y);
            Parent.SendAction(ma);
        }

        /// <summary>
        /// 新增技能移动
        /// </summary>
        /// <param name="skillMove"></param>
        public void SendUnitSkillMove(SkillMove skillMove)
        {
            var skill = this.GetSkillState(skillMove.SkillID);
            if (skill != null)
            {
                Parent.SendAction(skillMove);
            }
        }

        public void SendUnitLaunchSkill(UnitLaunchSkillAction launch)
        {
            //mSendAxis = null;
            //mSendPos = null;
            var skill = this.GetSkillState(launch.SkillID);
            if (skill != null)
            {
                Parent.SendAction(launch);
                //mIsWaittingSkillLaunch = 10;
                //YXJDebug.logWarning(">>LaunchSkill:{0}", launch.SkillID);
            }
        }
        public void SendUnitLaunchSkill(int skillID, uint targetObjectID)
        {
            UnitLaunchSkillAction launch = new UnitLaunchSkillAction(base.ObjectID, skillID);
            launch.IsAutoFocusNearTarget = IsSkillAutoFocusTarget;
            launch.TargetObjID = targetObjectID;
            SendUnitLaunchSkill(launch);
        }

        public void SendUnitLaunchSkill(int skillID)
        {
            UnitLaunchSkillAction launch = new UnitLaunchSkillAction(base.ObjectID, skillID);
            launch.IsAutoFocusNearTarget = IsSkillAutoFocusTarget;
            SendUnitLaunchSkill(launch);
        }
        public void SendUnitLaunchSkill(int skillID, float x, float y)
        {
            UnitLaunchSkillAction launch = new UnitLaunchSkillAction(base.ObjectID, skillID);
            launch.IsAutoFocusNearTarget = IsSkillAutoFocusTarget;
            if (x != X || y != Y)
            {
                launch.SpellTargetPos = new Vector2(x, y);
            }
            SendUnitLaunchSkill(launch);
        }
        public void SendUnitLaunchNormalAttack(float x, float y)
        {
            UnitLaunchSkillAction launch = new UnitLaunchSkillAction(base.ObjectID, BaseSkillID);
            launch.IsAutoFocusNearTarget = IsSkillAutoFocusTarget;
            if (x != X || y != Y)
            {
                launch.SpellTargetPos = new Vector2(x, y);
            }
            SendUnitLaunchSkill(launch);
        }

        public void SendUnitGuard(bool auto)
        {
            mSendAxis = null;
            mSendPos = null;
            //IsGuard = auto;
            Parent.SendAction(new UnitGuardAction(ObjectID, auto));
        }

        public void SendUnitFollow(bool auto)
        {
            mSendAxis = null;
            mSendPos = null;
            //IsFollow = auto;
            Parent.SendAction(new UnitFollowAction(ObjectID, auto));
        }

        public void SendUnitGuard(bool auto, string reason)
        {
            mSendAxis = null;
            mSendPos = null;
            //IsGuard = auto;
            Parent.SendAction(new UnitGuardAction(ObjectID, auto, reason));
        }

        public void SendUnitAttackMoveTo(float x, float y, bool attack = false)
        {
            UnitAttackToAction ma = new UnitAttackToAction(base.ObjectID, x, y, attack);
            Parent.SendAction(ma);
        }
        public void SendUnitFocuseTarget(uint targetID)
        {
            if ((Parent.GetObject(targetID) != null))
            {
                UnitFocuseTargetAction ma = new UnitFocuseTargetAction(base.ObjectID, targetID);
                Parent.SendAction(ma);
            }
        }

        public void SendUnitUseItem(int index, int count = 1)
        {
            UnitUseItemAction use = new UnitUseItemAction(base.ObjectID, index, count);
            Parent.SendAction(use);
        }

        public void SendUnitPickObject(uint pickableID)
        {
            mSendAxis = null;
            mSendPos = null;
            UnitPickObjectAction act = new UnitPickObjectAction(ObjectID, pickableID);
            Parent.SendAction(act);
        }

        public void SendCancelBuff(int buffID)
        {
            BuffState bs = GetBuff(buffID);
            if (bs != null)
            {
                UnitCancelBuffAction act = new UnitCancelBuffAction(ObjectID, bs.Data.TemplateID);
                Parent.SendAction(act);
            }
        }

        public void SendSetSubState(byte substate)
        {
            UnitSetSubStateAction use = new UnitSetSubStateAction(base.ObjectID, substate);
            Parent.SendAction(use);
        }

        //新增回城状态
        public void SetLocalClientState(UnitActionStatus states, object evt)
        {
            SetCurrentState(states, evt);
        }

        #endregion
        //-----------------------------------------------------------------------------------------------------------

        #region __PreMoveAndSkill__

        public virtual bool IsCanControlMove
        {
            get
            {
                //渡劫地图
                if(Parent!= null && Parent.IsSceneDujie())
                {
                    if (CurrentState == UnitActionStatus.Idle)
                    {
                        //YXJDebug.logError(">>在渡劫场景,try to move??{0}", CurrentState);
                    }
                    return false;
                }

                //收到不能移动的状态,就是不能动
                if ((CurrentSubState & (byte)UnitActionSubStatus.CanNotMove) != 0)
                {
                    return false;
                }

                if (CurrentState == UnitActionStatus.Skill)
                {
                    if (this.CurrentActorSkillAction is PreSkillByClient)
                    {
                        var st = this.CurrentActorSkillAction as PreSkillByClient;
                        return st.IsControlMoveable;
                    }
                    else if (this.CurrentActorSkillAction is PreSkillByServer)
                    {
                        var st = this.CurrentActorSkillAction as PreSkillByServer;
                        return st.IsControlMoveable;
                    }

                    return false;
                }

                return (CurrentState == UnitActionStatus.Move || CurrentState == UnitActionStatus.Idle || CurrentState == UnitActionStatus.Pick || CurrentState == UnitActionStatus.DaZuo || CurrentState == UnitActionStatus.DaZuoRecoveryAttr || CurrentState == UnitActionStatus.ChargeAtkIdle || CurrentState == UnitActionStatus.ChargeAtkMove || CurrentState == UnitActionStatus.HomeBack);
            }
        }
        public virtual bool IsCanControlFaceTo
        {
            get
            {
                if (CurrentState == UnitActionStatus.Skill)
                {
                    if (this.CurrentActorSkillAction is PreSkillByClient)
                    {
                        var st = this.CurrentActorSkillAction as PreSkillByClient;
                        return st.IsControlFaceable;
                    }
                    else if (this.CurrentActorSkillAction is PreSkillByServer)
                    {
                        var st = this.CurrentActorSkillAction as PreSkillByServer;
                        return st.IsControlFaceable;
                    }
                    return false;
                }
                return CurrentState == UnitActionStatus.Move || CurrentState == UnitActionStatus.Idle || CurrentState == UnitActionStatus.Pick || CurrentState == UnitActionStatus.ChargeAtkIdle || CurrentState == UnitActionStatus.ChargeAtkMove;
            }
        }

        private PreSkillStartMove mSkillMove = null;

        internal protected void PreFaceTo(float x, float y)
        {
            if (this.X == x && this.Y == y)
            {
                return;
            }
            float d = (float)(Math.Atan2(y - this.Y, x - this.X));
            if (d != mDirection || d != this.mDirectionChange)
            {
                this.mDirection = this.mDirectionChange = d;
            }
        }
        internal protected void PreTurnTo(float add)
        {
            this.mDirection += add;
            this.mDirectionChange = this.mDirection;
        }

        /// <summary>
        /// 尝试客户端移动
        /// </summary>
        /// <returns>TRUE=无法移动</returns>
        internal protected bool PreMoveTo(float x, float y, float speedSEC, int intervalMS)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            float minstep = MoveHelper.GetDistance(intervalMS, mMinStepSEC);
            if (Math.Abs(distance) < minstep)
            {
                return true;
            }
            float ddx = x - mLocalPos.X;
            float ddy = y - mLocalPos.Y;
            if (Math.Abs(ddx) < distance && Math.Abs(ddy) < distance)
            {
                return false;
            }
            float angle = MathVector.getDegree(ddx, ddy);
            return PreMoveToInner(angle, distance);
        }

        /// <summary>
        /// 尝试客户端移动
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="speedSEC"></param>
        /// <param name="intervalMS"></param>
        /// <returns>TRUE=无法移动</returns>
        internal protected bool PreMoveTo(float angle, float speedSEC, int intervalMS)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            float minstep = MoveHelper.GetDistance(intervalMS, mMinStepSEC);
            if (Math.Abs(distance) < minstep)
            {
                return true;
            }
            mIsSkillMove = true;
            return PreMoveToInner(angle, distance);
        }
        internal protected bool PreMoveToInner(float angle, float distance)
        {
            float dx = (float)(Math.Cos(angle) * distance);
            float dy = (float)(Math.Sin(angle) * distance);
            float oldx = mLocalPos.X;
            float oldy = mLocalPos.Y;
            int tick = 0;
            if (this.TouchMap)
            {
                mLocalPos.AddX(dx);
                if (Parent.TouchMap(this))
                {
                    mLocalPos.SetX(oldx);
                    tick++;
                }
                mLocalPos.AddY(dy);
                if (Parent.TouchMap(this))
                {
                    mLocalPos.SetY(oldy);
                    tick++;
                }
            }
            else
            {
                mLocalPos.AddX(dx);
                mLocalPos.AddY(dy);
            }
            if (tick >= 2)
            {
                return true;
            }
            if (Templates.CFG.OBJECT_NONE_TOUCH || !this.TouchObj)
            {
                ZoneUnit zu = Parent.TouchBuilding(this);
                if (this.TouchMap && zu != null)
                {
                    mLocalPos.SetY(oldy);
                    mLocalPos.SetX(oldx);
                    if (Parent.TouchObject2(this, zu))
                    {
                        PreElasticOtherObject(zu);
                    }
                    return true;
                }
            }
            else
            {
                ZoneUnit zu = Parent.TouchUnit(this);
                if (zu != null)
                {
                    mLocalPos.SetY(oldy);
                    mLocalPos.SetX(oldx);
                    if (Parent.TouchObject2(this, zu))
                    {
                        PreElasticOtherObject(zu);
                    }
                    return true;
                }
            }
            return false;
        }
        //-----------------------------------------------------------------------------------------------------------
        public virtual void PreSetPos(float x, float y)
        {
            mLocalPos.SetX(x);
            mLocalPos.SetY(y);
        }
        protected virtual void PreMove(float dx, float dy)
        {
            mLocalPos.AddX(dx);
            mLocalPos.AddY(dy);
        }
        internal protected void PreJumpTo(float direction, float speedSEC, int intervalMS)
        {
            float distance = MoveHelper.GetDistance(intervalMS, speedSEC);
            float dx = (float)(Math.Cos(direction) * distance);
            float dy = (float)(Math.Sin(direction) * distance);
            float oldx = mLocalPos.X;
            float oldy = mLocalPos.Y;
            if (this.TouchMap)
            {
                mLocalPos.AddX(dx);
                if (Parent.TouchMap(this))
                {
                    mLocalPos.SetX(oldx);
                }
                mLocalPos.AddY(dy);
                if (Parent.TouchMap(this))
                {
                    mLocalPos.SetY(oldy);
                }
                if (Parent.TouchBuilding(this) != null)
                {
                    mLocalPos.SetY(oldy);
                    mLocalPos.SetX(oldx);
                }
            }
            else
            {
                mLocalPos.AddX(dx);
                mLocalPos.AddY(dy);
            }
        }

        /// <summary>
        /// 获取当前最适合攻击的目标
        /// </summary>
        /// <param name="skill"></param>
        /// <param name="directionChange"></param>
        /// <returns></returns>
        public ZoneUnit PreGetSkillAttackableFirstTarget(SkillTemplate skill, ref bool directionChange)
        {
            using (var list = ListObjectPool<ZoneUnit>.AllocAutoRelease())
            {
                Parent.GetSkillAttackableUnits(this, skill, list);
                if (list.Count > 0)
                {
                    float rg = GetSkillAttackRange(skill);
                    // 检测攻击范围内的单位 //
                    float dr = skill.AttackAngle / 2;
                    foreach (ZoneUnit u in list)
                    {
                        if (CMath.intersectFanRound(this.X, this.Y, rg, u.X, u.Y, u.Info.BodyHitSize, this.Direction - dr, this.Direction + dr))
                        {
                            directionChange = false;
                            return u;
                        }
                    }
                    // 优先当前朝向的目标 //
                    dr = CMath.PI_DIV_2;
                    directionChange = true;
                    foreach (ZoneUnit u in list)
                    {
                        if (CMath.intersectFanRound(this.X, this.Y, rg, u.X, u.Y, u.Info.BodyHitSize, this.Direction - dr, this.Direction + dr))
                        {
                            return u;
                        }
                    }
                    // 最后选取最近的目标 //
                    ZoneUnit min = null;
                    float min_len = float.MaxValue;
                    foreach (ZoneUnit u in list)
                    {
                        float len = MathVector.getDistanceSquare(u.X, u.Y, X, Y);
                        if (min_len > len)
                        {
                            min_len = len;
                            min = u;
                        }
                    }
                    return min;
                }
            }
            return null;
        }

        public PreSkillStartMove PreSkillMove(
                float direction,
                float rotateSpeedSEC,
                int expectlTimeMS,
                float moveSpeedSEC,
                float moveSpeedAdd,
                float moveSpeedAcc,
                float moveZSpeed,
                float zgravity,
                float zlimit,
                bool isNoneTouch)
        {
            if (mSkillMove != null)
            {
                mSkillMove.Stop();
            }
            PreSkillStartMove move = new PreSkillStartMove(this, direction, rotateSpeedSEC, expectlTimeMS, moveSpeedSEC, moveSpeedAdd, moveSpeedAcc, moveZSpeed, zgravity, zlimit, isNoneTouch);
            mSkillMove = move;
            return move;
        }

        /// <summary>
        /// 被别的单位挤开
        /// </summary>
        /// <returns></returns>
        public bool PreElasticOtherObjects()
        {
            if (this.TouchObj)
            {
                bool force_sync = false;
                Parent.ForEachNearObjects(X, Y, (ZoneObject o, ref bool cancel) =>
                {
                    ZoneUnit u = o as ZoneUnit;
                    if ((u != null) && (o != this) && (o.TouchObj) && Parent.TouchObject2(this, o))
                    {
                        PreElasticOtherObject(u);
                        force_sync = true;
                    }
                });
                return force_sync;
            }
            return false;
        }

        /// <summary>
        /// 被别的单位挤开
        /// </summary>
        /// <param name="o"></param>
        public void PreElasticOtherObject(ZoneUnit o)
        {
            float targetAngle = MathVector.getDegree(this.X, this.Y, o.X, o.Y);
            float ddr = MathVector.getDistance(this.X, this.Y, o.X, o.Y);
            float bdr = (this.BodySize + o.BodySize);
            float distance = -(bdr - ddr);
            float dx = (float)(Math.Cos(targetAngle) * distance);
            float dy = (float)(Math.Sin(targetAngle) * distance);
            float oldx = mLocalPos.X;
            float oldy = mLocalPos.Y;
            if (this.TouchMap)
            {
                mLocalPos.AddX(dx);
                if (Parent.TouchMap(this))
                {
                    mLocalPos.SetX(oldx);
                }
                mLocalPos.AddY(dy);
                if (Parent.TouchMap(this))
                {
                    mLocalPos.SetY(oldy);
                }
            }
            else
            {
                mLocalPos.AddX(dx);
                mLocalPos.AddY(dy);
            }
        }


        /// <summary>
        /// 和所有单位(包括地图)做碰撞检测,是否阻挡
        /// </summary>
        /// <param name="src"></param>
        /// <param name="addX"></param>
        /// <param name="addY"></param>
        /// <returns>阻挡</returns>
        public bool PreBlockMove(ref float addX, ref float addY)
        {
            if (this.TouchMap)
            {
                if (Parent.TryTouchMap(this, this.X + addX, this.Y))
                {
                    addX = 0;
                }
                if (Parent.TryTouchMap(this, this.X, this.Y + addY))
                {
                    addY = 0;
                }
                if (Parent.TryTouchMap(this, this.X + addX, this.Y + addY))
                {
                    addX = 0;
                    addY = 0;
                }
                if (addX == 0 && addY == 0) { return true; }
            }
            /** 暂时屏蔽 地图上只有地图阻挡 
            float x = this.X + addX;
            float y = this.Y + addY;
            float r = this.Info.BodySize;
            if (this.TouchObj)
            {
                ZoneUnit u = Parent.TryTouchUnit(this, x, y);
                if (u != null)
                {
                    addX = 0;
                    addY = 0;
                    if (Parent.TouchObject2(u, this))
                    {
                        Vector2 bpos = new Vector2(u.X, u.Y);
                        MathVector.movePolar(bpos, MathVector.getDegree(u.X - this.X, u.Y - this.Y), this.Info.BodySize + u.Info.BodySize);
                        addX = bpos.x - this.X;
                        addY = bpos.x - this.X;
                    }
                    return true;
                }
            }
            else if (this.TouchMap)
            {
                ZoneUnit u = Parent.TryTouchBuilding(this, x, y);
                if (u != null)
                {
                    addX = 0;
                    addY = 0;
                    if (Parent.TouchObject2(u, this))
                    {
                        Vector2 bpos = new Vector2(u.X, u.Y);
                        MathVector.movePolar(bpos, MathVector.getDegree(u.X - this.X, u.Y - this.Y), this.Info.BodySize + u.Info.BodySize);
                        addX = bpos.x - this.X;
                        addY = bpos.x - this.X;
                    }
                    return true;
                }
            }
            **/
            return false;
        }
        /*
        public class ForceMoveAgent
        {
            private readonly ZoneActor actor;
            private AstarManhattan.MWayPoint path;

            public bool IsEnd { get { return path != null; } }

            private ForceMoveAgent(ZoneActor actor, float x, float y)
            {
                this.actor = actor;
            }

            public bool Start(float toX, float toY)
            {
                AstarManhattan.FindPathResult ret = actor.Parent.FindPathResult(actor.X, actor.Y, toX, toY, out path);
                if (ret == AstarManhattan.FindPathResult.Destination)
                {

                }
                else if (ret == AstarManhattan.FindPathResult.Cross)
                {

                }
                else
                {
                    return false;
                }
                return true;
            }

            public void Stop()
            {

            }

            internal void Update(int deltatime)
            {

            }

            internal void Dispose()
            {
                if (path != null)
                {
                    path.Dispose();
                }
            }
        }*/
        #endregion

        //--------------------------------------------------------------------------------------------------------
        #region __SkillActionStatus__

        /// <summary>
        /// 是否客户端位移模式
        /// </summary>
        public bool IsClientControlMove
        {
            get
            {
                if (IsGuard || IsFollow) return false;
                if (Parent.ActorSyncMode != SyncMode.MoveByClient_PreSkillByClient) return false;
                return true;
            }
        }
        private ISkillAction mCurrentSkillAction;
        public override ISkillAction CurrentSkillAction
        {
            get { return mCurrentSkillAction; }
        }
        public IActorSkillAction CurrentActorSkillAction
        {
            get { return mCurrentSkillAction as IActorSkillAction; }
        }
        public SkillState CurrentSkillState
        {
            get
            {
                if (mCurrentSkillAction is IActorSkillAction)
                {
                    return (mCurrentSkillAction as IActorSkillAction).State;
                }
                return null;
            }
        }


        protected override void doLaunchSkillAction(UnitLaunchSkillEvent me)
        {
            clearSkillAction();
            SkillState state = GetSkillState(me.skill_id);
            if (state != null)
            {
                if (IsClientControlMove)
                {
                    PreSkillByClient action = new PreSkillByClient(this, state);
                    action.onLaunch(me);
                    this.mCurrentSkillAction = action;
                }
                else
                {
                    PreSkillByServer action = new PreSkillByServer(this, state);
                    action.onLaunch(me);
                    this.mCurrentSkillAction = action;
                }
                invokeSkillActionStart(mCurrentSkillAction);
            }
        }
        private void updateServerSkillAction(int intervalMS)
        {
            if (mCurrentSkillAction != null)
            {
                if (mCurrentSkillAction is PreSkillByClient)
                {
                    if (mCurrentSkillAction.IsDone)
                    {
                        clearSkillAction();
                    }
                }
                else
                {
                    mCurrentSkillAction.onUpdate(intervalMS);
                    if (mCurrentSkillAction.IsDone)
                    {
                        clearSkillAction();
                    }
                }
            }
        }
        private void clearSkillAction()
        {
            if (mCurrentSkillAction != null)
            {
                if (mCurrentSkillAction.IsJumpAction)
                {
                    base.DoJumpToTargetEnd();
                    mCurrentSkillAction.RestJumpAction(false);
                }

                mCurrentSkillAction.onStop();
                mCurrentSkillAction = null;
                mIsSkillMove = false;
            }
        }

        private void doPlayerSkillStopEvent(PlayerSkillStopEvent evt)
        {
            clearSkillAction();
        }
        private void doUnitSkillActionChangeEvent(UnitSkillActionChangeEvent evt)
        {
            if (mCurrentSkillAction != null)
            {
                mCurrentSkillAction.onUnitSkillActionChangeEvent(evt);
            }
        }

        //-------------------------------------------------------------------------------------------------------

        public interface IActorSkillAction
        {
            SkillState State { get; }
        }

        public class PreSkillByServer : UnitSkillAction, IActorSkillAction
        {
            readonly private ZoneActor ownerUnit;
            readonly private SkillState state;

            public PreSkillByServer(ZoneActor actor, SkillState state)
                : base(actor, state.Data)
            {
                this.state = state;
                this.ownerUnit = actor;
            }
            public SkillState State { get { return state; } }
        }

        public class PreSkillByClient : ISkillAction, IActorSkillAction
        {
            readonly private ZoneActor ownerUnit;
            readonly private SkillTemplate skill;
            readonly private SkillState state;

            //--------------------------------------------------------

            public ZoneLayer Parent { get { return ownerUnit.Parent; } }
            public Vector2 StopFaceTo { get; private set; }
            public SkillState State { get { return state; } }
            public override bool IsJumpAction {
                get { return is_jump_action; }
            }

            public override bool IsDone { get { return is_done; } }
            public override byte ActionStepIndex { get { return (launch_event != null) ? launch_event.action_index : (byte)0; } }
            public override int[] ActionTimeArray { get { return action_time_array; } }
            public override int TotalTimeMS { get { return total_time_ms; } }
            public override int CurrentActionIndex { get { return current_action_index; } }
            public override string CurrentActionName { get { if (current_action != null) return current_action.ActionName; return null; } }
            public override UnitActionData CurrentAction { get { return current_action; } }
            public override float ExpirePercent { get { return total_pass_time / (float)TotalTimeMS; } }
            public override SkillTemplate SkillData { get { return skill; } }
            public override UnitLaunchSkillEvent LaunchEvent { get { return launch_event; } }
            public override int CurPassTimeMS { get { return current_pass_time; } }
            public override float ActionSpeed
            {
                get
                {
                    if (launch_event != null)
                    {
                        if (launch_event.action_speed_add != null && launch_event.action_index < launch_event.action_speed_add.Length)
                        {
                            return launch_event.action_speed + launch_event.action_speed_add[launch_event.action_index];
                        }
                        return launch_event.action_speed;
                    }
                    return action_speed;
                }
            }

            //--------------------------------------------------------
            private UnitLaunchSkillEvent launch_event;

            private int total_pass_time = 0;
            private int total_time_ms = 0;
            private float action_speed = 1f;
            private int current_action_index = 0;
            private int current_pass_time = 0;
            private int current_action_total_time = 0;
            private bool is_done = false;
            private ZoneUnit targetUnit;
            private Vector2 targetPos;
            private bool is_jump_action = false;

            private Queue<UnitActionData> action_queue;
            private UnitActionData current_action = null;
            private PopupKeyFrames<UnitActionData.KeyFrame> current_frames = new PopupKeyFrames<UnitActionData.KeyFrame>();
            private PreSkillStartMove action_move_time;
            private int[] action_time_array;

            private Vector2 move_to;
            //--------------------------------------------------------

            public PreSkillByClient(ZoneActor actor, SkillState state)
            {
                this.state = state;
                this.skill = state.Data;
                this.ownerUnit = actor;
            }

            internal override void onLaunch(UnitLaunchSkillEvent e)
            {
                this.launch_event = e;

                this.current_pass_time = 0;
                this.action_speed = e.action_speed;
                this.targetUnit = Parent.GetUnit(e.target_object_id);
                this.RestJumpAction(false);
                //TODO 屏蔽了下面这段代码 不知道哪个人才写的
                //this.targetUnit = null;

                if (e.IsSpellTargetPos)
                {
                    this.targetPos = new Vector2(e.spell_target_pos.X, e.spell_target_pos.Y);
                    this.ownerUnit.PreFaceTo(e.spell_target_pos.X, e.spell_target_pos.Y);
                }

                if (skill.IsSingleAction)
                {
                    var sa = skill.ActionQueue[e.action_index];
                    this.action_queue = new Queue<UnitActionData>(1);
                    this.action_queue.Enqueue(sa);
                    this.current_action_index = e.action_index;
                }
                else
                {
                    this.action_queue = new Queue<UnitActionData>(skill.ActionQueue);
                    this.current_action_index = 0;
                }
                if (e.action_time_array != null && e.action_time_array.Length > 0)
                {
                    this.total_time_ms = e.TotalActionTimeMS;
                    this.action_time_array = e.action_time_array;
                }
                else if (skill.IsSingleAction)
                {
                    this.total_time_ms = skill.ActionQueue[launch_event.action_index].TotalTimeMS;
                    this.action_time_array = new int[] { TotalTimeMS };
                }
                else
                {
                    this.total_time_ms = skill.ActionQueueTimeMS;
                    this.action_time_array = skill.ActionQueueTimeArray;
                }
                nextAction(current_action_index);

            }
            internal override void onUnitSkillActionChangeEvent(UnitSkillActionChangeEvent e)
            {
                while (this.CurrentActionIndex < e.ActionIndex)
                {
                    if (!nextAction(current_action_index + 1))
                    {
                        is_done = true;
                        total_pass_time = TotalTimeMS;
                        break;
                    }
                }
            }

            internal override void RestJumpAction(bool isJumpAction)
            {
                is_jump_action = isJumpAction;
            }

            internal override void onStop()
            {
                if (action_move_time != null)
                {
                    action_move_time.Stop();
                    action_move_time = null;
                }

                is_done = true;
                total_pass_time = TotalTimeMS;
                if (StopFaceTo != null)
                {
                    ownerUnit.PreFaceTo(StopFaceTo.X, StopFaceTo.Y);
                }

                //预演未做完,服务器下发结束的通知
                if (current_action != null && current_action.IsJumpToTarget)
                {
                    doJumpToTarget();
                }
            }
            internal override void onUpdate(int intervalMS)
            {
                int pass_time = (int)(intervalMS * ActionSpeed);
                this.total_pass_time += pass_time;
                this.total_pass_time = Math.Min(total_pass_time, TotalTimeMS);
                this.current_pass_time += pass_time;

                if (current_action == null)
                {
                    nextAction(current_action_index + 1);
                }
                if (current_action == null)
                {
                    is_done = true;
                    total_pass_time = TotalTimeMS;
                }
                else
                {
                    // 关键帧 //
                    using (var kfs = ListObjectPool<UnitActionData.KeyFrame>.AllocAutoRelease())
                    {
                        if (current_frames.PopKeyFrames(current_pass_time, kfs) > 0)
                        {
                            for (int i = 0; i < kfs.Count; i++)
                            {
                                doKeyFrame(kfs[i]);
                            }
                        }
                    }

                    //跳跃动作
                    if (current_action.IsJumpToTarget)
                    {
                        doJumpToTarget();
                    }
                    // 移动到目标时,不切换动作 //
                    if (current_action.IsMoveToTarget)
                    {
                        // 冲到目标,立即下段 //
                        doMoveToTarget();
                    }
                    else
                    {
                        // 技能位移 //
                        if (action_move_time != null)
                        {
                            doMove(intervalMS);
                        }
                        if (move_to != null)
                        {
                            if (IsControlMoveable)
                            {
                                ownerUnit.PreMoveTo(move_to.X, move_to.Y, ownerUnit.MoveSpeedSEC, intervalMS);
                            }
                            else
                            {
                                move_to = null;
                            }
                        }
                        if (current_action.BodyBlockOnAttackRange)
                        {
                            doBodyBlock();
                        }
                        /*if (IsFaceToTarget)
                        {
                            float tx = 0;
                            float ty = 0;
                            if (getTargetPos(out tx, out ty))
                            {
                                ownerUnit.PreFaceTo(tx, ty);
                            }
                        }*/
                    }
                    // 下段动作 //
                    if ((current_action != null) && (current_pass_time >= current_action_total_time))
                    {
                        current_action = null;
                        if (action_queue.Count == 0)
                        {
                            is_done = true;
                            total_pass_time = TotalTimeMS;
                        }
                    }
                }
            }
            private bool nextAction(int index)
            {
                if (action_move_time != null)
                {
                    action_move_time.Stop();
                    action_move_time = null;
                }

                if (action_queue.Count > 0)
                {
                    this.current_action_index = index;
                    //NewAction//
                    this.current_action = action_queue.Dequeue();
                    this.current_frames.AddRange(current_action.KeyFrames);
                    this.current_pass_time = 0;
                    //NewAction//
                    if (launch_event.action_time_array != null)
                    {
                        if (skill.IsSingleAction)
                        {
                            this.current_action_total_time = launch_event.TotalActionTimeMS;
                        }
                        else
                        {
                            this.current_action_total_time = launch_event.action_time_array[current_action_index];
                        }
                    }
                    else
                    {
                        this.current_action_total_time = current_action.TotalTimeMS;
                    }

                    this.IsCancelableBySkill = current_action.IsCancelableBySkill;
                    this.IsNoneBlock = current_action.IsNoneBlock;
                    this.IsNoneTouch = current_action.IsNoneTouch;
                    this.IsFaceToTarget = current_action.IsFaceToTarget;
                    this.IsCancelableByMove = current_action.IsCancelable;
                    this.IsControlMoveable = current_action.IsControlMoveable;
                    this.IsControlFaceable = current_action.IsControlFaceable;

                    if (current_action.IsMoveToTarget)
                    {
                        doMoveToTarget();
                    }
                    else if (current_action.IsJumpToTarget)
                    {
                        this.RestJumpAction(true);
                        doJumpToTarget();
                    }
                    else
                    {
                        this.RestJumpAction(false);
                    }

                    /*服务器已经接管这个了
                     * if (this.IsFaceToTarget || launch_event.IsAutoFocusNearTarget)
                    {
                        if (targetUnit != null && targetUnit != ownerUnit)
                        {
                            ownerUnit.PreFaceTo(
                                targetUnit.X,
                                targetUnit.Y);
                        }
                    }*/
                    return true;
                }
                current_action = null;
                return false;
            }

            private void doKeyFrame(UnitActionData.KeyFrame kf)
            {
                // 关键帧改变状态
                if (kf.ChangeStatus != null)
                {
                    this.IsNoneBlock = kf.ChangeStatus.IsNoneBlock;
                    this.IsNoneTouch = kf.ChangeStatus.IsNoneTouch;
                    this.IsFaceToTarget = kf.ChangeStatus.IsFaceToTarget;
                    this.IsCancelableByMove = kf.ChangeStatus.IsCancelable;
                    this.IsCancelableBySkill = kf.ChangeStatus.IsCancelableBySkill;
                    this.IsControlMoveable = kf.ChangeStatus.IsControlMoveable;
                    this.IsControlFaceable = kf.ChangeStatus.IsControlFaceable;
                }
                // 如果关键帧绑定单位位移
                if (kf.Move != null && (targetUnit == null || kf.hitTargetMoveEnable))
                {
                    StartMove action_move = kf.Move;
                    this.action_move_time = ownerUnit.PreSkillMove(
                        ownerUnit.Direction + action_move.Direction,
                        action_move.RotateSpeedSEC,
                        action_move.KeepTimeMS,
                        action_move.SpeedSEC,
                        action_move.SpeedAdd,
                        action_move.SpeedAcc,
                        action_move.ZSpeedSEC,
                        action_move.OverrideGravity,
                        action_move.ZLimit,
                        action_move.IsNoneTouch);
                }
            }

            private void doMove(int intervalMS)
            {
                action_move_time.IsNoneTouch = this.IsNoneTouch;
                if (action_move_time.IsEnd)
                {
                    action_move_time = null;
                }
            }

            public void setFaceTo(Vector2 face_to)
            {
                if (IsControlFaceable)
                {
                    ownerUnit.PreFaceTo(face_to.X, face_to.Y);
                }
                this.StopFaceTo = face_to;
            }

            public void setMoveTo(UnitAxisAction axis, int _tm = 0)
            {
                if (axis == null || axis.IsZero)
                {
                    this.move_to = null;
                    return;
                }
                if (this.IsCancelableByMove)
                {
                    is_done = true;
                    total_pass_time = TotalTimeMS;
                }

                float degree = MathVector.getDegree(axis.dx, axis.dy);
                Vector2 pos = new Vector2(ownerUnit.X, ownerUnit.Y);
                MathVector.movePolar(pos, degree, MoveHelper.GetDistance((_tm == 0) ? this.TotalTimeMS : _tm, ownerUnit.MoveSpeedSEC));

                if (IsControlMoveable)
                {
                    move_to = pos;
                }
                if (IsControlFaceable)
                {
                    ownerUnit.PreFaceTo(pos.X, pos.Y);
                }
                this.StopFaceTo = new Vector2(pos.X, pos.Y);

            }

            /// <summary>
            /// 防止技能位移导致单位重合
            /// </summary>
            private void doBodyBlock()
            {
                ownerUnit.PreElasticOtherObjects();
            }

            /// <summary>
            /// 移动到目标面前
            /// </summary>
            private bool doMoveToTarget()
            {
                //Force Sync from server//
                return false;
            }
            private bool doJumpToTarget()
            {
                if (is_done)
                {
                    ownerUnit.Z = 0;
                }
                else
                {
                    ownerUnit.Z = MoveHelper.CalulateParabolicHeight(current_action.JumpToTargetHeightZ, current_action.TotalTimeMS, this.current_pass_time);
                }
                return false;
            }

            public bool getTargetPos(out float x, out float y)
            {
                if (targetPos != null)
                {
                    x = targetPos.X;
                    y = targetPos.Y;
                    return true;
                }
                else if (targetUnit != null && targetUnit != ownerUnit)
                {
                    x = targetUnit.X;
                    y = targetUnit.Y;
                    return true;
                }
                x = ownerUnit.X;
                y = ownerUnit.Y;
                return false;
            }
        }

        public class PreSkillStartMove
        {
            private readonly ZoneClient.ZoneActor owner;
            private readonly float startDirection;

            private readonly float moveSpeedAdd;
            private readonly float moveSpeedAcc;
            private readonly float RotateSpeedSEC;

            private float moveSpeedSEC;
            private FallingDown hasFly;
            private TimeExpire<int> hitMoveTime;
            private bool isNoneTouch;

            public PreSkillStartMove(
                ZoneClient.ZoneActor owner,
                float direction,
                float rotateSpeedSEC,
                int expectlTimeMS,
                float moveSpeedSEC,
                float moveSpeedAdd,
                float moveSpeedAcc,
                float moveZSpeed,
                float zgravity,
                float zlimit,
                bool isNoneTouch)
            {
                this.RotateSpeedSEC = rotateSpeedSEC;

                this.moveSpeedSEC = moveSpeedSEC;
                this.moveSpeedAdd = moveSpeedAdd;
                this.moveSpeedAcc = moveSpeedAcc / 100f;

                this.owner = owner;
                this.startDirection = direction;

                this.isNoneTouch = isNoneTouch;

                if (moveZSpeed != 0)
                {
                    this.hasFly = owner.StartFly(moveZSpeed, zgravity, zlimit);
                    this.TotalTimeMS = hasFly.ExpectTimeMS;
                }
                else
                {
                    this.TotalTimeMS = expectlTimeMS;
                }
                this.hitMoveTime = new TimeExpire<int>(TotalTimeMS);
                this.IsEnd = false;
            }
            public void Stop()
            {
                this.IsEnd = true;
            }

            public bool Update(int intervalMS)
            {
                if (RotateSpeedSEC != 0)
                {
                    float add = MoveHelper.GetDistance(intervalMS, RotateSpeedSEC);
                    owner.PreTurnTo(add);
                }
                // 落下 //
                if (hasFly != null)
                {
                    owner.PreJumpTo(startDirection, moveSpeedSEC, intervalMS);
                }
                else
                {
                    if (IsNoneTouch)
                    {
                        owner.PreJumpTo(startDirection, moveSpeedSEC, intervalMS);
                    }
                    else
                    {
                        owner.PreMoveTo(startDirection, moveSpeedSEC, intervalMS);
                    }
                }
                // 后退 //
                {
                    MoveHelper.UpdateSpeed(intervalMS, ref moveSpeedSEC, moveSpeedAdd, moveSpeedAcc);
                }
                if (hitMoveTime.Update(intervalMS))
                {
                    IsEnd = true;
                }
                return IsEnd;
            }

            public bool IsEnd { get; private set; }
            public int TotalTimeMS { get; private set; }
            public bool IsNoneTouch { get { return isNoneTouch; } set { isNoneTouch = value; } }
        }

        #endregion

        //--------------------------------------------------------------------------------------------------------

        /*private void DoPlayerFocuseTargetEvent(PlayerFocuseTargetEvent e)
        {
            if (this.TargetUnitID != e.targetUnitID)
            {
                this.mFocusTarget = e;
                var target = Parent.GetObject(e.targetUnitID);
                if (mOnGuardFocusTarget != null)
                {
                    mOnGuardFocusTarget.Invoke(this, target, e.expectTarget);
                }
            }
            this.mFocusTarget = e;
        }

        private OnGuardFocusTargetHandler mOnGuardFocusTarget;

        /// <summary>
        /// 自动战斗锁定目标
        /// </summary>
        /// <param name="actor"></param>
        /// <param name="target"></param>
        /// <param name="expect"></param>
        public delegate void OnGuardFocusTargetHandler(ZoneActor actor, ZoneObject target, SkillTemplate.CastTarget expect);

        [EventTriggerDescAttribute("单位持有技能发生变化时触发")]
        public event OnGuardFocusTargetHandler OnGuardFocusTarget { add { mOnGuardFocusTarget += value; } remove { mOnGuardFocusTarget -= value; } }*/



        /*
        public class MoveAgent
        {
            public delegate void EndAction(ZoneActor actor);
            
            private readonly ZoneActor actor;

            private List<Vector2> path;
            private EndAction endAction;

            internal MoveAgent(ZoneActor actor)
            {
                this.actor = actor;
            }

            public void Stop()
            {
                path = null;
            }
            public bool Start(float toX, float toY, EndAction endAction)
            {
                AstarManhattan.MWayPoint wayPoints;
                AstarManhattan.FindPathResult ret = actor.Parent.FindPathResult(actor.X, actor.Y, toX, toY, out wayPoints);
                if (ret == AstarManhattan.FindPathResult.Destination)
                {
                    path.Clear();
                    path.Add(new Vector2(toX, toY));
                }
                else if (ret == AstarManhattan.FindPathResult.Cross)
                {
                    path.Clear();
                    path.Add(new Vector2(actor.X, actor.Y));
                    do
                    {
                        path.Add(new Vector2(wayPoints.PosX, wayPoints.PosY));
                        wayPoints = wayPoints.Next;
                    }
                    while (wayPoints != null);
                }
                else
                {
                    return false;
                }
                this.endAction = endAction;
                return true;
            }

            private void OnStop()
            {
                if (endAction != null) { endAction.Invoke(actor); }
                endAction = null;
            }

            internal void update(int deltatime)
            {
                if (path != null)
                {
                    var pos = path[0];
                    float length = actor.MoveSpeedSEC * deltatime / 1000f;
                    if (length > 0 && path.Count > 1)
                    {
                        float l = MathVector.getDistance(path[1], path[0]);
                        if (l <= length)
                        {
                            path.RemoveAt(0);
                        }
                        else
                        {
                            MathVector.moveTo(path[0], path[1].x, path[1].y, length);
                        }
                    }

                    //pos = path[0] - pos;
                    //pos = path[0];
                    //updateAction(path[0].x, path[0].y, userdata);
                    
                    if (path.Count < 2)
                    {
                        OnStop();
                    }
                }
            }
            
        }
        */
        //--------------------------------------------------------------------------------------------------------
    }
}