using CommonAI.Zone;
using CommonAI.Zone.Instance;
using CommonAI.ZoneServer;
using CommonLang;
using CommonLang.ByteOrder;
using CommonLang.Concurrent;
using CommonLang.IO;
using CommonLang.IO.Attribute;
using CommonLang.Property;
using CommonLang.Protocol;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using XmdsCommon.Message;
using XmdsCommon.Plugin;
using XmdsCommonServer.Message;
using XmdsCommonServer.Plugin;
using XmdsServerNode.Node.Interface;
using CommonAIServer.Node;
using CommonAI.ZoneClient;
using XmdsCommonServer.Plugin.Units;
using XmdsCommonServer.Plugin.Scene;
using CommonAI.Zone.ZoneEditor;
using System.Dynamic;
using XmdsServerNode.CheatingDeath;
using Pomelo;
using System.Web.Helpers;
using static CommonAI.XmdsConstConfig;
using CommonAI.Zone.Helper;
using CommonAI.Data;

namespace XmdsServerNode.Node
{
    public class ServerZoneNode : CommonAIServer.Node.ZoneNode
    {
        private GameOverEvent mGameOver = null;
        public bool PauseOnNoPlayer { get; set; }
        public string UUID { get { return Zone.UUID; } }
        public bool IsGameOver { get { return mGameOver != null; } }

        public ICEZoneSession Callback;
        private readonly string BindGameServerId;


		public ServerZoneNode(string gameServerId) : base(ZoneNodeManager.Templates, ZoneNodeManager.NodeConfig)
        {
            this.BindGameServerId = gameServerId;
            PauseOnNoPlayer = false;
        }

		public string GetBindGameSrvId()
		{
			return this.BindGameServerId;
		}

		/// <summary>
		/// 房间初始化
		/// </summary>
		public void Start(string instanceID, int scene_id, string monsterHard, byte allowAutoGuard, bool calPKValue, 
			int average_level, double monsterAddPropPercentWithFloor, double monsterAddPropRatioWithLv, int killInterval,
			int killMax, int killMaxCoolTime, bool usespaceDiv, CommonAI.Data.SceneType scenetype, GSCreateAreaData areaData, 
			CommonAI.XmdsConstConfig.AreaType areaType, bool isteam = false, bool canRiding = true)
        {
            try
            {
				var sd = base.DataRoot.LoadScene_Server(scene_id, true, false);
                sd.DefaultUnitLevel = average_level;
                sd.MonsterAddPropPercentWithFloor = monsterAddPropPercentWithFloor;
                sd.MonsterAddPropRatioWithLv = monsterAddPropRatioWithLv;
                sd.canRiding = canRiding;
				sd.killInterval = killInterval;
                sd.killMax = killMax;
                sd.killMaxCoolTime = killMaxCoolTime;
                sd.isTeam = isteam;
                sd.sceneType = scenetype;

				XmdsSceneProperties zsp = sd.Properties as XmdsSceneProperties;
                XmdsServerSceneData sceneData = new XmdsServerSceneData();
                sceneData.AllowAutoGuard = allowAutoGuard;
                sceneData.CalPKValue = calPKValue;
                sceneData.SceneHard = monsterHard;
                sceneData.UsespaceDiv = usespaceDiv;
                sceneData.CurAreaType = areaType;
                zsp.ServerSceneData = sceneData;				

				base.Start(sd, areaData, this.BindGameServerId);
                base.Zone.UUID = instanceID;
			}
            catch (System.Exception e)
            {
                throw new Exception(string.Format("scene {0} start error : {1}", scene_id, e.ToString()), e);
            }
        }

        public void QueueTaskAsync(System.Action<EditorScene> action)
        {
            base.QueueTask(() =>
            {
                action(base.Zone);
            });
        }
        public void QueueTaskAsync(System.Action action)
        {
            base.QueueTask(() =>
            {
                action();
            });
        }

        public void SendToGameServer(string name, Object param)
        {
            if (Callback == null)
            {
                this.Callback = IceManager.instance().getCallback(this.BindGameServerId);
                log.Warn("SendToGameServer callback - 1 - null : " + this.BindGameServerId + ", name:" + name + ", data:" + param);
            }
            string json = null;
            if (Callback != null && Callback.callback != null)
            {
				try
                {
					json = Json.Encode(param);
                    Callback.callback.eventNotify(name, json);
                }
				catch (Exception err)
				{
                    if(json == null)
                    {
                        log.Error("SendToGameServer序列化就异常了,放弃记录:" + name + ", err:" + err.Message, err);
                    }
                    else
                    {
                        Callback.notifyFailData.Enqueue(new ICENotifyData(name, json));
                        log.Error("SendToGameServer: " + name + ", err:" + err.Message, err);
                        EventNotifyFail();                        
                    }
				}
			}
            else
            {
                log.Warn("SendToGameServer callback - 2- null : " + this.BindGameServerId + ", name:" + name + ", data:" + param);
            }
        }

		private void EventNotifyFail()
		{
			try
			{
				if (Callback.callback.ice_getCachedConnection() == null)
				{
					Callback.failTimes++;
					if (Callback.fastSession != null/* && Callback.failTimes >= 3*/)
					{
						Callback.fastSession.doClose();
						Callback.failTimes = 0;
						log.Warn("EventNotifyFail 重置连接: " + Callback.fastSession.GetDescribe());
					}
					else
					{
						log.Error("EventNotifyFail fastSession null:" + Callback.callback.ToString());
					}
				}
			}
			catch (System.Exception e)
			{
				log.Error("EventNotifyFail catch:" + e);
			}
		}


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

		#region _主线程内回调_线程安全_

		public override bool ZoneUpdate(int intervalMS)
        {
            if (PauseOnNoPlayer && base.PlayerCount == 0) { intervalMS = 0; }
            return base.ZoneUpdate(intervalMS);
        }

        //过滤游戏场景推送出的消息//
        protected override bool OnMessageHandlerFromInstanceZone(Event e)
        {
            //战斗服To游戏服.
            if (e is MessagePlayerEventB2R)
            {
                e.sender = null;
                var msg = e as MessagePlayerEventB2R;
                msg.eventName = e.GetType().Name;
                SendToGameServer("playerEvent", e);
                return true;
            }
            else if (e is MessageZoneEventB2R)
            {
                e.sender = null;
                var msg = e as MessageZoneEventB2R;
                msg.eventName = e.GetType().Name;
                SendToGameServer("zoneEvent", e);
                return true;
            }
			else if(e is MessageMapEventB2R)
			{
				var msg = e as MessageMapEventB2R;
				msg.eventName = e.GetType().Name;
				SendToGameServer("mapNotify", e);
				return true;
			}
            else if (e is GameOverEvent)
            {
                if (mGameOver == null)
                {
                    mGameOver = e as GameOverEvent;
                    var eventParam = new
                    {
                        eventName = "gameOver",
                        instanceId = this.UUID,
                        winForce = mGameOver.WinForce
                    };
                    SendToGameServer("areaEvent", eventParam);
                }
            }
            return false;
        }


        protected override void OnEndUpdate()
        {
            base.ForEachPlayers((c) =>
            {
                var zone_client = c.Client as ZoneNodePlayer;
                zone_client.Flush();
            });
        }

        protected override void OnPlayerEntered(PlayerClient client)
        {
            base.OnPlayerEntered(client);
            CheatingDeath.CheatingDeathManager.OnPlayerEnter(client.Actor);

            //进去默认自动战斗的情况下
            if(this.SceneData.Properties.GetAutoFightFlag() == 3 && !client.Actor.IsGuard)
            {
                client.Actor.doEnterAutoFight();
            }

            client.Actor.Virtual.doEvent(JSGCustomOpType.UpdateAutoBattleFlag);
        }
        protected override void OnPlayerLeft(PlayerClient client)
        {
            base.OnPlayerLeft(client);
            this.KillPlayerAOIObjects(client);
        }

        //干掉所有和玩家同一位面单位//
        protected void KillPlayerAOIObjects(PlayerClient client)
        {
            var player = client.Actor;
            if (player != null && player.AoiStatus != null)
            {
                var src_aoi = player.AoiStatus as XmdsPlayerAOI;
                if (src_aoi.Owner == player)
                {
                    src_aoi.Cleanup();
                }
            }
        }

        #endregion

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

        #region _游戏服控制玩家_

        /// <summary>
        /// 单位进入场景
        /// </summary>
        /// <param name="player"></param>
        /// <param name="enter"></param>
        public void OnPlayerEnter(IPlayer player, PlayerEnterRoomS2R enter, Action<PlayerClient> callback, Action<Exception> callerror)
        {
            if (enter == null)
            {
                // 建立绑定关系 //
                var zone_player = new ZoneNodePlayer(this, player);
                base.PlayerEnter(zone_player, null, 0, 0, 0, null,0, callback, callerror);
            }
            else
            {
                // 有出生点则放入出生点 //
                CommonLang.Vector.Vector2 enterPos = enter.Pos;
                if (enterPos.X == 0 && enterPos.Y == 0)
                {
                    enterPos = null;
                }
                if (!string.IsNullOrEmpty(enter.FlagName))
                {
                    InstanceFlag p = Zone.getFlag(enter.FlagName);
					if(p != null)
					{
	                    if (p is ZoneRegion)
	                    {
	                        // Region随机取一个坐标
	                        var pos = (p as ZoneRegion).getRandomPos(Zone.RandomN);
	                        enterPos.SetX(pos.X);
	                        enterPos.SetY(pos.Y);
	                    }
	                    else
	                    {
	                        enterPos = p.Pos;
	                    }
					}
                }
                UnitInfo temp = ZoneNodeManager.Templates.Templates.getUnit(enter.UnitData.UnitTemplateID);
                if (temp != null)
                {
                    temp = temp.Clone() as UnitInfo;
                    temp.UType = UnitInfo.UnitType.TYPE_PLAYER;
                    XmdsUnitProperties tprop = (temp.Properties as XmdsUnitProperties);

                    //临时代码.
                    //默认无限等待.
                    temp.RebirthTimeMS = int.MaxValue;

                    // 插入玩家能力属性 //
                    tprop.ServerData = ((enter.UnitData.UnitPropData) as XmdsUnitProperties).ServerData;

                    // 建立绑定关系 //
                    var zone_player = new ZoneNodePlayer(this, player);
                    base.PlayerEnter(zone_player, temp, enter.UnitData.Force, enter.UnitData.alliesForce, 
                        tprop.ServerData.BaseInfo.UnitLv, enterPos,enter.direction, callback, callerror);
                }
                else
                {
                    throw new Exception("Unit template not exist : " + enter);
                }
            }
        }

        /// <summary>
        /// 单位离开场景
        /// </summary>
        /// <param name="player"></param>
        public void OnPlayerLeave(InstancePlayer player, Action<PlayerClient> callback, Action<Exception> callerror, bool keep_object = false)
        {
            if (player != null)
            {
                base.PlayerLeave(player, callback, callerror, keep_object);
            }
        }

        /// <summary>
        /// 玩家网络状况改变
        /// </summary>
        /// <param name="player"></param>
        /// <param name="state"></param>
        public void OnPlayerNetStateChanged(IPlayer player, string state)
        {
            QueueTask(() =>
            {
                var zc = player.BindingObject;
                if (zc != null)
                {
                    zc.NetStateChanged(state);
                }
            });
        }

        /// <summary>
        /// 单位收到来自客户端的消息
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        public void OnPlayerReceivedMessage(IPlayer player, byte[] msg)
        {
            QueueTask(() =>
            {
                //if (doDecodePing(player, msg))
                //{
                //    return;
                //}
                //else
                {
                    var zone_player = player.BindingObject;
                    if (zone_player != null)
                    {
                        zone_player.Recv(msg);
                    }
                }
            });
        }

        public void ReceiveMsgR2B(IPlayer client, object status)
        {
            QueueTask(() =>
            {
                var zc = client.BindingObject;

                if (zc != null && zc.BindingActor != null)
                {
                    XmdsVirtual zv = (XmdsVirtual)zc.BindingActor.Virtual;
                    zv.ReceiveMsgR2B(status);
                }
            });
        }

        /// <summary>
        /// 玩家复活,分原地复活和复活点复活
        /// </summary>
        /// <param name="client"></param>
        /// <param name="status"></param>
        public void OnHelpPlayerRebirth(IPlayer player, IPlayer revivePlayer, int time)
        {
            QueueTask(() =>
            {
                var p = player.BindingObject;
                var r = revivePlayer.BindingObject;

                if (p != null && r != null && p.BindingActor != null && r.BindingActor != null)
                {
                    PlayerSaveEventR2B r2b = new PlayerSaveEventR2B();
                    XmdsVirtual Decedent = (XmdsVirtual)(r.BindingActor).Virtual;
                    XmdsVirtual Saver = (XmdsVirtual)(p.BindingActor).Virtual;
                    r2b.Decedent = Decedent.mUnit;
                    r2b.Saver = Saver.mUnit;
                    r2b.SaveTime = time;
                    Saver.ReceiveMsgR2B(r2b);
                }
            });

        }

        public void OnPlayerReadyR2B(IPlayer client)
        {
            QueueTask(() =>
            {
                InstancePlayer out_player;
                PlayerClient out_client;
                if (GetPlayerAndClient(client.PlayerUUID, out out_player, out out_client))
                {
                    if (out_player != null && out_client != null)
                    {
                        (out_player as XmdsInstancePlayer).PlayerReady();
                    }
                }
            });
        }

        public void OnPlayerReviveTeamInfoEventR2B(IPlayer client, TeamInfoEventR2B team)
        {
            QueueTask(() =>
            {
                InstancePlayer out_player;
                PlayerClient out_client;
                if (GetPlayerAndClient(client.PlayerUUID, out out_player, out out_client))
                {
                    if (out_player != null && out_client != null)
                    {
                        (out_client as BindingPlayerClient).OnPlayerReviveTeamInfoEventR2B(team);
                        var zv = (XmdsVirtual)out_player.Virtual;
                        zv.ReceiveMsgR2B(team);
                    }
                }
            });
        }

        public void OnPlayerAddHPByItem(List<IPlayer> notifyPlayers, IPlayer client, int addHP)
        {
            QueueTask(() =>
            {
                var nodePlayer = client.BindingObject as ZoneNodePlayer;

                if (nodePlayer != null)
                {
                    XmdsVirtual zv = (nodePlayer.BindingActor.Virtual) as XmdsVirtual;
                    int finalHp = zv.AddHPByItem(addHP);
                    ZoneNodePlayer temp = null;

                    foreach (IPlayer p in notifyPlayers)
                    {
                        temp = p.BindingObject as ZoneNodePlayer;
                        XmdsVirtual notifyPlayer = null;

                        if (temp != null)
                        {
                            notifyPlayer = (temp.BindingActor.Virtual) as XmdsVirtual;
                            notifyPlayer.SendHPChangeMessage(zv.mUnit.ID, finalHp);
                        }
                    }
                }
            });
        }

		public float GetDropRange(int items)
		{
			if(items >= 10)
			{
				return 5.0f;
			}
			if (items >= 7)
			{
				return 4.0f;
			}
			else if(items > 4)
			{
				return 3.6f;
			}
			return 2.8f;
		}

		public float GetDropOffect(float dropRange)
		{
			int index = (this.Zone.RandomN.Next() % 2 == 0) ? 1 : -1;
			return dropRange * this.Zone.RandomN.Next(0, 100) / 100f * index;
		}

        public void AddDropItem(float x, float y, dynamic items)
        {
            QueueTask(() =>
            {
				//阿基米德螺线<-装B用,实际不需要这样
				//20170621wuyonghui修改为随机掉落位置算法
				float dropRange = GetDropRange(((DynamicJsonArray)items).Length);// 掉落半径范围为5
				bool addSuc = false;
                foreach (dynamic obj in items)
                {
                    XmdsCommon.Message.DropItem di = new XmdsCommon.Message.DropItem();
                    di.FileName = (string)obj.showId;
                    di.FreezeTime = (int)obj.freezeTime;
                    di.Name = (string)obj.name;
                    di.ObjID = (string)obj.id;
                    di.ProtectTime = (int)obj.protectTime;
                    di.Qty = (int)obj.groupCount;
                    di.Quality = (int)obj.qColor;
                    di.TemplateID = (int)obj.itemTypeId;
                    di.TTL = (int)obj.lifeTime;
					di.PlayerUUID = new List<string>();
					di.Mode = (byte)obj.distributeType;
                    di.OriginX = x;
                    di.OriginY = y;
					bool showLifeTimes = (bool)obj.showLifeTime;
					di.code = (String)obj.code;
					di.bindPlayerId = obj.bindPlayerId;
					di.createTime = (int)(CommonLang.CUtils.S_LOCAL_TIMESTAMPMS/1000);

					if (obj.PlayerUUID != null)
					{
						foreach (dynamic playeruuid in obj.PlayerUUID)
						{
							di.PlayerUUID.Add(playeruuid);
						}
					}
				
                    di.IconName = (string)obj.IconName;

					ItemTemplate templateTemp = Zone.Templates.getItem(di.TemplateID);
					if(templateTemp == null)
					{
						log.Warn("AddDropItem没有对应单位信息:" + di.TemplateID + ", " + di.code);
						return;
					}

					ItemTemplate template = templateTemp.Clone() as ItemTemplate;
                    //每个物品类型可能有多个显示模型,所以按游戏服传过来的策划配置模型名称
                    template.FileName = di.FileName;
                    //修改模板的部分数据,由于模板是共享的,所以必须每次都把以下数据完整覆盖
                    template.LifeTimeMS = di.TTL;
                    template.GotCoolDownTimeMS = di.FreezeTime;
                    template.DropForAll = true;
                    template.GotOnUse = true;
					template.showLifeTime = showLifeTimes;
					//template.Pickable = false;//这里注释掉,直接用模板里的值,不要改变
					XmdsItemProperties props = template.Properties as XmdsItemProperties;
                    props.ItemType = XmdsItemProperties.XmdsItemType.Equip;

                    float x1 = this.GetDropOffect(dropRange);//获得X偏移量
                    float y1 = this.GetDropOffect(dropRange);//获得Y偏移量
                    if(Zone.TryTouchMap(null,x+x1,y+y1))
                    {
                        x1 = 0;
                        y1 = 0;
                    }

					//System.Console.WriteLine("掉落物:" + di.Name + ", 偏移:" + x1 + ", " + y1 + "----" + (x + x1) + ", " + (y + y1));
                    AddItemEvent aie;
                    XmdsDropableInstanceItem drop_item = Zone.AddItem(template, obj.name, x + x1, y + y1, 0, 0, obj.name, out aie, null,1);
					if(drop_item == null || aie == null)
					{
						log.Warn("添加bs掉落物失败:" + template.ID + ", " + template.Name + ", " + this.SceneID);
						return;
					}
                    aie.Sync.ExtData = di;
					if(drop_item != null)
					{
						addSuc = true;						
					}
				}

				if (addSuc)
				{
					base.RecordDropItem();
				}
            });
        }

        public void FinishPickItem(IPlayer player, string itemIcon, int quality, int num)
        {
            QueueTask(() =>
            {
                var p = player.BindingObject;
             
                if (p != null && p.BindingActor != null)
                {
                    PlayerGotItemB2C b2c = new PlayerGotItemB2C();
                    XmdsVirtual zv = (XmdsVirtual)(p.BindingActor).Virtual;
                    b2c.IconName = itemIcon;
                    b2c.Qty = num;
                    b2c.Quality = quality;
                    zv.mUnit.queueEvent(b2c);
                }
            });
        }


        #endregion

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

        #region _PingPong_

        //private static readonly int MSG_TYPE_ID_PING = PropertyUtil.GetAttribute<MessageTypeAttribute>(typeof(Ping)).MessageTypeID;
        //private static readonly int MSG_TYPE_ID_PONG = PropertyUtil.GetAttribute<MessageTypeAttribute>(typeof(Pong)).MessageTypeID;
        //private ArraySegment<byte> pong_data = new ArraySegment<byte>(new byte[8], 0, 8);

        //public bool doDecodePing(IPlayer player, byte[] data)
        //{
        //    int pos = 0;
        //    int msg_id = LittleEdian.GetS32(data, ref pos);
        //    if (msg_id == MSG_TYPE_ID_PING)
        //    {
        //        uint time = LittleEdian.GetU32(data, ref pos);
        //        pos = 0;
        //        LittleEdian.PutS32(pong_data.Array, ref pos, MSG_TYPE_ID_PONG);
        //        LittleEdian.PutU32(pong_data.Array, ref pos, time);
        //        player.SendToClient(pong_data);
        //        return true;
        //    }
        //    return false;
        //}

        #endregion

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

        protected override PlayerClient CreatePlayerClient(CommonAIServer.Node.Interface.IPlayer client, InstancePlayer actor)
        {
            var syncIn = base.Config.CLIENT_SYNC_OBJECT_IN_RANGE;
            var syncOut = base.Config.CLIENT_SYNC_OBJECT_OUT_RANGE;
            var zpp = base.SceneData.Properties as XmdsSceneProperties;
            if (zpp.AOIMinRange > 0 && zpp.AOIMaxRange > 0)
            {
                syncIn = zpp.AOIMinRange;
                syncOut = zpp.AOIMaxRange;
            }
            return new BindingPlayerClient(client, actor, this, syncIn, syncOut);
        }

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

        public class ZoneNodePlayer : CommonAIServer.Node.Interface.IPlayer
        {
            private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
            /// <summary>
            /// 分配实例数量
            /// </summary>
            public static int AllocCount { get { return s_alloc_object_count.Value; } }

            public readonly ZoneNode node;
            public readonly IPlayer player;

            private ZoneNodeCodec mCodec = new ZoneNodeCodec(ZoneNodeManager.MessageFactory);
            private AtomicReference<PlayerClient> binding_player = new AtomicReference<PlayerClient>(null);
            private Action<object> handler;
            private PackEvent mSendingQueue = new PackEvent();
            private AtomicInteger mSendingSequenceNo = new AtomicInteger(0);
            private string display_name = "";

            //private Queue<object> mPreQueue = new Queue<object>();

            internal ZoneNodePlayer(ZoneNode node, IPlayer player)
            {
                s_alloc_object_count++;
                this.node = node;
                this.player = player;
                this.player.BindingObject = this;
                this.Connected = true;
            }
            ~ZoneNodePlayer()
            {
                s_alloc_object_count--;
            }

            public IPlayer SessionPlayer {get { return player; }}

            public PlayerClient BindingPlayer
            {
                get { return binding_player.Value; }
                set
                {
                    binding_player.Value = value;
                    if (value != null)
                    {
                        try
                        {
                            display_name = (value.Actor.Properties as XmdsUnitProperties).ServerData.BaseInfo.name;
                        }
                        catch (Exception err)
                        {
                            display_name = err.Message;
                        }
                    }
                }
            }
            public InstancePlayer BindingActor
            {
                get
                {
                    var player = binding_player.Value;
                    if (player != null)
                    {
                        return player.Actor;
                    }
                    return null;
                }
            }

            public bool Connected { get; private set; }

            internal void NetStateChanged(string state)
            {
                BaseZoneNode.log.InfoFormat("Player:{0} NetStateChanged:{1}", player.PlayerUUID, state);
                switch (state)
                {
                    case "disconnected":
                        this.Connected = false;
                        break;
                    case "connected":
                        this.Connected = true;
                        break;
                    default:
                        return;
                }
            }

            internal void Recv(byte[] data)
            {
                IMessage message;
                if (mCodec.doDecode(data, out message))
                {
                    //if(handler == null)
                    //{
                    //    mPreQueue.Enqueue(message);
                    //}
                    //else
                    //{
                    //    handler.Invoke(message);
                    //}
                    if (handler != null)
                    {
                        handler.Invoke(message);
                    }

                }
                else
                {
                    CheatingDeathManager.SendPlayerException(BindingActor, "decode error");
                }
            }
            public void Send(IMessage msg)
            {
                if (msg is PlayerLeaveScene)
                {
                    this.Flush();
                    this.ForceSend(msg);
                }
                else if (this.Connected)
                {
                    lock (mSendingQueue)
                    {
                        mSendingQueue.events.Add(msg);
                    }
                }
            }
            internal void Flush()
            {
                lock (mSendingQueue)
                {
                    if (mSendingQueue.events.Count > 0)
                    {
                        try
                        {
                            if (this.Connected)
                            {
                                mSendingQueue.sequenceNo = mSendingSequenceNo.GetAndIncrement();
                                ForceSend(mSendingQueue);
                            }
                        }
                        finally
                        {
                            mSendingQueue.events.Clear();
                        }
                    }
                }
            }
            internal void ForceSend(IMessage msg)
            {
                //BaseZoneNode.log.Debug("B2C msg>>>" + msg);
                ArraySegment<byte> data;
                if (mCodec.doEncode(msg, out data))
                {
                    this.player.SendToClient(data);
                }
            }
            #region CommonAIServer.Node.Interface.IPlayer.

            void CommonAIServer.Node.Interface.IPlayer.OnConnected(PlayerClient bindingg)
            {
            }
            void CommonAIServer.Node.Interface.IPlayer.OnDisconnect(PlayerClient bindingg)
            {
                this.player.BindingObject = null;
                this.player.Dispose();
            }
            string CommonAIServer.Node.Interface.IPlayer.DisplayName
            {
                get { return display_name; }
            }
            string CommonAIServer.Node.Interface.IPlayer.PlayerUUID
            {
                get { return player.PlayerUUID; }
            }
            object CommonAIServer.Node.Interface.IPlayer.GetAttribute(string key)
            {
                return player.GetAttribute(key);
            }
            bool CommonAIServer.Node.Interface.IPlayer.IsAttribute(string key)
            {
                return player.IsAttribute(key);
            }
            void CommonAIServer.Node.Interface.IPlayer.SetAttribute(string key, object value)
            {
                player.SetAttribute(key, value);
            }
            void CommonAIServer.Node.Interface.IPlayer.Listen(Action<object> handler)
            {
                this.handler = handler;
                //while(mPreQueue.Count > 0)
                //{
                //    this.handler.Invoke(mPreQueue.Dequeue());
                //}
            }
            #endregion

        }


        public class BindingPlayerClient : PlayerClient
        {
            private readonly ZoneNodePlayer Xmds_client;
            private readonly HashSet<string> team_info = new HashSet<string>();
            private List<string> team_removing = new List<string>(1);

            internal BindingPlayerClient(CommonAIServer.Node.Interface.IPlayer client, InstancePlayer actor, CommonAIServer.Node.ZoneNode node, float syncIn, float syncOut)
                : base(client, actor, node, syncIn, syncOut)
            {
                this.Xmds_client = client as ZoneNodePlayer;
            }
            protected override void OnStart()
            {
                base.OnStart();
                foreach (var obj in base.Zone.AllUnits)
                {
                    if (IsStaticUnit(obj))
                    {
                        base.ForceAddObjectInView(obj);
                    }
                }
            }
            private bool IsStaticUnit(InstanceZoneObject obj)
            {
                if (obj is InstanceUnit)
                {
                    XmdsUnitProperties prop = (obj as InstanceUnit).Info.Properties as XmdsUnitProperties;
                    return prop.IsStaticUnit;
                }
                return false;
            }
            protected override bool IsLookInRange(InstanceZoneObject obj)
            {
                if (obj is InstancePlayer)
                {
                    //组队列表中的单位永远不出视野//
                    var player = obj as InstancePlayer;
                    if (team_info.Contains(player.PlayerUUID))
                    {
                        return true;
                    }

					//if((player.CurrentActionSubstate & (byte)UnitActionSubStatus.Stealth) > 0 
     //                   && (this.Actor.CurrentActionSubstate & (byte)UnitActionSubStatus.Stealth) <= 0)
					//{
					//	return false;
					//}
                }
                else if (IsStaticUnit(obj))
                {
                    return true;
                }
                return base.IsLookInRange(obj);
            }
            protected override bool IsLookOutRange(InstanceZoneObject obj)
            {
                if (obj is InstancePlayer)
                {
                    //组队列表中的单位永远不出视野//
                    var player = obj as InstancePlayer;
                    if (team_info.Contains(player.PlayerUUID))
                    {
                        return false;
                    }

     //               if ((player.CurrentActionSubstate & (byte)UnitActionSubStatus.Stealth) > 0
     //                   && (this.Actor.CurrentActionSubstate & (byte)UnitActionSubStatus.Stealth) <= 0
     //                   && !player.Virtual.IsAllies(this.Actor.Virtual))                  
					//{
					//	return true;
					//}
				}
                else if (IsStaticUnit(obj))
                {
                    return false;
                }
                return base.IsLookOutRange(obj);
            }

			public override bool RemoveInRange(InstanceZoneObject o)
			{
				if (IsLookOutRange(o))
				{
					m_RemovingList.Add(o.ID);
					OnLeaveView(o);

					return true;
				}

				return false;
			}

			internal void OnPlayerReviveTeamInfoEventR2B(TeamInfoEventR2B team)
            {
                if (team.UUIDList != null)
                {
                    //检测加入队伍//
                    foreach (var uuid in team.UUIDList)
                    {
                        if (!string.IsNullOrEmpty(uuid) && !team_info.Contains(uuid))
                        {
                            InstancePlayer tu = base.Zone.getPlayerByUUID(uuid);
                            if (tu != null)
                            {
                                team_info.Add(uuid);
                                base.ForceAddObjectInView(tu);
                            }
                        }
                    }
                    //检测离开队伍//
                    team_removing.Clear();
                    foreach (var uuid in team_info)
                    {
                        if (!team.UUIDList.Contains(uuid))
                        {
                            team_removing.Add(uuid);
                        }
                    }
                    if (team_removing.Count > 0)
                    {
                        foreach (var uuid in team_removing)
                        {
                            team_info.Remove(uuid);
                        }
                    }
                }
            }
        }

        //------------------------------------------------------------------------------------------------------------
    }

}