using CommonAI.RTS;
using CommonAI.Zone;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Instance;
using CommonAI.Zone.ZoneEditor;
using CommonAI.ZoneClient;
using CommonLang;
using CommonLang.ByteOrder;
using CommonLang.IO;
using CommonLang.IO.Attribute;
using CommonLang.Log;
using CommonLang.Property;
using CommonLang.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommonAI.ZoneServer;
using System.Threading;
using CommonLang.Concurrent;
using System.Diagnostics;
using CommonAIServer.Node.Interface;
using CommonLang.Vector;
using CommonAI.Zone.Interface;

namespace CommonAIServer.Node
{
    public class ZoneNode : BaseZoneNode
    {
        //------------------------------------------------------------------------------------------------------------
        /// <summary> 
        /// 存储玩家UUID和场景内单位的对应关系,如果玩家掉线重连,优先从此表内获取单位信息。
        /// </summary>
        private PlayerClientMap mPlayerObjectMap = new PlayerClientMap();
        private bool mEnableAOI = true;

		//最后一次场景掉落物时间
		private long mCheckDropEndTime;

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

        public ZoneNode(EditorTemplates data_root, ZoneNodeConfig cfg)
            : base(data_root, cfg)
        {

        }

        public int PlayerCount
        {
            get { return mPlayerObjectMap.Count; }
        }
        public bool EnableAOI
        {
            get { return mEnableAOI; }
            set
            {
                lock (this)
                {
                    if (mEnableAOI != value)
                    {
                        mEnableAOI = value;
                        OnAoiChanged(value);
                    }
                }
            }
        }

        /// <summary>
        /// 根据UUID获取单位
        /// </summary>
        /// <param name="uuid"></param>
        /// <returns></returns>
        public InstancePlayer GetPlayer(string uuid)
        {
            return mPlayerObjectMap.GetPlayer(uuid);
        }
        public PlayerClient GetPlayerClient(string uuid)
        {
            return mPlayerObjectMap.GetClient(uuid);
        }
        public bool GetPlayerAndClient(string uuid, out InstancePlayer player, out PlayerClient client)
        {
            return mPlayerObjectMap.Get(uuid, out player, out client);
        }
        /// <summary>
        /// 遍历所有客户端
        /// </summary>
        /// <param name="action"></param>
        public void ForEachPlayers(Action<PlayerClient> action)
        {
            mPlayerObjectMap.ForEachPlayers(action);
        }

        /// <summary>
        /// 单位进入场景
        /// </summary>
        /// <param name="player"></param>
        /// <param name="temp"></param>
        /// <param name="force"></param>
        /// <param name="level"></param>
        /// <param name="enterPos"></param>
        /// <param name="direction"></param>
        /// <param name="callback"></param>
        /// <param name="callerror"></param>
        public void PlayerEnter(IPlayer player, UnitInfo temp, int force, int alliesForce, int level, Vector2 enterPos, 
            float direction,Action<PlayerClient> callback, Action<Exception> callerror)
        {
            // 客户端连接到战斗服 //
            QueueTask(() =>
            {
                try
                {
                    if (mPlayerObjectMap.ContainsKey(player.PlayerUUID))
                    {
						if(player.BindingPlayer == null)
						{
							log.Warn(this.Name + " Player reconnect : " + player.PlayerUUID);
						}
						else
						{
							log.Warn(this.Name + " Player already exist : " + player.BindingPlayer.Actor.Name +"," +player.PlayerUUID);
						}                      
                    }
                    // 场景内已有玩家 //
                    InstancePlayer actor = Zone.getPlayerByUUID(player.PlayerUUID);
                    if (actor == null)
                    {
                        // 有出生点则放入出生点 //
                        if (enterPos == null)
                        {
                            enterPos = new Vector2();
                            ZoneRegion start = base.Zone.GetEditStartRegion(force);
                            if (start != null)
                            {
                                CMath.RandomPosInRound(Zone.RandomN, start.X, start.Y, start.Radius, ref enterPos);
                            }
                            else
                            {
                                // 没有出身点,随机一个出生点 //
                                using (var kvs = ListObjectPool<  KeyValuePair < int, ZoneRegion>>.AllocAutoRelease())
                                {
                                    base.Zone.GetEditStartRegions(kvs);
                                    if (kvs.Count > 0)
                                    {
                                        start = CUtils.GetRandomInArray(kvs, Zone.RandomN).Value;
                                        if (start != null)
                                        {
                                            CMath.RandomPosInRound(Zone.RandomN, start.X, start.Y, start.Radius, ref enterPos);
                                        }
                                    }
                                }
                            }
                        }
                        AddUnitEvent add;
						try
						{
							actor = base.Zone.AddUnit(
							  temp,
							  player.PlayerUUID,
							  force,
							  level,
							  enterPos.X,
							  enterPos.Y,
							  direction,
							  out add, null, "", 0, alliesForce) as InstancePlayer;

							if (actor != null)
							{
								// 初始化 InstanceUnit 各个字段 //
								actor.Alias = player.DisplayName;
								add.Sync.Name = player.DisplayName;
								add.Sync.Level = level;
							}
						}
						catch(Exception e)
						{
							log.Error("AddUnit catch:" + (player == null ? "player null" : player.PlayerUUID)  + ", " + 
								(enterPos == null ? "pos null" : " pos ok") + ", " + e);
						}
                    }
                    else
                    {
                        actor.OnReconnected(temp, force, level, enterPos);
                    }
                    if (actor != null)
                    {
                        // 绑定客户端ID和游戏角色 //
                        //zc.Actor.ClientID = zc.ID;
                        //绑定关系//
                        PlayerClient zc = CreatePlayerClient(player, actor);

                        // 准备发送当前场景信息 //
                        mPlayerObjectMap.PutPlayer(zc);
                        zc.Send(new ClientEnterScene(SceneData.ID, Zone.SpaceDivSize, Templates.ResourceVersion), true);
                        zc.Send(actor.GenLockActorEvent(player.DisplayName, zc.SyncObjectRange, zc.SyncObjectOutRange, base.UpdateInterval), true);
                        zc.Send(actor.GetSyncSkillActives(), true);
                        zc.Send(Zone.GetSyncFlagsEvent(), true);
                        zc.Start();
                        if (!mEnableAOI)
                        {
                            zc.Send(zc.GetSyncObjectsEvent(), true);
                        }
                        OnPlayerEntered(zc);
                        callback(zc);
                    }
                    else
                    {
                        callerror(new Exception("Can not add player : " + temp));
                    }
                }
                catch (Exception err)
                {
                    log.Error(err.Message, err);
                    OnError(err);
                    callerror(err);
                }
            });
        }

        /// <summary>
        /// 单位离开场景
        /// </summary>
        /// <param name="player"></param>
        /// <param name="callback"></param>
        /// <param name="callerror"></param>
        /// <param name="keep_object">保留单位</param>
        public void PlayerLeave(InstancePlayer player, Action<PlayerClient> callback, Action<Exception> callerror, bool keep_object = false)
        {
            if (player == null) return;
            QueueTask(() =>
            {
                try
                {
                    InstancePlayer out_player;
                    PlayerClient out_client;
                    if (mPlayerObjectMap.RemoveByKey(player.PlayerUUID, out out_player, out out_client))
                    {
                        try
                        {
                            if (!keep_object)
                            {
                                player.removeFromParent();
                            }
                            else
                            {
                                player.OnDisconnected();
                            }
                            // 通知客户端清理BattleClient //
                            out_client.Send(new PlayerLeaveScene(out_player.ID), true);
                            OnPlayerLeft(out_client);
                        }
                        finally
                        {
                            out_client.Dispose();
                        }
                        callback(out_client);
                    }
                    else
                    {
                        callerror(new Exception("leave Player not exist : " + player.PlayerUUID + "from " + this.Name));
                    }
                }
                catch (Exception err)
                {
                    log.Error(err.Message, err);
                    OnError(err);
                    callerror(err);
                }
            });
        }

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

        #region _Virtual_And_Override_

        public override void ZoneUpdate(int intervalMS)
        {
            Zone.SyncPos = !mEnableAOI;
            base.ZoneUpdate(intervalMS);
        }

        protected override void OnZoneUpdate(bool slowRefresh)
        {
            //客户端更新//
            mPlayerObjectMap.ForEachPlayers((PlayerClient c) =>
            {
                c.BeginUpdate(slowRefresh);
            });
            //向客户端推送实时场景信息//
            mPlayerObjectMap.ForEachPlayers((PlayerClient zc) =>
            {
                foreach (IMessage msg in PostZoneEvents)
                {
                    zc.Send(msg);
                }
            });
            //客户端更新//
            mPlayerObjectMap.ForEachPlayers((PlayerClient c) =>
            {
                c.EndUpdate(slowRefresh);
            });
        }

        protected virtual void OnAoiChanged(bool enable)
        {
            if (!enable)
            {
                ForEachPlayers((zc) =>
                {
                    zc.Send(zc.GetSyncObjectsEvent(), true);
                });
            }
        }

        protected virtual void OnPlayerEntered(PlayerClient client) { }
        protected virtual void OnPlayerLeft(PlayerClient client) { }


		protected void RecordDropItem()
		{
			////场景掉落物最大存活时间,用来降低检测频率
			this.mCheckDropEndTime = CommonLang.CUtils.localTimeMS + 300000;
		}

		public override bool CheckDropItem()
		{
			return this.mCheckDropEndTime > CommonLang.CUtils.localTimeMS;
		}

		/// <summary>
		/// 过滤消息,过滤掉非知晓消息
		/// </summary>
		/// <param name="client"></param>
		/// <param name="msg"></param>
		/// <returns></returns>
		protected virtual IMessage FilterSendingMessage(PlayerClient client, CommonLang.Protocol.IMessage msg)
        {
            if (!mEnableAOI)
            {
                return msg;
            }
            InstancePlayer mActor = client.Actor;
            if (msg is AddUnitEvent)
            {
                return null;
            }
            else if (msg is AddItemEvent)
            {
                return null;
            }
            else if (msg is AddSpellEvent)
            {
                return null;
            }
            else if (msg is RemoveObjectEvent)
            {
                return null;
            }
            // 过滤不是发给自己的聊天指令 //
            else if (msg is ChatEvent)
            {
                ChatEvent chat = msg as ChatEvent;
                switch (chat.To)
                {
                    case ChatMessageType.SystemToForce:
                    case ChatMessageType.PlayerToForce:
                        if (chat.Force != mActor.Force)
                        {
                            return null;
                        }
                        break;
                    case ChatMessageType.SystemToPlayer:
                    case ChatMessageType.PlayerToPlayer:
                        if (!string.Equals(chat.ToPlayerUUID, client.PlayerUUID))
                        {
                            return null;
                        }
                        break;
                }
            }
            else if (msg is UnitHitEvent)
            {
                //过滤不是自己有关的伤害//
                UnitHitEvent he = msg as UnitHitEvent;
				//if (he.senderId != mActor.ID && he.object_id != mActor.ID)
				//{
				//	ISummonedUnit summon = Zone.getUnit(he.senderId) as ISummonedUnit;
				//	if (summon == null || summon.SummonerUnit != mActor)
				//	{
				//		summon = Zone.getUnit(he.object_id) as ISummonedUnit;
				//		if (summon == null || summon.SummonerUnit != mActor)
				//		{
				//			return null;
				//		}
				//	}
				//}
				if (he.senderId != mActor.ID && he.object_id != mActor.ID && he.senderMasterId != mActor.ID && he.hitMasterId != mActor.ID)
				{
					if(he.InViewForceSend && he.sender != null && client.IsInView(he.sender as InstanceZoneObject))
					{
						return msg;
					}

					return null;
				}
			}
			else if(msg is PlayerSingleMsg)
			{
				ObjectEvent talnetInfo = msg as ObjectEvent;
				if(talnetInfo.ObjectID != mActor.ID)
				{
					return null;
				}
			}
            else if (msg is PlayerEvent)
            {
                // 过滤不是本人的玩家事件 //
                PlayerEvent pe = msg as PlayerEvent;
                if (pe.object_id != mActor.ID)
                {
                    return null;
                }
            }
            else if (msg is ActorMessage)
            {
                // 过滤不是本人的玩家事件 //
                ActorMessage pe = msg as ActorMessage;
                if (pe.ObjectID != mActor.ID)
                {
                    return null;
                }
            }
            else if (msg is ObjectEvent)
            {
                // 过滤不在自己感兴趣范围内的消息 //
                ObjectEvent om = msg as ObjectEvent;
                if (om.ObjectID != mActor.ID && om.sender is InstanceZoneObject)
                {
                    InstanceZoneObject obj = om.sender as InstanceZoneObject;
                    if (!client.IsInView(obj))
                    {
                        return null;
                    }
                }
            }
            else if (msg is ClientEvent)
            {
                // 过滤不是发给本人的ClientEvent事件 //
                ClientEvent cm = msg as ClientEvent;
                if (cm.sender != null && cm.sender != mActor)
                {
                    return null;
                }
            }
            else if (msg is PositionMessage)
            {
                // 过滤不在自己感兴趣范围内的消息 //
                PositionMessage pm = msg as PositionMessage;
                if (!client.IsLookInRange(pm.X, pm.Y))
                {
                    return null;
                }
            }
            return msg;
        }

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

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

        #region __客户端__

        protected virtual PlayerClient CreatePlayerClient(IPlayer client, InstancePlayer actor)
        {
            return new PlayerClient(client, actor, this, Config.CLIENT_SYNC_OBJECT_IN_RANGE, Config.CLIENT_SYNC_OBJECT_OUT_RANGE);
        }

        public class PlayerClient : PlayerClientObject
		{
            private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
            private static AtomicInteger s_active_object_count = new AtomicInteger(0);
            /// <summary>
            /// 未释放实例数量
            /// </summary>
            public static int ActiveCount { get { return s_active_object_count.Value; } }
            /// <summary>
            /// 分配实例数量
            /// </summary>
            public static int AllocCount { get { return s_alloc_object_count.Value; } }


            private readonly IPlayer mClient;
            private readonly ZoneNode mNode;
            private readonly EditorScene mZone;
            private readonly InstancePlayer mActor;

            private readonly float mSyncObjectInRange;
            private readonly float mSyncObjectOutRange;

            private bool mDisposed = false;

            private long mPreUpdateTime = 0;

            // 视野范围内的单位 //
            private readonly HashMap<uint, InstanceZoneObject> mInViewList = new HashMap<uint, InstanceZoneObject>();
            protected List<uint> m_RemovingList = new List<uint>();
            private Pong mSendPong = new Pong();

            public float SyncObjectRange { get { return mSyncObjectInRange; } }
            public float SyncObjectOutRange { get { return mSyncObjectOutRange; } }
            public ZoneNode Node { get { return mNode; } }
            public EditorScene Zone { get { return mZone; } }
            public InstancePlayer Actor { get { return mActor; } }
            public IPlayer Client { get { return mClient; } }
            public string PlayerUUID { get { return mClient.PlayerUUID; } }

            public long UpdateTime { get { return mPreUpdateTime; } set{mPreUpdateTime = value;}
            }

            public PlayerClient(IPlayer client, InstancePlayer actor, ZoneNode node, float look_in_range, float look_out_range)
            {
                s_alloc_object_count++;
                s_active_object_count++;
                this.mActor = actor;
                this.mClient = client;
                this.mNode = node;
                this.mZone = node.Zone;
                this.mSyncObjectInRange = Math.Min(look_in_range, look_out_range);
                this.mSyncObjectOutRange = Math.Max(look_in_range, look_out_range);
                if ((int)(mSyncObjectOutRange / mZone.SpaceDivSize) <= (int)(mSyncObjectInRange / mZone.SpaceDivSize))
                {
                    mSyncObjectOutRange = mSyncObjectInRange + mZone.SpaceDivSize;
                }
                this.mInViewList.Add(mActor.ID, mActor);
                this.mClient.Listen(RecvInternal);
                this.mClient.BindingPlayer = this;
                this.mClient.OnConnected(this);
            }
            ~PlayerClient()
            {
                s_alloc_object_count--;
            }
            internal void Dispose()
            {
                if (mDisposed) { return; }
                this.Disposing();
                this.mClient.OnDisconnect(this);
                this.mClient.BindingPlayer = null;
                this.mDisposed = true;
                s_active_object_count--;
            }

            protected virtual void Disposing() { }

            protected virtual void OnStart() { }

            protected virtual void OnBeginUpdate() { }
            protected virtual void OnEndUpdate() { }


            internal void Start()
            {
                OnStart();
                BeginUpdate(true);
            }

            /// <summary>
            /// 定时更新Client
            /// </summary>
            internal void BeginUpdate(bool slowRefresh)
            {
                OnBeginUpdate();
                if (mNode.mEnableAOI && slowRefresh)
                {
                    LookInRange();
                }
            }
            internal void EndUpdate(bool slowRefresh)
            {
                if (mNode.mEnableAOI)
                {
					LookOutRange(slowRefresh);  
					                  
                    // 一直同步周围单位
                    SyncPosEvent mSyncPosLocal = GetSyncPosEvent();
                    if (mSyncPosLocal != null && !mSyncPosLocal.IsEmpty)
                    {
                        mClient.Send(mSyncPosLocal);
                    }
                }
                OnEndUpdate();
            }
            /// <summary>
            /// 排队发送消息
            /// </summary>
            /// <param name="msg"></param>
            /// <param name="immediately"></param>
            public void Send(IMessage msg, bool immediately = false)
            {
                if (mNode.mEnableAOI)
                {
                    if (immediately)
                    {
                        this.mClient.Send(msg);
                    }
                    else if (msg is AddSpellEvent)
                    {
                        OnLookSpell(msg as AddSpellEvent);
                    }
                    else
                    {
                        msg = mNode.FilterSendingMessage(this, msg);
                        if (msg != null)
                        {
                            this.mClient.Send(msg);
                        }
                    }
                }
                else
                {
                    this.mClient.Send(msg);
                }
            }

            /// <summary>
            /// 从客户端接收消息
            /// </summary>
            /// <param name="message"></param>
            private void RecvInternal(object message)
            {
                if (message is Ping)
                {
                    var ping = message as Ping;
                    mSendPong.ClientTimeDayOfMS = ping.DayOfMS;
                    mClient.Send(mSendPong);
                    return;
                }
                else
                {
                    //mNode.QueueTask(() =>
                    //{
                        if (mActor.Enable)
                        {
                            ObjectAction oa = message as ObjectAction;
                            if (oa != null)
                            {
                                BaseZoneNode.log.Debug("C2B msg<<<" + oa);
                                oa.object_id = mActor.ID;
                                oa.sender = mActor;
                                if (oa is ActorRequest)
                                {
                                    mActor.doRequest(oa as ActorRequest);
                                }
                                else
                                {
                                    mZone.pushAction(oa);
                                }
                            }
                        }
                    //});
                }
            }

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

            //------------------------------------------------------------------------------------------------------------
            #region _AOI_视野控制_

            /// <summary>
            /// 获取当前场景内所有单位,用于同步现有场景中单位 
            /// </summary>
            /// <returns></returns>
            public SyncObjectsEvent GetSyncObjectsEvent()
            {
                if (mNode.mEnableAOI)
                {
                    return mZone.GetSyncObjectsEvent(mInViewList.Values);
                }
                else
                {
                    return mZone.GetSyncUnitsEvent(mActor);
                }
            }
            public bool IsInView(InstanceZoneObject obj)
            {
                if (mNode.mEnableAOI)
                    return mInViewList.ContainsKey(obj.ID);
                else
                    return true;
            }
            public bool IsLookInRange(float x, float y)
            {
                if (mNode.mEnableAOI)
                    return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, x, y);
                else
                    return true;
            }
            public SyncPosEvent GetSyncPosEvent()
            {
                return mZone.GetSyncPosEvent(mInViewList.Values, this.Actor, this);
            }

            /// <summary>
            /// 判断单位是否进入视野
            /// </summary>
            /// <param name="obj"></param>
            /// <returns>True,进入视野</returns>
            protected virtual bool IsLookInRange(InstanceZoneObject obj)
            {
				return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, obj.X, obj.Y);
            }
            /// <summary>
            /// 判断单位是否超出视野
            /// </summary>
            /// <param name="obj"></param>
            /// <returns>True,超出视野</returns>
            protected virtual bool IsLookOutRange(InstanceZoneObject obj)
            {
				return !CMath.includeRoundPoint(mActor.GetX(), mActor.GetY(), mSyncObjectOutRange, obj.GetX(), obj.GetY());
            }


            protected void ForceAddObjectInView(InstanceZoneObject obj)
            {
                if (!mInViewList.ContainsKey(obj.ID))
                {
                    mInViewList.Put(obj.ID, obj);
                    OnEnterView(obj);
                }
            }
            private void LookInRange()
            {
                mZone.ForEachNearObjects<InstanceZoneObject>(mActor.X, mActor.Y, mSyncObjectInRange, mZone_CheckInRange);
            }
            private void mZone_CheckInRange(InstanceZoneObject o, ref bool cancel)
            {
                if ((o != mActor) && o.ClientVisible && !(o is InstanceSpell) && !mInViewList.ContainsKey(o.ID))
                {
                    if (o.Enable && mZone.IsVisibleAOI(mActor, o) && IsLookInRange(o))
                    {
                        mInViewList.Put(o.ID, o);
                        OnEnterView(o);
                    }
                }
            }
            private void LookOutRange(bool slowRefresh)
            {
                foreach (InstanceZoneObject o in mInViewList.Values)
                {
					if (o == mActor)
					{
						continue;
					}

					if (!o.Enable || (slowRefresh && (!mZone.IsVisibleAOI(mActor, o) || IsLookOutRange(o))))
                    {
						m_RemovingList.Add(o.ID);
						OnLeaveView(o);
                    }
                }
                if (m_RemovingList.Count > 0)
                {
                    foreach (uint oid in m_RemovingList)
                    {
                        mInViewList.Remove(oid);
                    }
                    m_RemovingList.Clear();
                }
            }

			public virtual bool RemoveInRange(InstanceZoneObject o) { return false; }



			protected virtual void OnLookSpell(AddSpellEvent em)
            {
                // 过滤不在自己感兴趣范围内的消息
                if (em.sender is InstanceSpell)
                {
                    var sp = em.sender as InstanceSpell;
                    //作用于自己或者自己发射的//
                    if (sp.Launcher == mActor || sp.Target == mActor)
                    {
                        mInViewList.Put(sp.ID, sp);
                        mClient.Send(em);
                        return;
                    }
                    if (mZone.IsVisibleAOI(mActor, sp))
                    {
                        if (IsLookInRange(em.x, em.y))
                        {
                            mInViewList.Put(sp.ID, sp);
                            mClient.Send(em);
                            return;
                        }
                    }
                }
            }
            protected virtual void OnEnterView(InstanceZoneObject obj)
            {
                if (obj is InstanceUnit)
                {
                    InstanceUnit u = obj as InstanceUnit;
                    var sync = u.GenSyncUnitInfo(true);
                    var add = new AddUnitEvent(sync);
                    mClient.Send(add);

					if(u.Info.SpawnEffect != null && u.CurrentActionStatus == UnitActionStatus.Spawn)
					{
						u.Parent.queueEvent(new AddEffectEvent(u.ID, u.X, u.Y, u.Direction, u.Info.SpawnEffect));
					}
                }
                else if (obj is InstanceItem)
                {
                    InstanceItem i = obj as InstanceItem;
                    var sync = i.GenSyncItemInfo(true, this.PlayerUUID);
                    var add = new AddItemEvent(sync);
                    mClient.Send(add);
                }
            }
            protected virtual void OnLeaveView(InstanceZoneObject obj)
            {
                RemoveObjectEvent remove = new RemoveObjectEvent(obj.ID);
                mClient.Send(remove);
            }

            public void ForEachInViewList(Action<InstanceZoneObject> action)
            {
                using (var list = ListObjectPool<InstanceZoneObject>.AllocAutoRelease(mInViewList.Values))
                {
                    foreach (var obj in list) { action(obj); }
                }
            }

            #endregion
            //------------------------------------------------------------------------------------------------------------
            //             private OnObjectEnterViewHandler event_OnObjectEnterView;
            //             private OnObjectLeaveViewHandler event_OnObjectLeaveView;
            //             public delegate void OnObjectEnterViewHandler(PlayerClient sender, InstanceZoneObject obj);
            //             public delegate void OnObjectLeaveViewHandler(PlayerClient sender, InstanceZoneObject obj);
            //             public event OnObjectEnterViewHandler OnObjectEnterView { add { event_OnObjectEnterView += value; } remove { event_OnObjectEnterView -= value; } }
            //             public event OnObjectLeaveViewHandler OnObjectLeaveView { add { event_OnObjectLeaveView += value; } remove { event_OnObjectLeaveView -= value; } }
        }

        private class PlayerClientMap
        {
            private HashMap<string, InstancePlayer> mPlayerObjectMap = new HashMap<string, InstancePlayer>();
            private HashMap<string, PlayerClient> mPlayerClientMap = new HashMap<string, PlayerClient>();
            public int Count
            {
                get
                {
                    lock (this)
                    {
                        return mPlayerClientMap.Count;
                    }
                }
            }
            public InstancePlayer[] Players
            {
                get
                {
                    lock (this)
                    {
                        return mPlayerObjectMap.Values.ToArray();
                    }
                }
            }
            public void PutPlayer(PlayerClient client)
            {
                lock (this)
                {
                    mPlayerObjectMap.Put(client.PlayerUUID, client.Actor);
                    mPlayerClientMap.Put(client.PlayerUUID, client);
                }
            }
            public InstancePlayer GetPlayer(string uuid)
            {
                lock (this)
                {
                    return mPlayerObjectMap.Get(uuid);
                }
            }
            public PlayerClient GetClient(string uuid)
            {
                lock (this)
                {
                    return mPlayerClientMap.Get(uuid);
                }
            }
            public bool Get(string uuid, out InstancePlayer player, out PlayerClient client)
            {
                lock (this)
                {
                    player = mPlayerObjectMap.Get(uuid);
                    client = mPlayerClientMap.Get(uuid);
                }
                return client != null;
            }
            public bool RemoveByKey(string uuid, out InstancePlayer player, out PlayerClient client)
            {
                lock (this)
                {
                    player = mPlayerObjectMap.RemoveByKey(uuid);
                    client = mPlayerClientMap.RemoveByKey(uuid);
                }
                return client != null;
            }
            public bool ContainsKey(string uuid)
            {
                lock (this)
                {
                    return mPlayerObjectMap.ContainsKey(uuid);
                }
            }
            public void ForEachPlayers(Action<PlayerClient> action)
            {
                lock (this)
                {
                    foreach (PlayerClient c in mPlayerClientMap.Values)
                    {
                        action(c);
                    }
                }
            }
        }

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

        #endregion


    }
}