Exemple #1
0
        /// <summary>
        /// Zamyka Lobby i wysyła informację do graczy o zamknięciu
        /// </summary>
        public void Close()
        {
            // Wysyłanie sygnału o zamknięciu Lobby
            var communicate = new StandardCommunicateSerializer();
            var serializer  = new LobbySignalsSerializer();

            serializer.Signal           = LobbySignalsSerializer.SIGNAL_CLOSED;
            serializer.Message          = "Lobby has been closed";
            communicate.CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL;
            communicate.Data            = serializer.GetApiObject();
            Broadcast(communicate.GetApiObject());

            foreach (var client in ConnectedClients)
            {
                try {
                    MainConfig.SERVER_SOCKET.DisconnectClient(client);
                } catch (ArgumentException) {
                    Console.WriteLine("Client " + client.ToString() + " not connected, cannot disconnect.");
                }
            }

            Closed?.Invoke(this, null);

            Console.WriteLine("Lobby zamknięte: " + this.ToString());

            Dispose();
        }
        protected override BaseSerializer PerformAction(ClientConnection conn, BaseSerializer requestData)
        {
            RequestSerializer  data = (RequestSerializer)requestData;
            ResponseSerializer resp = (ResponseSerializer)InitializeResponseSerializer();

            resp.Status = "OK";

            Lobby  lobby    = (Lobby)conn.Session.Get("joined-lobby");
            string username = (string)conn.Session.Get("username");

            var signal = new ChatMessageSerializer()
            {
                Signal   = ChatMessageSerializer.SIGNAL_CHAT_MESSAGE,
                Username = username,
                Message  = username + ": " + data.Message
            };

            Console.WriteLine("New message > {0}", username + ": " + data.Message);

            var result = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                Data            = signal.GetApiObject()
            };

            lobby.Broadcast(result.GetApiObject());
            return(resp);
        }
        /// <summary>
        /// Treść komunikatu przy odłączeniu klienta od serwera przez zbyt długi czas autoryzacji
        /// </summary>
        /// <returns>Obiekt JSON do przekazania do klienta</returns>
        protected virtual JObject GetAuthorizationTimeoutSignal()
        {
            var resp = new StandardResponseSerializer()
            {
                Status  = "AUTHORIZATION_TIMEOUT",
                Message = "Authorization failed - timeout"
            };
            var result = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_AUTHORIZATION,
                Data            = resp.GetApiObject()
            };

            return(result.GetApiObject());
        }
        /// <summary>
        /// Treść komunikatu przy odłączeniu klienta od serwera
        /// </summary>
        /// <returns>Obiekt JSON do przekazania do klienta</returns>
        protected virtual JObject GetDisconnectedSignal()
        {
            var resp = new StandardResponseSerializer()
            {
                Status  = "DISCONNECTED",
                Message = "You have been disconnected"
            };
            var result = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_SERVER_SIGNAL,
                Data            = resp.GetApiObject()
            };

            return(result.GetApiObject());
        }
Exemple #5
0
        public void Join(ClientConnection newConnection)
        {
            if (newConnection.Session.Has("joined-lobby"))
            {
                var lobby = newConnection.Session.Get("joined-lobby");
                if (lobby != null)
                {
                    throw new LobbyException("Cannot join two lobbies at once");
                }
            }

            if (ConnectedClients.Contains(newConnection))
            {
                throw new LobbyException("Already joined this lobby");
            }

            if (LobbyOwner == null)
            {
                LobbyOwner = newConnection;
            }

            string username = newConnection.Session.Get <string>("username");

            if (UsernameAlreadyJoined(username))
            {
                throw new UsernameTakenException("Username taken");
            }

            Console.WriteLine("Player " + username + " joined the lobby!");
            newConnection.Session.Set("joined-lobby", this);
            newConnection.BeforeDispose += OnClientConnectionDisposed;

            // Broadcast o dołączeniu nowego gracza do Lobby
            var signal = new LobbySignalUserJoinedSerializer()
            {
                Signal   = LobbySignalUserJoinedSerializer.SIGNAL_USER_JOINED,
                Message  = "User " + username + " joined the lobby",
                Username = username
            };
            var result = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                Data            = signal.GetApiObject()
            };

            Broadcast(result.GetApiObject());
            ConnectedClients.Add(newConnection);
        }
Exemple #6
0
        protected override BaseSerializer PerformAction(ClientConnection conn, BaseSerializer requestData)
        {
            RequestSerializer  data = (RequestSerializer)requestData;
            ResponseSerializer resp = (ResponseSerializer)InitializeResponseSerializer();

            resp.Status = "OK";

            Lobby lobby = (Lobby)conn.Session.Get("joined-lobby");
            Match game  = lobby.Game;

            if (lobby.LobbyState != LobbyState.IDLE)
            {
                data.AddError(null, "INVALID_LOBBY_STATE", "Nie można usiąść w tym momencie gry");
                data.ThrowException();
            }

            try {
                var player = new Player((PlayerTag)data.PlaceTag, (string)conn.Session.Get("username"));
                game.AddPlayer(player);
                conn.Session.Set("player", player);
                Console.WriteLine("Player sat at " + data.PlaceTag + ": " + conn.Session.Get("username"));

                var broadcastData = new LobbySignalUserSatSerializer()
                {
                    Signal   = LobbySignalUserSatSerializer.SIGNAL_USER_SAT,
                    PlaceTag = data.PlaceTag,
                    Username = player.Name
                };
                var broadcastWrapper = new StandardCommunicateSerializer()
                {
                    CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                    Data            = broadcastData.GetApiObject()
                };
                lobby.Broadcast(broadcastWrapper.GetApiObject());
            } catch (SeatTakenException) {
                data.AddError("PlaceTag", "SEAT_TAKEN", "Miejsce jest już zajęte");
                data.ThrowException();
            } catch (DuplicatedPlayerNameException) {
                data.AddError(null, "ALREADY_SEATED", "Użytkownik zajął już miejsce");
                data.ThrowException();
            } catch (WrongGameStateException) {
                data.AddError(null, "WRONG_GAME_STATE", "Nieprawidłowy stan gry dla tej operacji");
                data.ThrowException();
            }

            return(resp);
        }
Exemple #7
0
        protected override BaseSerializer PerformAction(ClientConnection conn, BaseSerializer requestData)
        {
            RequestSerializer  data = (RequestSerializer)requestData;
            ResponseSerializer resp = (ResponseSerializer)InitializeResponseSerializer();

            resp.Status = "OK";

            Lobby  lobby  = (Lobby)conn.Session.Get("joined-lobby");
            Match  game   = lobby.Game;
            Player player = new Player((PlayerTag)data.PlaceTag, (string)conn.Session.Get("username"));

            if (player != null)
            {
                try
                {
                    game.RemovePlayer(player);
                    conn.Session.Remove("player");

                    lobby.SetLobbyState(LobbyState.IDLE);

                    var username = conn.Session.Get <string>("username");

                    var signal = new LobbySignalUserSittedOutSerializer()
                    {
                        Signal   = LobbySignalUserSittedOutSerializer.SIGNAL_USER_SITTED_OUT,
                        Message  = "User " + username + " joined the lobby",
                        Username = username,
                        PlaceTag = (int)player.Tag
                    };
                    var result = new StandardCommunicateSerializer()
                    {
                        CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                        Data            = signal.GetApiObject()
                    };
                    lobby.Broadcast(result.GetApiObject());

                    Console.WriteLine("Player left at " + data.PlaceTag + ": " + conn.Session.Get("username"));
                }
                catch (WrongPlayerException) {
                    data.AddError("PlaceTag", "NOT_SEATEN_HERE", "Gracz nie siedzi na tym miejscu");
                    data.ThrowException();
                }
            }
            return(resp);
        }
Exemple #8
0
        /// <summary>
        /// Zmienia stan lobby jeśli jest inny niż podany w argumencie "newState"
        /// </summary>
        /// <param name="newState">Nowy stan do ustawienia</param>
        /// <param name="sendBroadcast">Określa czy należy wysłać broadcast do graczy o zmianie stanu lobby (jeżeli nastąpi zmiana stanu)</param>
        public void SetLobbyState(LobbyState newState, bool sendBroadcast = true)
        {
            if (newState != LobbyState)
            {
                LobbyState = newState;

                if (sendBroadcast)
                {
                    // Broadcast do graczy
                    var broadcastData = new LobbySignalLobbyStateChangedSerializer()
                    {
                        Signal     = LobbySignalLobbyStateChangedSerializer.SIGNAL_LOBBY_STATE_CHANGED,
                        LobbyState = (int)LobbyState
                    };
                    var broadcastWrapper = new StandardCommunicateSerializer()
                    {
                        CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                        Data            = broadcastData.GetApiObject()
                    };
                    Broadcast(broadcastWrapper.GetApiObject());
                }
            }
        }
Exemple #9
0
        protected override BaseSerializer PerformAction(ClientConnection conn, BaseSerializer requestData)
        {
            RequestSerializer  data = (RequestSerializer)requestData;
            ResponseSerializer resp = (ResponseSerializer)InitializeResponseSerializer();

            resp.Status = "OK";
            resp.Color  = data.Color;
            resp.Height = data.Height;
            resp.X      = data.X;
            resp.XX     = data.XX;

            Lobby lobby = (Lobby)conn.Session.Get("joined-lobby");
            Match game  = lobby.Game;

            if (lobby.LobbyState != LobbyState.IN_GAME)
            {
                data.AddError(null, "INVALID_LOBBY_STATE", "Nie można licytować w tym stanie lobby");
                data.ThrowException();
            }

            string username = (string)conn.Session.Get("username");

            int playerIndex = game.PlayerList.FindIndex(x => { return(username == x.Name); });

            // gdy nie ma takiego gracza przy stole => wywal wyjątek
            if (playerIndex == -1)
            {
                data.AddError("PlayerUsername", "INVALID_PLAYER", "Nie ma takiego gracza");
                data.ThrowException();
            }

            var player   = game.PlayerList[playerIndex];
            var contract = new Contract((ContractHeight)data.Height, (ContractColor)data.Color, player.Tag, data.X, data.XX);

            if (!game.CheckAddBid(contract))
            {
                data.AddError(null, "INVALID_CONTRACT", "Nie można zalicytować kontraktu");
                data.ThrowException();
            }
            game.AddBid(contract);

            Console.WriteLine(username + "> Bid: " + contract.ToString());

            // Broadcast do pozostałych graczy
            var broadcastData = new LobbySignalNewBidSerializer()
            {
                Signal   = LobbySignalNewBidSerializer.SIGNAL_NEW_BID,
                Username = username,
                PlaceTag = (int)player.Tag,
                Color    = data.Color,
                Height   = data.Height,
                X        = data.X,
                XX       = data.XX
            };
            var broadcastWrapper = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                Data            = broadcastData.GetApiObject()
            };

            lobby.Broadcast(broadcastWrapper.GetApiObject());

            // Broadcast o przepasowaniu całej licytacji, nowe rozdanie
            if (game.CurrentBidding.IsEnd() && game.CurrentBidding.HighestContract.ContractColor == ContractColor.NONE)
            {
                game.GameState = GameState.BIDDING;
                game.StartBidding();

                var bData = new LobbySignalGameStartedNextBiddingSerializer()
                {
                    Signal = LobbySignalGameStartedNextBiddingSerializer.SIGNAL_GAME_STARTED_NEXT_BIDDING,

                    PointsNSAboveLine = game.PointsNS[1],
                    PointsNSBelowLine = game.PointsNS[0],
                    PointsWEAboveLine = game.PointsWE[1],
                    PointsWEBelowLine = game.PointsWE[0],

                    RoundsNS = game.RoundsNS,
                    RoundsWE = game.RoundsWE
                };
                var bWrapper = new StandardCommunicateSerializer()
                {
                    CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                    Data            = bData.GetApiObject()
                };
                lobby.Broadcast(bWrapper.GetApiObject());
            }

            return(resp);
        }
Exemple #10
0
        public void RemoveFromLobby(ClientConnection client)
        {
            if (!ConnectedClients.Contains(client))
            {
                throw new ArgumentException("Client not connected to Lobby");
            }

            // Komunikat o opuszczeniu Lobby przez użytkownika
            string username = client.Session.Get <string>("username");

            var signal = new LobbySignalUserRemovedSerializer()
            {
                Signal   = LobbySignalUserRemovedSerializer.SINGAL_USER_REMOVED,
                Message  = "User " + username + " left the lobby",
                Username = username
            };
            var player = Game.GetPlayerByUsername(username);

            if (player != null)
            {
                Game.RemovePlayer(player);
                signal.WasSitted = true;
                signal.PlaceTag  = (int)player.Tag;

                SetLobbyState(LobbyState.IDLE); // Użytkownik siedział przy stole, jeśli gra była w trakcie, należy ją zapauzować
            }
            else
            {
                signal.WasSitted = false;
            }

            var result = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                Data            = signal.GetApiObject()
            };

            Broadcast(result.GetApiObject());

            // Usuwamy klienta z Lobby
            ConnectedClients.Remove(client);
            client.BeforeDispose -= OnClientConnectionDisposed;
            Console.WriteLine("Użytkownik usunięty z Lobby: " + username);

            // Ustawianie nowego właściciela Lobby
            if (LobbyOwner == client)
            {
                if (ConnectedClients.Count > 0)
                {
                    LobbyOwner = ConnectedClients.First();
                }
                else
                {
                    if (ParentManager == null)
                    {
                        Close();
                    }
                    else
                    {
                        ParentManager.CloseLobby(Id);
                    }
                }
            }
            client.Dispose();
        }
        private void Listen()
        {
            TcpListener = new TcpListener(IpAddress, Port);
            TcpListener.Start();

            List <ClientConnection> toRemove            = new List <ClientConnection>();
            List <ClientConnection> currentlyAuthorized = new List <ClientConnection>();

            while (true)
            {
                // Komunikaty
                toRemove.Clear();
                foreach (var connection in AuthorizedConnections)
                {
                    try {
                        connection.SendCommunicates();
                    } catch (IOException) {
                        toRemove.Add(connection);
                    } catch (ObjectDisposedException) {
                        toRemove.Add(connection);
                    } catch (InvalidOperationException) {
                        toRemove.Add(connection);
                    } catch (Exception) {
                        Console.WriteLine("Nie można było wysłać komunikatów do klienta: " + connection.ToString());
                    }
                }
                // Usuwanie zamkniętych połączeń
                foreach (var connection in toRemove)
                {
                    connection.Dispose();
                    AuthorizedConnections.Remove(connection);
                }
                toRemove.Clear();
                foreach (var connection in UnauthorizedConnections)
                {
                    try {
                        connection.SendCommunicates();
                    } catch (IOException) {
                        toRemove.Add(connection);
                    } catch (ObjectDisposedException) {
                        toRemove.Add(connection);
                    } catch (InvalidOperationException) {
                        toRemove.Add(connection);
                    } catch (Exception) {
                        Console.WriteLine("Nie można było wysłać komunikatów do klienta: " + connection.ToString());
                    }
                }
                // Usuwanie zamkniętych połączeń
                foreach (var connection in toRemove)
                {
                    connection.Dispose();
                    UnauthorizedConnections.Remove(connection);
                }

                // Zautoryzowane połączenia
                bool canContinue;
                toRemove.Clear();
                foreach (var connection in AuthorizedConnections)
                {
                    if (connection.DataAvailable)
                    {
                        connection.LastActivateAt = DateTime.Now;
                        JObject data = connection.GetData();
                        JObject response;
                        canContinue = true;

                        // Inicjalna walidacja (Bierzemy kod zapytania, jeśli został podany)
                        var initialCheck = new StandardRequestSerializer(data);
                        try {
                            initialCheck.Validate();
                        } catch (ValidationException) {
                            // Inicjalny format nie przechodzi sprawdzenia
                            var result = new StandardCommunicateSerializer();
                            var resp   = new StandardResponseSerializer();

                            result.CommunicateType = StandardCommunicateSerializer.TYPE_REQUEST_ERROR;
                            resp.Status            = "INVALID_FORMAT";
                            resp.Message           = "Request failed initial validation";
                            result.Data            = resp.GetApiObject();

                            response = result.GetApiObject();
                            connection.WriteData(response);
                            connection.Flush();

                            canContinue = false;
                        }

                        if (canContinue)
                        {
                            try {
                                try {
                                    var resp        = HandleRequest(connection, initialCheck.Data);
                                    var respWrapper = new StandardCommunicateSerializer()
                                    {
                                        CommunicateType = StandardCommunicateSerializer.TYPE_RESPONSE,
                                        RequestCode     = initialCheck.RequestCode,
                                        Data            = resp
                                    };
                                    response = respWrapper.GetApiObject();
                                } catch (ValidationException e) {
                                    var resp        = e.GetJson();
                                    var respWrapper = new StandardCommunicateSerializer()
                                    {
                                        CommunicateType = StandardCommunicateSerializer.TYPE_RESPONSE,
                                        RequestCode     = initialCheck.RequestCode,
                                        Data            = resp
                                    };
                                    response = respWrapper.GetApiObject();
                                }
                            } catch (Exception e) {
                                var resp = new StandardResponseSerializer()
                                {
                                    Status  = "ERR_INTERNAL",
                                    Message = "Wystąpił wewnętrzny błąd serwera"
                                };
                                var respWrapper = new StandardCommunicateSerializer()
                                {
                                    CommunicateType = StandardCommunicateSerializer.TYPE_REQUEST_ERROR,
                                    RequestCode     = initialCheck.RequestCode,
                                    Data            = resp.GetApiObject()
                                };
                                response = respWrapper.GetApiObject();
                            }

                            try {
                                connection.WriteData(response);
                                connection.Flush();
                            } catch (IOException) {
                                toRemove.Add(connection);
                            } catch (InvalidOperationException) {
                                toRemove.Add(connection);
                            }
                        }
                    }
                    else if (TimeSpan.Compare(DateTime.Now - connection.LastActivateAt, MaxIdleTime) > 0)
                    {
                        Console.WriteLine("IDLE CHECK");
                        connection.LastActivateAt = DateTime.Now;
                        var wrappedResponse = new StandardCommunicateSerializer()
                        {
                            CommunicateType = StandardCommunicateSerializer.TYPE_CONNECTION_CHECK,
                            RequestCode     = -1,
                            Data            = null
                        };
                        try {
                            connection.WriteData(wrappedResponse.GetApiObject());
                        } catch (IOException) {
                            toRemove.Add(connection);
                        } catch (ObjectDisposedException) {
                            toRemove.Add(connection);
                        } catch (InvalidOperationException) {
                            toRemove.Add(connection);
                        } catch (Exception) {
                            Console.WriteLine("Nie można było wysłać komunikatów do klienta: " + connection.ToString());
                        }
                    }
                }

                // Usuwanie zamkniętych połączeń
                foreach (var connection in toRemove)
                {
                    connection.Dispose();
                    AuthorizedConnections.Remove(connection);
                }

                // Niezautoryzowane połączenia
                toRemove.Clear();
                foreach (var connection in UnauthorizedConnections)
                {
                    bool authorized = false;
                    if (connection.DataAvailable)
                    {
                        canContinue = true;
                        JObject data         = connection.GetData();
                        var     initialCheck = new StandardRequestSerializer(data);
                        try {
                            try {
                                initialCheck.Validate();
                            } catch (ValidationException e) {
                                var wrappedResponse = new StandardCommunicateSerializer()
                                {
                                    CommunicateType = StandardCommunicateSerializer.TYPE_AUTHORIZATION,
                                    RequestCode     = initialCheck.RequestCode,
                                    Data            = GetAuthorizationResponseFailed()
                                };
                                connection.WriteData(wrappedResponse.GetApiObject());
                                connection.Flush();
                                canContinue = false;
                            }
                            if (canContinue)
                            {
                                // Zero zaufania do niezautoryzowanych połączeń
                                try {
                                    if (AuthorizeConnection(connection, initialCheck.Data))
                                    {
                                        var response        = GetAuthorizationResponseSuccessful();
                                        var wrappedResponse = new StandardCommunicateSerializer()
                                        {
                                            CommunicateType = StandardCommunicateSerializer.TYPE_AUTHORIZATION,
                                            RequestCode     = initialCheck.RequestCode,
                                            Data            = response
                                        };
                                        authorized = true;

                                        // Informacja dla odbiorcy o poprawnej autoryzacji
                                        connection.WriteData(wrappedResponse.GetApiObject());
                                        connection.Flush();

                                        connection.LastActivateAt = DateTime.Now;

                                        currentlyAuthorized.Add(connection);
                                    }
                                    else
                                    {
                                        var response        = GetAuthorizationResponseFailed();
                                        var wrappedResponse = new StandardCommunicateSerializer()
                                        {
                                            CommunicateType = StandardCommunicateSerializer.TYPE_AUTHORIZATION,
                                            RequestCode     = initialCheck.RequestCode,
                                            Data            = response
                                        };
                                        connection.WriteData(wrappedResponse.GetApiObject());
                                        connection.Flush();
                                    }
                                } catch (ValidationException e) {
                                    var wrappedResponse = new StandardCommunicateSerializer()
                                    {
                                        CommunicateType = StandardCommunicateSerializer.TYPE_AUTHORIZATION,
                                        RequestCode     = initialCheck.RequestCode,
                                        Data            = GetAuthorizationResponseFailed()
                                    };
                                    connection.WriteData(wrappedResponse.GetApiObject());
                                    connection.Flush();
                                }
                            }
                        } catch (IOException e) {
                            // Połączenie socketu rozłączone
                            toRemove.Add(connection);
                        } catch (ObjectDisposedException e) {
                            // Połączenie socketu rozłączone
                            toRemove.Add(connection);
                        } catch (InvalidOperationException) {
                            toRemove.Add(connection);
                        } catch (Exception e) {
                            Console.WriteLine("Nieobsłużony wyjątek dla zapytania od połączenia " + connection.ToString() + "\n" + e.ToString());
                        }
                    }
                    if (!authorized && TimeSpan.Compare(connection.GetConnectionTime(), TimeForAuthorization) > 0)
                    {
                        connection.WriteData(GetAuthorizationTimeoutSignal());
                        connection.Flush();

                        connection.TcpClient.Close();
                        toRemove.Add(connection);
                    }
                }

                // Finalizacja przenoszenie połączenia po zautoryzowaniu lub zamknięciu
                foreach (var connection in currentlyAuthorized)
                {
                    UnauthorizedConnections.Remove(connection);
                    AuthorizedConnections.Add(connection);
                }
                currentlyAuthorized.Clear();
                foreach (var connection in toRemove)
                {
                    connection.Dispose();
                    UnauthorizedConnections.Remove(connection);
                }

                // Odłączanie klientów do odłączenia
                foreach (var connection in ClientsToDisconnect)
                {
                    if (AuthorizedConnections.Contains(connection))
                    {
                        try {
                            connection.WriteData(GetDisconnectedSignal());
                            connection.Flush();
                        } catch (Exception) { }

                        connection.Dispose();
                        AuthorizedConnections.Remove(connection);
                    }
                    else if (UnauthorizedConnections.Contains(connection))
                    {
                        try {
                            connection.WriteData(GetDisconnectedSignal());
                            connection.Flush();
                        } catch (Exception) { }

                        connection.Dispose();
                        UnauthorizedConnections.Remove(connection);
                    }
                }

                // Nowe połączenia
                HandleIncommingConnections();
            }
        }
        protected override BaseSerializer PerformAction(ClientConnection conn, BaseSerializer requestData)
        {
            RequestSerializer  data = (RequestSerializer)requestData;
            ResponseSerializer resp = (ResponseSerializer)InitializeResponseSerializer();

            resp.Status = "OK";

            Lobby lobby = (Lobby)conn.Session.Get("joined-lobby");
            Match game  = lobby.Game;

            if (lobby.LobbyState != LobbyState.IN_GAME)
            {
                data.AddError(null, "INVALID_LOBBY_STATE", "Nie można wyłożyć karty w tym stanie lobby");
                data.ThrowException();
            }

            if (game.GameState != GameState.PLAYING)
            {
                data.AddError(null, "INVALID_GAME_STATE", "Gra nie jest w poprawnym stanie do tej akcji");
                data.ThrowException();
            }

            var username = conn.Session.Get <string>("username");

            Console.WriteLine(username + "> Card attempt: " + data.CardOwnerPosition + " " + data.Figure + " " + ((CardColor)data.Color).ToString());
            if (!conn.Session.Has("player"))
            {
                data.AddError(null, "INVALID_USER", "Podany użytkownik nie jest uczestnikiem rozgrywki");
                data.ThrowException();
            }
            var player    = conn.Session.Get <Player>("player");
            var cardOwner = game.GetPlayerAt((PlayerTag)data.CardOwnerPosition);

            // Inny gracz niz my (gracz musi byc dziadkiem)
            if (player != game.GetPlayerAt((PlayerTag)data.CardOwnerPosition))
            {
                if (player.Tag != game.CurrentBidding.Declarer)
                {
                    data.AddError(null, "INVALID_HAND", "Nie można wyłożyć karty z ręki tego gracza");
                    data.ThrowException();
                }

                if (((int)player.Tag + 2) % 4 == (int)game.CurrentBidding.Declarer)
                {
                    // Próbujemy wyłożyć kartę kogoś innego niż dziadka
                    data.AddError(null, "INVALID_HAND", "Nie można wyłożyć karty jako dziadek");
                    data.ThrowException();
                }
            }
            else
            {
                if (((int)player.Tag + 2) % 4 == (int)game.CurrentBidding.Declarer)
                {
                    // Jesteśmy dziadkiem
                    data.AddError(null, "INVALID_HAND", "Nie można wyłożyć karty jako dziadek");
                    data.ThrowException();
                }
            }

            // czy gracz ma taką kartę na ręce
            bool cardFound = false;
            Card card      = null;

            for (int i = 0; i < cardOwner.Hand.Length; i++)
            {
                if (cardOwner.Hand[i].Color == (CardColor)data.Color && cardOwner.Hand[i].Figure == (CardFigure)data.Figure)
                {
                    cardFound = true;
                    card      = cardOwner.Hand[i];
                    break;
                }
            }

            // gracz nie ma takiej karty na ręce
            if (!cardFound)
            {
                data.AddError(null, "INVALID_CARD", "Gracz nie posiada takiej karty na ręce");
                data.ThrowException();
            }

            bool canPlayerPutCard = game.CheckNextCard(cardOwner.Tag, card.Color, card.Figure);

            // gracz nie może wyłożyć tej karty
            if (!canPlayerPutCard)
            {
                data.AddError(null, "INVALID_CARD", "Nie można wyłożyć tej karty");
                data.ThrowException();
            }

            game.NextCard((PlayerTag)data.CardOwnerPosition, card.Color, card.Figure);

            Console.WriteLine(username + "> Card: " + data.CardOwnerPosition + " " + (int)card.Figure + " " + card.Color.ToString());

            var broadcastData = new PutCardSignalSerializer()
            {
                Signal        = PutCardSignalSerializer.SIGNAL_USER_PUT_CARD,
                Username      = username,
                OwnerPosition = data.CardOwnerPosition,
                CardFigure    = data.Figure,
                CardColor     = data.Color
            };
            var broadcastWrapper = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                Data            = broadcastData.GetApiObject()
            };

            lobby.Broadcast(broadcastWrapper.GetApiObject());

            if (game.GameState == GameState.BIDDING)
            {
                var bData = new LobbySignalGameStartedNextBiddingSerializer()
                {
                    Signal = LobbySignalGameStartedNextBiddingSerializer.SIGNAL_GAME_STARTED_NEXT_BIDDING,

                    PointsNSAboveLine = game.PointsNS[1],
                    PointsNSBelowLine = game.PointsNS[0],
                    PointsWEAboveLine = game.PointsWE[1],
                    PointsWEBelowLine = game.PointsWE[0],

                    RoundsNS = game.RoundsNS,
                    RoundsWE = game.RoundsWE
                };
                var bWrapper = new StandardCommunicateSerializer()
                {
                    CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                    Data            = bData.GetApiObject()
                };
                lobby.Broadcast(bWrapper.GetApiObject());
            }
            else if (game.GameState == GameState.GAME_FINISHED)
            {
                var bData = new LobbySignalGameFinishedSerializer()
                {
                    Signal   = LobbySignalGameFinishedSerializer.SIGNAL_GAME_FINISHED,
                    Winner   = (game.RoundsNS == 2) ? (short)0 : (short)1,
                    PointsNS = game.PointsNS[0] + game.PointsNS[1],
                    PointsWE = game.PointsWE[0] + game.PointsWE[1],
                    RoundsNS = game.RoundsNS,
                    RoundsWE = game.RoundsWE
                };
                var bWrapper = new StandardCommunicateSerializer()
                {
                    CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                    Data            = bData.GetApiObject()
                };
                lobby.Broadcast(bWrapper.GetApiObject());
            }

            resp.CardFigure    = (int)card.Figure;
            resp.CardColor     = (int)card.Color;
            resp.OwnerPosition = (int)data.CardOwnerPosition;
            return(resp);
        }
        protected override BaseSerializer PerformAction(ClientConnection conn, BaseSerializer requestData)
        {
            RequestSerializer  data = (RequestSerializer)requestData;
            ResponseSerializer resp = (ResponseSerializer)InitializeResponseSerializer();

            resp.Status = "OK";

            Lobby lobby = conn.Session.Get <Lobby>("joined-lobby");
            Match game  = lobby.Game;

            // Check czy ktokolwiek w ogóle siedzi na tym miejscu
            var playerAtPlace = lobby.Game.GetPlayerAt((PlayerTag)data.PlaceTag);

            if (playerAtPlace == null)
            {
                data.AddError("PlaceTag", "NO_PLAYER_HERE", "Żaden gracz nie siedzi na tym miejscu");
                data.ThrowException();
            }

            // Check uprawnień w przypadku, gdy nie jesteśmy właścicielem Lobby
            if (lobby.LobbyOwner != conn)
            {
                if (playerAtPlace.Name != conn.Session.Get <string>("username"))
                {
                    data.AddError(null, "FORBIDDEN", "Brak uprawnień do tej czynności.");
                    data.ThrowException();
                }
            }

            // Lepiej jeśli cokolwiek zepsuje się po usunięciu gracza ze stołu. Wtedy rozgrywkę będzie można kontynuować mimo błędu
            lobby.Game.RemovePlayer(playerAtPlace);

            lobby.SetLobbyState(LobbyState.IDLE); // Jeśli Lobby miało rozpoczętą grę, zostanie zapauzowane

            var username = playerAtPlace.Name;
            var signal   = new LobbySignalUserSittedOutSerializer()
            {
                Signal   = LobbySignalUserSittedOutSerializer.SIGNAL_USER_SITTED_OUT,
                Message  = "User " + username + " joined the lobby",
                Username = username,
                PlaceTag = (int)playerAtPlace.Tag
            };
            var result = new StandardCommunicateSerializer()
            {
                CommunicateType = StandardCommunicateSerializer.TYPE_LOBBY_SIGNAL,
                Data            = signal.GetApiObject()
            };

            lobby.Broadcast(result.GetApiObject());

            var index = lobby.ConnectedClients.FindIndex((client) => {
                return(client.Session.Get <string>("username") == playerAtPlace.Name);
            });

            if (index != -1)
            {
                var client = lobby.ConnectedClients[index];
                client.Session.Remove("player");
            }

            return(resp);
        }