private void Send(ClientPack obj)
 {
     lock (sendLock)
     {
         if (server.Clients.Contains(this))
         {
             MessagePackSerializer.Serialize(_netStream, obj, PlayerdomGame.SerializerSettings);
         }
     }
 }
        public void InitializePlayer(Player p, ushort dimensionId)
        {
            FocusedObjectId = Guid.NewGuid();


            DimensionId = dimensionId;

            server.LoadDimension(DimensionId);
            server.Dimensions[DimensionId].Map.LoadedObjects.TryAdd(FocusedObjectId.Value, p);
            ClientPack pack = new ClientPack()
            {
                CurrentMessage = new ServerMessage()
                {
                    MessageType = "focusedObjectId", MessageContent = new string[1] {
                        FocusedObjectId.Value.ToString()
                    }
                }
            };

            Task.Delay(2000).Wait();
            externalPacks.Enqueue(pack);

            Task.Delay(2000).Wait();
            (float hue, float sat, float val) = server.Dimensions[DimensionId].Discolorization;
            pack = new ClientPack()
            {
                CurrentMessage = new ServerMessage()
                {
                    MessageType = "changeDimension", MessageContent = new string[4] {
                        DimensionId.ToString(), hue.ToString(), sat.ToString(), val.ToString()
                    }
                }
            };
            externalPacks.Enqueue(pack);


            SavePlayer();
        }
        public void ChangeDimensions(ushort dimensionId)
        {
            server.Dimensions[DimensionId].Map.LoadedObjects.TryRemove(FocusedObjectId.Value, out GameObject p);

            server.LoadDimension(dimensionId);
            server.Dimensions[dimensionId].Map.LoadedObjects.TryAdd(FocusedObjectId.Value, p);
            DimensionId = dimensionId;

            (float hue, float sat, float val) = server.Dimensions[DimensionId].Discolorization;
            ClientPack pack = new ClientPack()
            {
                CurrentMessage = new ServerMessage()
                {
                    MessageType = "changeDimension", MessageContent = new string[4] {
                        DimensionId.ToString(), hue.ToString(), sat.ToString(), val.ToString()
                    }
                }
            };

            externalPacks.Enqueue(pack);


            SavePlayer();
        }
        private void StartSendingMessages()
        {
            Task.Run(() =>
            {
                while (server.Clients.Contains(this))
                {
                    try
                    {
                        if (UserId.HasValue && FocusedObjectId.HasValue && server.Dimensions[DimensionId].Map.LoadedObjects.ContainsKey(FocusedObjectId.Value))
                        {
                            GameObject go = server.Dimensions[DimensionId].Map.LoadedObjects[FocusedObjectId.Value];

                            //Deep Clone to make thread-safe
                            //TODO: Make it more efficient
                            ConcurrentDictionary <Guid, GameObject> objClone;
                            ConcurrentDictionary <Guid, GameEntity> entClone;
                            lock (server.Dimensions[DimensionId].Map.LoadedObjects)
                                objClone = MessagePackSerializer.Deserialize <ConcurrentDictionary <Guid, GameObject> >(MessagePackSerializer.Serialize(server.Dimensions[DimensionId].Map.LoadedObjects));

                            lock (server.Dimensions[DimensionId].Map.LoadedEntities)
                                entClone = MessagePackSerializer.Deserialize <ConcurrentDictionary <Guid, GameEntity> >(MessagePackSerializer.Serialize(server.Dimensions[DimensionId].Map.LoadedEntities));


                            ConcurrentDictionary <Guid, GameObject> objCloneToSend = new ConcurrentDictionary <Guid, GameObject>();
                            ConcurrentDictionary <Guid, GameEntity> entCloneToSend = new ConcurrentDictionary <Guid, GameEntity>();


                            (long, long)goChunk = Map.PositionToChunkIndex(go.Coordinates);
                            foreach ((Guid id, GameObject o) in objClone)
                            {
                                (long, long)oChunk = Map.PositionToChunkIndex(o.Coordinates);

                                if (Math.Abs(oChunk.Item1 - goChunk.Item1) <= Map.CHUNK_RANGE && Math.Abs(oChunk.Item2 - goChunk.Item2) <= Map.CHUNK_RANGE)
                                {
                                    objCloneToSend.TryAdd(id, o);
                                }
                            }

                            foreach ((Guid id, GameEntity e) in entClone)
                            {
                                (long, long)eChunk = Map.PositionToChunkIndex(e.Coordinates);

                                if (Math.Abs(eChunk.Item1 - goChunk.Item1) <= Map.CHUNK_RANGE && Math.Abs(eChunk.Item2 - goChunk.Item2) <= Map.CHUNK_RANGE)
                                {
                                    entCloneToSend.TryAdd(id, e);
                                }
                            }

                            lock (go)
                            {
                                while (externalPacks.TryDequeue(out ClientPack result))
                                {
                                    Send(result);
                                }

                                if (objCloneToSend.ContainsKey(FocusedObjectId.Value))
                                {
                                    Queue <ChatMessage> messages = new Queue <ChatMessage>();
                                    while (MessageOutbox.TryDequeue(out ChatMessage m))
                                    {
                                        messages.Enqueue(m);
                                    }


                                    ClientPack pack = new ClientPack()
                                    {
                                        Chunks = server.Dimensions[DimensionId].Map.GetLocalChunks(objCloneToSend[FocusedObjectId.Value].Coordinates.Item1, objCloneToSend[FocusedObjectId.Value].Coordinates.Item2, DimensionId, Path.Combine(server.saveDirectoryPath, "Dimensions", DimensionId.ToString()), server.Dimensions[DimensionId].DefaultSeedString), GameObjects = objCloneToSend, GameEntities = entCloneToSend, NewChats = messages
                                    };
                                    Send(pack);
                                }
                                else
                                {
                                    //throw new Exception("Player object removed");
                                    //Player object now CAN be removed when the player is shifting Dimensions. Just don't send them anything this round
                                }
                            }
                        }
                        else
                        {
                            while (externalPacks.TryDequeue(out ClientPack result))
                            {
                                Send(result);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        if (e.GetType() == typeof(Exception))
                        {
                            server.logger(EndPointString + " disconnected: " + e.Message);
                        }
                        server.RemoveClient(this);
                    }
                    Task.Delay(5).Wait();
                }
            });
        }