/// <summary>
        /// Get the player's opponent
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>null if player is not part of a game session</returns>
        public NetworkBackgammonPlayer GetOpposingPlayer(NetworkBackgammonPlayer player)
        {
            NetworkBackgammonPlayer retval = null;

            // Get the game session associated with this player
            NetworkBackgammonGameSession gameSession = GetGameSession(player);

            if (gameSession != null)
            {
                retval = gameSession.GetOpponent(player);
            }

            return(retval);
        }
        /// <summary>
        /// Get the game session the the "player" is currently apart of
        /// </summary>
        /// <param name="player">Backgammon player to be checked</param>
        /// <returns>null if player is not part of a game session</returns>
        public NetworkBackgammonGameSession GetGameSession(NetworkBackgammonPlayer player)
        {
            NetworkBackgammonGameSession retval = null;

            // Look through the list of game sessions and make sure the player is not already playing in another room
            foreach (NetworkBackgammonGameSession session in gameSessions)
            {
                if (session.ContainsPlayer(player))
                {
                    retval = session;
                    break;
                }
            }

            return(retval);
        }
        /// <summary>
        /// Game session monitor (worker thread)
        /// </summary>
        public void GameSessionsMonitorThreadFunc()
        {
            NetworkBackgammonEventQueueElement queueElement = null;

            while (gameSessionsMonitorKeepRunning)
            {
                gameSessionsSemaphore.WaitOne();

                lock (gameSessionsEventQueue)
                {
                    if (gameSessionsEventQueue.Count > 0)
                    {
                        queueElement = gameSessionsEventQueue.Dequeue();
                    }
                }

                if (queueElement != null)
                {
                    if (queueElement.Notifier is NetworkBackgammonGameSession &&
                        queueElement.Event is NetworkBackgammonGameSessionEvent)
                    {
                        NetworkBackgammonGameSession      gameSession      = (NetworkBackgammonGameSession)queueElement.Notifier;
                        NetworkBackgammonGameSessionEvent gameSessionEvent = (NetworkBackgammonGameSessionEvent)queueElement.Event;

                        if (gameSessionEvent.EventType == NetworkBackgammonGameSessionEvent.GameSessionEventType.GameFinished)
                        {
                            // Broadcast the game active event to all registered listeners
                            Broadcast(new NetworkBackgammonGameRoomEvent(NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerFinished));

                            gameSession.Stop();

                            gameSessions.Remove(gameSession);

                            gameSession = null;

                            GC.Collect();
                        }
                    }
                }

                queueElement = null;
            }
        }
        /// <summary>
        /// Exit the game room by player
        /// </summary>
        /// <param name="_player">Backgammon player who wants to leave the game room</param>
        public void Leave(NetworkBackgammonPlayer _player)
        {
            if (connectedPlayers.Contains(_player))
            {
                // The disconnected player should no longer be listening...
                RemoveListener(_player);
                // Stop listening to this player
                _player.RemoveListener(this);

                // Check if player is associated with a game room and remove if necessary
                NetworkBackgammonGameSession _playerGameSession = GetGameSession(_player);

                if (_playerGameSession != null)
                {
                    // Disconnect the player from the game session
                    _player.RemoveListener(_playerGameSession);
                    // Disconnect the game session from the player
                    _playerGameSession.RemoveListener(_player);

                    // Get the opposing player
                    NetworkBackgammonPlayer opposingPlayer = _playerGameSession.GetOpponent(_player);

                    if (opposingPlayer != null)
                    {
                        // Disconnect the player from the game session
                        opposingPlayer.RemoveListener(_playerGameSession);
                        // Disconnect the game session from the player
                        _playerGameSession.RemoveListener(opposingPlayer);
                    }

                    // Halt the game sesssion
                    _playerGameSession.Stop();
                }

                // Remove player from connected player list
                connectedPlayers.Remove(_player);

                // Broadcast the player disconnected event to all registered listeners
                Broadcast(new NetworkBackgammonGameRoomEvent(NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerDisconnected));
            }
        }
        public void OnEventNotification(INetworkBackgammonNotifier sender, INetworkBackgammonEvent e)
        {
            if (sender is NetworkBackgammonPlayer)
            {
                NetworkBackgammonPlayer player = (NetworkBackgammonPlayer)sender;

                if (e is NetworkBackgammonChallengeResponseEvent)
                {
                    NetworkBackgammonChallengeResponseEvent challengeResponseEvent = (NetworkBackgammonChallengeResponseEvent)e;

                    if (challengeSyncList.Keys.Contains(player))
                    {
                        if (challengeSyncList[player] != null)
                        {
                            challengeSyncList[player].ChallengeAccepted = challengeResponseEvent.ChallengeAccepted;

                            try
                            {
                                challengeSyncList[player].ChallengeSemaphore.Release();
                            }
                            catch (SemaphoreFullException ex)
                            {
                                // TODO: If this exception occurs calling Release too many times...
                            }
                        }
                    }
                }
                else if (e is NetworkBackgammonChatEvent)
                {
                    // Pass the message through to the listeners
                    Broadcast((NetworkBackgammonChatEvent)e);
                }
            }
            else if (sender is NetworkBackgammonGameSession)
            {
                NetworkBackgammonGameSession gameSession = (NetworkBackgammonGameSession)sender;

                if (e is NetworkBackgammonGameSessionEvent)
                {
                    NetworkBackgammonGameSessionEvent gameSessionEvent = (NetworkBackgammonGameSessionEvent)e;

                    if (gameSessionEvent.EventType == NetworkBackgammonGameSessionEvent.GameSessionEventType.GameFinished)
                    {
                        bool newQueueItemAdd = true;

                        NetworkBackgammonEventQueueElement newQueueItem = new NetworkBackgammonEventQueueElement(e, sender);

                        lock (newQueueItem)
                        {
                            /*
                             * if (gameSessionsEventQueue.Count > 0)
                             * {
                             *  NetworkBackgammonEventQueueElement lastQueueItem = gameSessionsEventQueue.Last();
                             *  // Avoid adding the same event (from the same sender) twice
                             *  // Reason: Game Room listens to events from all players, i.e. also
                             *  // both players that are in one Game Session. Thus, all events broadcasted
                             *  // by the Game Session arrive here (at the Game Room) twice
                             *  if (gameSessionsEventQueue.Last().Notifier == sender &&
                             *      gameSessionsEventQueue.Last().Event == e)
                             *  {
                             *      newQueueItemAdd = false;
                             *  }
                             * }
                             */

                            if (newQueueItemAdd)
                            {
                                gameSessionsEventQueue.Enqueue(new NetworkBackgammonEventQueueElement(e, sender));

                                gameSessionsSemaphore.Release();
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Challenge an opponent to a game
        /// </summary>
        /// <param name="_challengingPlayer">Challenging backgammon player</param>
        /// <param name="_challengedPlayer">Challenged backgammon player</param>
        /// <returns></returns>
        public bool Challenge(string _challengingPlayerName, string _challengedPlayerName)
        {
            bool retval = false;

            NetworkBackgammonPlayer _challengingPlayer = GetPlayerByName(_challengingPlayerName);
            NetworkBackgammonPlayer _challengedPlayer  = GetPlayerByName(_challengedPlayerName);

            // Check if the players are in the available player game room list
            //if (connectedPlayers.Contains(_challengingPlayer) && connectedPlayers.Contains(_challengedPlayer))
            if (_challengingPlayer != null && _challengedPlayer != null)
            {
                // Check if players are currently free to participate in a game session
                if (!IsPlayerInGameSession(_challengingPlayer) && !IsPlayerInGameSession(_challengedPlayer))
                {
                    Semaphore challengeSemaphore = new Semaphore(0, 1);

                    // Add game challenge data container instance to be used for the (asynchronous) challenge procedure
                    challengeSyncList.Add(_challengedPlayer, new NetworkBackgammonChallengeDataContainer(challengeSemaphore));

                    // Broadcast the player challenge event
                    Broadcast(new NetworkBackgammonChallengeEvent(_challengingPlayerName, _challengedPlayerName));

                    // Wait for response from challenged player (or timeout)
                    if (challengeSemaphore.WaitOne(challengeRequestTimeoutMs))
                    {
                        retval = challengeSyncList[_challengedPlayer].ChallengeAccepted;

                        // Create and start game session if challenge has been accepted by challenged player
                        if (retval)
                        {
                            // Create game session monitor if it doesn't exist yet
                            StartGameSessionMonitor();

                            // Create game session instance
                            NetworkBackgammonGameSession gameSession = new NetworkBackgammonGameSession(_challengingPlayer, _challengedPlayer);

                            // Append to list of game sessions...
                            gameSessions.Add(gameSession);
                            // Start the game...
                            gameSession.Start();

                            // Broadcast the game active event to all registered listeners
                            Broadcast(new NetworkBackgammonGameRoomEvent(NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerPlaying));
                        }

                        challengeSyncList.Remove(_challengedPlayer);

                        // Give the challenging player the challenge response
                        Broadcast(new NetworkBackgammonChallengeResponseEvent(retval, _challengedPlayerName, _challengingPlayerName));
                    }
                    else
                    {
                        challengeSyncList.Remove(_challengedPlayer);

                        retval = false;
                    }
                }
            }

            return(retval);
        }
Beispiel #7
0
        public void OnEventNotification(INetworkBackgammonNotifier sender, INetworkBackgammonEvent e)
        {
            if (InvokeRequired)
            {
                Invoke(new NotifyDelegate(OnEventNotification), new object[] { sender, e });
            }
            else
            {
                buttonAction.Enabled = false;
                buttonAction.Text    = "[No Action]";

                #region Sender: Game Room

                if (sender is NetworkBackgammonRemoteGameRoom)
                {
                    try
                    {
                        if (e is NetworkBackgammonGameRoomEvent)
                        {
                            NetworkBackgammonGameRoomEvent gameRoomEvent = (NetworkBackgammonGameRoomEvent)e;

                            switch (gameRoomEvent.EventType)
                            {
                            case NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerConnected:
                                UpdateConnectedPlayersList();
                                break;

                            case NetworkBackgammonGameRoomEvent.GameRoomEventType.PlayerDisconnected:
                                UpdateConnectedPlayersList();
                                break;
                            }
                        }
                        else if (e is NetworkBackgammonChallengeEvent)
                        {
                            NetworkBackgammonChallengeEvent challengeEvent = (NetworkBackgammonChallengeEvent)e;

                            string challengingPlayer = challengeEvent.ChallengingPlayer;
                            string challengedPlayer  = challengeEvent.ChallengedPlayer;

                            if (challengingPlayer.CompareTo(player.PlayerName) != 0 &&
                                challengedPlayer.CompareTo(player.PlayerName) == 0)
                            {
                                bool challengeResponse = MessageBox.Show(
                                    "Accept game challenge from " + challengeEvent.ChallengingPlayer + "?",
                                    "Game Challenge",
                                    MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Question,
                                    MessageBoxDefaultButton.Button1) == DialogResult.Yes;

                                player.RespondToChallenge(challengeResponse, challengeEvent.ChallengingPlayer);

                                groupBoxGameControls.Enabled = challengeResponse;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        listBoxLog.Items.Add(ex.Message);
                    }
                }

                #endregion

                #region Sender: Game Session

                else if (sender is NetworkBackgammonGameSession)
                {
                    // Filter out broadcasts from our own player
                    if (sender != player)
                    {
                        try
                        {
                            NetworkBackgammonGameSession gameSession = (NetworkBackgammonGameSession)sender;

                            if (e is NetworkBackgammonGameSessionEvent)
                            {
                                // Generate warning if last event has been overwritten
                                // (Currently every event received is supposed to be responded too by means of an
                                //  action (e.g. move, dice roll acknowledge, etc), which resets the last event type to invalid)
                                if (lastGameSessionEventType != null)
                                {
                                    listBoxLog.Items.Add("Warning: Overwriting last event (" + lastGameSessionEventType.ToString() + ") with new event " + e.GetType().ToString() + " (i.e. last event hasn't been responded to by means of an action)");
                                }

                                // Latch the event type
                                lastGameSessionEventType = e.GetType();
                            }

                            #region Actions for initial dice roll

                            if (e is GameSessionInitialDiceRollEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionInitialDiceRollEvent gameSessionInitialDiceRollEvent = (GameSessionInitialDiceRollEvent)e;

                                // if (player.InitialDice != null)
                                if (gameSessionInitialDiceRollEvent.GetDiceForPlayer(player.PlayerName) != null)
                                {
                                    listBoxLog.Items.Add("Initial dice rolled: " + gameSessionInitialDiceRollEvent.GetDiceForPlayer(player.PlayerName).CurrentValue);

                                    buttonAction.Enabled = true;

                                    buttonAction.Text = "Confirm initial dice roll";
                                }
                                else
                                {
                                    listBoxLog.Items.Add("Warning: Event received is " + e.GetType().ToString() + " but dice values are missing");
                                }
                            }

                            #endregion

                            #region Actions for checker update

                            else if (e is GameSessionCheckerUpdatedEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionCheckerUpdatedEvent gameSessionCheckerUpdateEvent = (GameSessionCheckerUpdatedEvent)e;

                                player = gameSessionCheckerUpdateEvent.GetPlayerByName(player.PlayerName);

                                string strDice = "";

                                foreach (NetworkBackgammonDice d in gameSessionCheckerUpdateEvent.DiceRolled)
                                {
                                    strDice += " " + d.CurrentValue;
                                }

                                listBoxLog.Items.Add("Dice: " + strDice);

                                foreach (NetworkBackgammonChecker checker in player.Checkers)
                                {
                                    listBoxCheckers.Items.Add(checker);
                                }
                            }

                            #endregion

                            #region Actions for move expected

                            else if (e is GameSessionMoveExpectedEvent)
                            {
                                GameSessionMoveExpectedEvent gameSessionMoveExpectedEvent = (GameSessionMoveExpectedEvent)e;

                                if (player.PlayerName == gameSessionMoveExpectedEvent.ActivePlayer)
                                {
                                    listBoxLog.Items.Add("I'm the active player, expected to make the next move ...");

                                    groupBoxGameControls.BackColor = Color.DarkGreen;

                                    buttonAction.Enabled = true;

                                    buttonAction.Text = "Make Move";
                                }
                                else
                                {
                                    groupBoxGameControls.BackColor = Color.DarkRed;
                                }
                            }

                            #endregion

                            #region Actions for no (valid) move

                            else if (e is GameSessionNoPossibleMovesEvent)
                            {
                                GameSessionNoPossibleMovesEvent gameSessionNoPossibleMovesEvent = (GameSessionNoPossibleMovesEvent)e;

                                if (player.PlayerName == gameSessionNoPossibleMovesEvent.PlayerName)
                                {
                                    listBoxLog.Items.Add("I'm the active player, but have no (valid) moves ...");

                                    groupBoxGameControls.BackColor = Color.DarkGreen;

                                    buttonAction.Enabled = true;

                                    buttonAction.Text = "Confirm";
                                }
                                else
                                {
                                    groupBoxGameControls.BackColor = Color.DarkRed;
                                }
                            }

                            #endregion

                            #region Actions for player resignation

                            else if (e is GameSessionPlayerResignationEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionPlayerResignationEvent gameSessionPlayerResignationEvent = (GameSessionPlayerResignationEvent)e;

                                listBoxLog.Items.Add("Player " + gameSessionPlayerResignationEvent.ResigningPlayer + " has resigned from current game");

                                listBoxCheckers.Items.Clear();

                                groupBoxGameControls.BackColor = SystemColors.Control;

                                groupBoxGameControls.Enabled = false;
                            }

                            #endregion

                            #region Actions for player won game

                            else if (e is GameSessionPlayerWonEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                GameSessionPlayerWonEvent gameSessionPlayerWonEvent = (GameSessionPlayerWonEvent)e;

                                if (gameSessionPlayerWonEvent.WinningPlayer == player.PlayerName)
                                {
                                    listBoxLog.Items.Add("Yeah!!! I won the game!!!");
                                }
                                else
                                {
                                    listBoxLog.Items.Add("Player " + gameSessionPlayerWonEvent.WinningPlayer + " won the game");
                                }

                                listBoxCheckers.Items.Clear();

                                groupBoxGameControls.BackColor = SystemColors.Control;

                                groupBoxGameControls.Enabled = false;
                            }

                            #endregion

                            else if (e is NetworkBackgammonGameSessionEvent)
                            {
                                listBoxCheckers.Items.Clear();
                                listBoxMoves.Items.Clear();

                                NetworkBackgammonGameSessionEvent gameSessionEvent = (NetworkBackgammonGameSessionEvent)e;

                                switch (gameSessionEvent.EventType)
                                {
                                case NetworkBackgammonGameSessionEvent.GameSessionEventType.GameFinished:
                                {
                                    listBoxLog.Items.Add("Game finished");
                                }
                                break;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            listBoxLog.Items.Add(ex.Message);
                        }
                    }
                }

                #endregion
            }
        }