public static void DisbandGame(string gameId)
 {
     if (m_Games.ContainsKey(gameId))
     {
         BesiegedGameInstance removedGame;
         m_Games.TryRemove(gameId, out removedGame);
         GenericClientMessage remove = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.RemoveGame, GameId = removedGame.GameId };
         NotifyAllConnectedClients(remove.ToXml());
         ConsoleLogger.Push(string.Format("Game disbanded: {0}", removedGame.Name));
         removedGame.Dispose();
     }
 }
        private void ProcessMessages()
        {
            // All generic server messages are handled here
            m_GenericServerMessageSubscriber = MessageSubject
                .Where(message => message is GenericServerMessage)
                .Subscribe(message =>
                {
                    var genericMessage = message as GenericServerMessage;
                    switch (genericMessage.MessageEnum)
                    {
                        case ServerMessage.ServerMessageEnum.StartServer:
                            break;
                        case ServerMessage.ServerMessageEnum.ServerStarted:
                            break;
                        default:
                            ConsoleLogger.Push("Unhandled GenericServerMessage was received: " + genericMessage.MessageEnum.ToString());
                            break;
                    }
                });

            // All server messages are handled here
            m_ServerMessageSubscriber = MessageSubject
                .Where(message => message is ServerMessage && !(message is GenericServerMessage))
                .Subscribe(message =>
                {
                    if (message is CreateGameMessage)
                    {
                        //CommandCreateGame commandCreateGame = command as CommandCreateGame; // create the new game instance
                        CreateGameMessage gameMessage = message as CreateGameMessage;
                        string gameId = Guid.NewGuid().ToString();
                        BesiegedGameInstance gameInstance = new BesiegedGameInstance(gameId, gameMessage.GameName, gameMessage.MaxPlayers, gameMessage.Password, gameMessage.ClientId);
                        m_Games.GetOrAdd(gameId, gameInstance);

                        JoinGameMessage join = new JoinGameMessage() { ClientId = message.ClientId, Password = gameMessage.Password, GameId = gameId };  // add the client that requested the new game to the game instance
                        m_MessageQueue.Add(join);

                        //string capacity = string.Format("{0}/{1} players", gameInstance.Players.Count, gameInstance.MaxPlayers);   // notify all connect clients of the updated game instance
                        //GameInfoMessage gameInfo = new GameInfoMessage(gameInstance.GameId, gameInstance.Name, capacity, gameInstance.IsGameInstanceFull, gameInstance.Password != string.Empty ? true : false);
                        ConsoleLogger.Push(string.Format("{0} has created a new game called: {1}", m_ConnectedClients[message.ClientId].Name, gameInstance.Name));
                        //NotifyAllConnectedClients(gameInfo.ToXml());
                    }
                });

            // Game messages that are no longer valid are handled here
            m_BadGameMessageSubscriber = MessageSubject
                .Where(message => message is GameMessage && !m_Games.ContainsKey(message.GameId))
                .Subscribe(message =>
                {
                    GenericClientMessage notFound = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.GameNotFound };
                    m_ConnectedClients[message.ClientId].Callback.SendMessage(notFound.ToXml());
                });
        }
        private void ConfigureMachine()
        {
            m_GameMachine = new StateMachine<State, Trigger>(() => m_CurrentState, newState => m_CurrentState = newState);
            ProcessMessages();

            #region WaitingForPlayers
            m_GameMachine.Configure(State.WaitingForPlayers)
                .Permit(Trigger.AllPlayersReady, State.AllPlayersReady)
                .OnEntryFrom(Trigger.PlayerNotReady, x =>
                {
                    GenericClientMessage waiting = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.PlayerNotReady };
                    LookupPlayerById(m_GameCreatorClientId).Callback.SendMessage(waiting.ToXml());
                })
                .OnEntryFrom(Trigger.PlayerLeft, x =>
                {
                    SendUpdatedGameInfo();
                })
                .PermitReentry(Trigger.PlayerLeft)
                .Ignore(Trigger.PlayerNotReady)
                .Ignore(Trigger.CreatorPressedStart);
            #endregion

            #region AllPlayersReady
            m_GameMachine.Configure(State.AllPlayersReady)
                .OnEntry(x =>
                {
                    GenericClientMessage ready = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.AllPlayersReady };
                    LookupPlayerById(m_GameCreatorClientId).Callback.SendMessage(ready.ToXml());
                })
                .Permit(Trigger.PlayerNotReady, State.WaitingForPlayers)
                .Permit(Trigger.PlayerLeft, State.WaitingForPlayers)
                .Permit(Trigger.CreatorPressedStart, State.GameStarted);
            #endregion

            #region GameStarted
            m_GameMachine.Configure(State.GameStarted)
                .OnEntry(x =>
                {
                    List<KeyValuePair<string, Army.ArmyTypeEnum>> PlayerInfos = new List<KeyValuePair<string, Army.ArmyTypeEnum>>();
                    foreach (Player player in Players)
                    {
                        PlayerInfos.Add(new KeyValuePair<string, Army.ArmyTypeEnum>(player.ClientId, player.ArmyType));
                        m_PlayerTurnOrder.Enqueue(player.ClientId);
                    }
                    GameState = new GameState(PlayerInfos);
                    pathFinder = new PathFinder(GameState);
                    ConsoleLogger.Push(String.Format("Game {0} has been started", Name));
                    NotifyAllPlayers(new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.TransitionToLoadingState }.ToXml()); // switch all the players to loading while we send the gamestate
                    ClientGameStateMessage gamestate = new ClientGameStateMessage() { State = GameState };
                    GenericClientMessage start = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.StartGame };
                    AggregateMessage aggregate = new AggregateMessage();
                    aggregate.MessageList.Add(gamestate);
                    aggregate.MessageList.Add(start);
                    NotifyAllPlayers(aggregate.ToXml());
                    m_GameMachine.Fire(Trigger.GameStarted);
                })
                .Permit(Trigger.GameStarted, State.PlayerTurn)
                .Ignore(Trigger.PlayerNotReady);
            #endregion

            #region PlayerTurn
            m_GameMachine.Configure(State.PlayerTurn)
                .PermitReentry(Trigger.PlayerTurn)
                .Permit(Trigger.PlayerLeft, State.Reconfigure)
                .Permit(Trigger.StartBattlePhase, State.BattlePhase)
                .Permit(Trigger.Cheatcode, State.EndGame)
                .OnEntry(x =>
                {
                    // notify the current player that its their turn
                    m_CurrentPlayerId = m_PlayerTurnOrder.Dequeue();
                    LookupPlayerById(m_CurrentPlayerId).Callback.SendMessage((new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.ActiveTurn }).ToXml());

                    // notify all other players that they have to wait
                    foreach (string playerId in m_PlayerTurnOrder)
                    {
                        LookupPlayerById(playerId).Callback.SendMessage((new WaitingForTurnMessage() { ActivePlayerName = LookupPlayerById(m_CurrentPlayerId).Name }).ToXml());
                    }

                    // add the current player back on the queue
                    m_PlayerTurnOrder.Enqueue(m_CurrentPlayerId);
                });
            #endregion

            m_GameMachine.Configure(State.BattlePhase)
                .OnEntry(x =>
                {

                });

            #region EndGame
            m_GameMachine.Configure(State.EndGame)
                .OnEntry(x =>
                {
                    var winner = LookupPlayerById(m_WinnerId);
                    var gameOverMessage = new GameOverMessage() { WinnerId = m_WinnerId, WinnerName = winner.Name };
                    NotifyAllPlayers(gameOverMessage.ToXml());
                });
            #endregion

            #region Reconfigure
            m_GameMachine.Configure(State.Reconfigure)
                .OnEntry(x =>
                {
                    // this state allows us to reconfigure the players involved in the game in case someone leaves or is defeated
                    Queue<string> tempPlayers = new Queue<string>();
                    foreach (string playerId in m_PlayerTurnOrder)
                    {
                        if (Players.FirstOrDefault(p => p.ClientId == playerId) != null)
                        {
                            tempPlayers.Enqueue(playerId);
                        }
                    }
                    if (tempPlayers.Count > 0)
                    {
                        m_PlayerTurnOrder.Clear();
                        m_PlayerTurnOrder = tempPlayers;
                        m_GameMachine.Fire(Trigger.PlayerTurn);
                    }
                })
                .Permit(Trigger.PlayerTurn, State.PlayerTurn);
            #endregion
        }
        public void SendMessage(string serializedMessage)
        {
            try
            {
                BesiegedMessage message = serializedMessage.FromXml<BesiegedMessage>();
                if (message is GenericServerMessage && (message as GenericServerMessage).MessageEnum == ServerMessage.ServerMessageEnum.StartServer)
                {
                    m_ServerCallback = OperationContext.Current.GetCallbackChannel<IClient>();
                    GenericServerMessage started = new GenericServerMessage() { MessageEnum = ServerMessage.ServerMessageEnum.ServerStarted };
                    m_ServerCallback.SendMessage(started.ToXml());
                    m_IsServerInitialized.Value = true;
                    //StartProcessingMessages();
                    ProcessMessages();
                }
                else if (message is ConnectMessage)
                {
                    IClient callback = OperationContext.Current.GetCallbackChannel<IClient>();
                    string clientId = Guid.NewGuid().ToString();
                    ConnectedClient connectedClient = new ConnectedClient((message as ConnectMessage).Name, clientId, callback);
                    AggregateMessage aggregate = new AggregateMessage();
                    GenericClientMessage success = new GenericClientMessage() { ClientId = clientId, MessageEnum = ClientMessage.ClientMessageEnum.ConnectSuccessful };
                    aggregate.MessageList.Add(success);

                    if (m_Games.Count > 0)  // notify the client of any pre-existing game instances that they might be able to join
                    {
                        foreach (KeyValuePair<string, BesiegedGameInstance> game in m_Games)
                        {
                            if (!game.Value.IsGameInstanceFull)
                            {
                                string capacity = string.Format("{0}/{1} players", game.Value.Players.Count, game.Value.MaxPlayers);
                                GameInfoMessage gameInfo = new GameInfoMessage(game.Value.GameId, game.Value.Name, capacity, false, game.Value.Password != string.Empty ? true : false);
                                aggregate.MessageList.Add(gameInfo);
                            }
                        }
                    }

                    callback.SendMessage(aggregate.ToXml());
                    ConsoleLogger.Push(string.Format("{0} has joined the server", connectedClient.Name));
                    m_ConnectedClients.GetOrAdd(clientId, connectedClient);     // Add an entry to the global client hook
                }
                else
                {
                    m_MessageQueue.Add(message);
                }
            }
            catch (Exception ex)
            {
                ErrorLogger.Push(ex);
            }
        }
        public void RemovePlayer(string clientId)
        {
            if (clientId == m_GameCreatorClientId)
            {
                GenericClientMessage disbanded = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.GameDisbanded };
                NotifyAllPlayers(disbanded.ToXml());
                BesiegedServer.DisbandGame(GameId);
            }
            else
            {
                Player player = Players.FirstOrDefault(x => x.ClientId == clientId);
                Players.Remove(player);
                ConsoleLogger.Push(string.Format("{0} with ClientId {1} has left game {2}", player.Name, player.ClientId, Name));

                AggregateMessage aggregate = new AggregateMessage();
                GenericClientMessage remove = new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.RemovePlayer, ClientId = player.ClientId };
                ClientChatMessage chatMessage = new ClientChatMessage() { Contents = string.Format("* {0} has left the game *", player.Name) };
                aggregate.MessageList.Add(remove);
                aggregate.MessageList.Add(chatMessage);
                NotifyAllPlayers(aggregate.ToXml());

                ColorPool.Push(player.PlayerColor);
                player.Callback.SendMessage((new GenericClientMessage() { MessageEnum = ClientMessage.ClientMessageEnum.TransitionToMultiplayerMenuState }).ToXml());
                player = null;
                m_GameMachine.Fire(Trigger.PlayerLeft);
            }
        }