internal static void ForceClose(Client client, GameDataAction Error)
 {
     if (client.RawClient.Connected)
     {
         client.Writer.SendAction(Error);
     }
 }
 private void AddLine(GameDataAction input)
 {
     var sb = new StringBuilder();
     sb.Append($"{input.Action} : ");
     foreach (var kvp in input.Data)
     {
         sb.Append($"['{kvp.Key}' = {kvp.Value}] ");
     }
     AddLine(sb.ToString());
 }
        private static async void HandleClientComm(object connection)
        {
            var tcpClient = (TcpClient) connection;
            // Create an instance of our custom client handling object
            var client = new Client(tcpClient);
            Clients.Add(client);
            var player = new Player
            {
                DataWriter = client.Writer
            };
            client.Player = player;
            Players.Add(player);
            if (Players.Count == 1)
            {
                // First player setup
                ServerRandom.Initialise();
            }


            // Initial Handshake as per protocol s2.0 should start with the
            //  protocol version to make sure client and server are compatible
            client.Writer.SendAction(GameAction.Meta,
                new Dictionary<string, GameData> {{"protocol", GameActionWriter.PROTOCOL_VERSION.ToString()}});
            var phase = ConnectionPhase.Handshake;
            while (tcpClient.Connected)
            {
                var line = await client.Reader.ReadLineAsync();
                if (string.IsNullOrEmpty(line))
                {
                    // This happens when the client disconnects unexpectedly
                    break;
                }
                var input = new GameDataAction(line);

                Console.WriteLine($"--> Recieved: {input.Action}");
                foreach (var kvp in input.Data)
                {
                    Console.WriteLine($"   + '{kvp.Key}' => {kvp.Value}");
                }
                var handled = false;
                if (input.Action == GameAction.Ping)
                {
                    // Network Protocol s2.1
                    if (input.Data["counter"] == (++client.PingCounter))
                    {
                        client.Writer.SendAction(GameAction.Ping,
                            new Dictionary<string, GameData> {{"counter", (++client.PingCounter)}});
                    }
                    else
                    {
                        // Use ForceClose here? 
                        // Should never occur -- just incase!
                        client.Writer.SendAction(GameAction.Error,
                            new Dictionary<string, GameData>
                            {
                                {"code", ErrorCode.PingMismatch},
                                {
                                    "message",
                                    $"Server was Expecting: {client.PingCounter}, Client Sent: {input.Data["counter"]}"
                                }
                            });
                    }
                    handled = true;
                }

                if (input.Action == GameAction.Meta)
                {
                    switch (phase)
                    {
                        case ConnectionPhase.Handshake:
                            HandleHandshake(client, ref phase, input, ref handled);
                            break;
                        case ConnectionPhase.Setup:
                            handled = HandleSetup(client, ref phase, input, ref handled);
                            break;
                    }

                    if (!handled)
                    {
                        Game.Board.RecieveCommand(player, input);
                    }
                }
            }
        }
 private static void HandleHandshake(Client client, ref ConnectionPhase phase, GameDataAction input, ref bool handled)
 {
     if (input.Data.ContainsKey("protocol"))
     {
         if (input.Data["protocol"] != GameActionWriter.PROTOCOL_VERSION.ToString())
         {
             CloseConnection(client,
                 ErrorCode.VersionMismatch,
                 $"Server version: {GameActionWriter.PROTOCOL_VERSION} - Client Version: {input.Data["protocol"]}");
             handled = true;
         }
     }
     if (input.Data.ContainsKey("name"))
     {
         client.Player.Name = input.Data["name"];
         handled = true;
         phase = ConnectionPhase.Setup;
         client.Writer.SendAction(GameAction.Meta, new Dictionary<string, GameData>
                     {
                         {"phase", ConnectionPhase.Setup}
                     });
     }
 }
        private static bool HandleSetup(Client client, ref ConnectionPhase phase, GameDataAction input, ref bool handled)
        {
            if (input.Data.ContainsKey("deck"))
            {
                handled = true;
                var deckData = input.Data["deck"].String();
                var ids = deckData.Split(',');
                if (ids.Length == Deck.CardLimit)
                {
                    client.Player.Deck = new Deck();
                    var usedIDs = new Dictionary<string, int>();
                    foreach (var id in ids)
                    {
                        int current;
                        if (usedIDs.TryGetValue(id, out current))
                        {
                            if (current < Deck.CardDuplicateLimit)
                            {
                                usedIDs[id] = current+1;
                            }
                            else
                            {
                                CloseConnection(client,
                                    ErrorCode.InvalidDeck,
                                    $"More than {Deck.CardDuplicateLimit} of card id '{id}' detected in deck.");
                            }
                        }
                        else
                        {
                            usedIDs.Add(id, 1);
                        }
                        var card = Game.Cards[id].CreateInstance();
                        
                        //Game.Board.Cards.Add(card.UID, card);
                        client.Player.Deck.PushRandom(card);
                    }

                    client.Writer.SendAction(GameAction.Meta, new Dictionary<string, GameData> {
                        { "deckvalid", 1 }
                    });

                    client.Player.SetupComplete = true;

                    if (Players.Count == PlayerAmount && Players.All(x => x.SetupComplete))
                    {
                        Game.StartGame(Players);
                    }
                }
                else
                {
                    CloseConnection(client,
                       ErrorCode.InvalidDeck,
                       $"Invalid amount of cards, deck requires {Deck.CardLimit}. {ids.Length} cards were recieved.");
                }

            }

            return handled;
        }
 public void SendAction(GameDataAction gameDataAction)
 {
     SendAction(gameDataAction.Action, gameDataAction.Data);
 }
        /// <summary>
        /// Handles a GameAction command sent by a player.
        /// </summary>
        /// <param name="player">The player that sent the command</param>
        /// <param name="action">What type of action it is</param>
        /// <param name="data">The data, such as who to target or the player's name</param>
        public void RecieveCommand(Player player, GameDataAction dataAction)
        {
            // TODO: Finish the command recieved events
            var data = dataAction.Data;
            var action = dataAction.Action;
            if (player == ActivePlayer)
            {
                switch (action)
                {
                    case GameAction.TurnEnd:
                        EndTurn(null);
                        break;
                    case GameAction.PlayCard:
                        Card card;
                        // Attempt to get the card matching the UID
                        if (player.Cards.TryGetValue(data["uid"], out card))
                        {
                            GameData targetID;
                            if (data.TryGetValue("target", out targetID))
                            {

                            }
                            card.Play();
                        }
                        break;
                    case GameAction.GameStart:
                        break;
                    case GameAction.TurnStart:
                        break;
                    case GameAction.DrawCard:
                        break;
                    case GameAction.SetMana:
                        break;
                    case GameAction.SetHealth:
                        break;
                    case GameAction.Attack:
                        break;
                    case GameAction.Trigger:
                        break;
                    case GameAction.Kill:
                        break;
                    case GameAction.MinionSummoned:
                        break;
                    case GameAction.SpellCast:
                        break;
                    case GameAction.GameOver:
                        break;
                    case GameAction.Meta:
                        break;
                    case GameAction.Ping:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(action), action, null);
                }
            }
        }
        private async void GetData(Client c)
        {
            while (c.RawClient.Connected)
            {
                var line = await c.Reader.ReadLineAsync();
                var input = new GameDataAction(line);
                AddLine(input);

                if (input.Action == GameAction.Ping)
                {
                    if (input.Data["counter"].Int() == (++_pingCounter))
                    {
                        AddLine("Ping Success.");
                    }
                    else
                    {
                        AddLine("WARNING: Ping Failure!!!!!!");
                    }
                }
            }
            lbRecieved.Items.Add("Disconnected.");
        }
 public void SendAction(GameDataAction gameDataAction)
 {
     SendAction(gameDataAction.Action, gameDataAction.Data);
 }
        private async void GetData(Client c)
        {
            while (c.RawClient.Connected)
            {
                var line = await c.Reader.ReadLineAsync();
                var input = new GameDataAction(line);
                AddLine(input);

                if (input.Action == GameAction.Ping)
                {
                    if (input.Data["counter"].Int() == (++_pingCounter))
                    {
                        AddLine("Ping Success.");
                    }
                    else
                    {
                        AddLine("WARNING: Ping Failure!!!!!!");
                    }
                }
                else if (input.Action == GameAction.Meta)
                {
                    if (input.Data.ContainsKey("phase"))
                    {
                        Phase = input.Data["phase"];
                        switch (Phase)
                        {
                            case ConnectionPhase.Handshake:
                                // This shouldn't occur, is the starting phase.
                                break;
                            case ConnectionPhase.Setup:
                                OnSetupPhase();
                                break;
                            case ConnectionPhase.Game:
                                OnGamePhase();
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                    }
                }
                else if (input.Action == GameAction.GameStart)
                {
                    PlayerID = input.Data["number"];
                    Players = input.Data["players"];
                }
                else if (input.Action == GameAction.DrawCard)
                {
                    if (input.Data["player"] == PlayerID)
                    {

                        string cardID = input.Data["card"];
                        var card = Game.Cards[cardID].CreateInstance();

                        AddCard($"{cardID}\n{card.Cost}\n{card.Type}");
                    }
                }
            }
            lbRecieved.Items.Add("Disconnected.");
        }