示例#1
0
        public void Received(NetworkStateContext context, IMessage message)
        {
            // Change state to PendingLogOn so if the client sends any messages
            // in the meantime, that state will take over.
            context.SetState(NetworkStateId.PendingLogOn);

            var attempt = (LogOnMessage)message;

            if (attempt.Version != BspConstants.Version)
            {
                _sender.Send(new RejectLogOnMessage(BspConstants.Version));
                return;
            }

            if (!_userRepo.TryLogIn(attempt.Username, attempt.Password, _sender))
            {
                _sender.Send(new RejectLogOnMessage(BspConstants.Version));
                return;
            }

            // Client has successfully logged in, so we update our record.
            _state.Username = attempt.Username;

            // Let the user know they were successful.
            _sender.Send(new BasicMessage(MessageTypeId.AcceptLogOn));

            // Send them the game types.
            foreach (var gameType in _gameTypeRepo.GetAll())
            {
                _sender.Send(new GameTypeMessage(gameType));
            }
        }
示例#2
0
        public void PromptLogOn()
        {
            Write("Username: "******"Password: ");
            var password = Console.ReadLine();

            _sender.Send(new LogOnMessage(BspConstants.Version, username, password));
        }
示例#3
0
        public void Received(NetworkStateContext context, IMessage message)
        {
            // Get the opponents connection.
            if (!_userRepo.TryGetSender(_state.Match.Opponent.Username, out var opponent))
            {
                // Somehow the opponent is not logged in.
                _disconnecter.Disconnect();
                return;
            }

            _state.CancelMatchTimer();

            // The player is rejecting the game.
            if (message.TypeId == MessageTypeId.RejectGame)
            {
                // Mark the player as accepting the game.
                _state.Match.Player.AcceptedGame = MatchResponse.Reject;

                // Update our state.
                context.SetState(NetworkStateId.WaitingForBoard);

                // Let the opponent know that the player has rejected the game.
                opponent.Send(new BasicMessage(MessageTypeId.RejectGame));
                return;
            }

            // The only remaining valid message is AcceptGame. So mark the player as accept.
            _state.Match.Player.AcceptedGame = MatchResponse.Accept;

            // If the opponent has also sent AcceptGame, we let both know to start the game.
            if (_state.Match.Opponent.AcceptedGame == MatchResponse.Accept)
            {
                // Let both know that the game has been accepted.
                _sender.Send(new BasicMessage(MessageTypeId.AcceptGame));
                opponent.Send(new BasicMessage(MessageTypeId.AcceptGame));

                // Notify who goes first
                if (_state.Match.PlayerGoesFirst)
                {
                    _sender.Send(new BasicMessage(MessageTypeId.AssignRed));
                    opponent.Send(new BasicMessage(MessageTypeId.AssignBlue));
                }
                else
                {
                    _sender.Send(new BasicMessage(MessageTypeId.AssignBlue));
                    opponent.Send(new BasicMessage(MessageTypeId.AssignRed));
                }
            }
        }
示例#4
0
        public void Sent(NetworkStateContext context, IMessage message)
        {
            // The only valid send is FoundGame
            context.SetState(NetworkStateId.FoundGame);

            // Get the opponents connection.
            if (!_userRepo.TryGetSender(_state.Match.Opponent.Username, out var opponent))
            {
                // Somehow the opponent is not logged in.
                _disconnecter.Disconnect();
                return;
            }

            _state.SetMatchTimeoutCallback((s, e) =>
            {
                // If the opponent has responded already, send a RejectGame to them.
                if (_state.Match.Opponent.AcceptedGame != MatchResponse.None)
                {
                    opponent.Send(new BasicMessage(MessageTypeId.RejectGame));
                }

                _sender.Send(new BasicMessage(MessageTypeId.GameExpired));
            });

            _state.StartMatchTimer();
        }
示例#5
0
        public void Received(NetworkStateContext context, IMessage message)
        {
            // Only valid receive is MyGuess
            context.SetState(NetworkStateId.Waiting);

            var guess       = ((MyGuessMessage)message).Position;
            var guessResult = _state.Match.Opponent.Board.Guess(guess);

            var id = guessResult switch
            {
                GuessResult.Miss => MessageTypeId.Miss,
                GuessResult.Hit => MessageTypeId.Hit,
                GuessResult.Sunk => MessageTypeId.Sunk,
                GuessResult.Win => MessageTypeId.YouWin,
                _ => throw new ArgumentOutOfRangeException()
            };

            _sender.Send(new BasicMessage(id));

            // Get the opponents connection.
            if (!_userRepo.TryGetSender(_state.Match.Opponent.Username, out var opponent))
            {
                // Somehow the opponent is not logged in.
                _disconnecter.Disconnect();
                return;
            }

            if (id == MessageTypeId.YouWin)
            {
                opponent.Send(new YouLoseMessage(guess));
                return;
            }

            opponent.Send(new TheirGuessMessage(guess));
        }
示例#6
0
        public void Received(NetworkStateContext context, IMessage message)
        {
            context.SetState(NetworkStateId.PendingBoard);

            var submission = (SubmitBoardMessage)message;
            var placements = submission.ShipPlacements;

            var isValidGameType = _gameTypeRepo.TryGet(submission.GameTypeId, out var gameType);

            if (!isValidGameType)
            {
                SendRejection(RejectBoardErrorId.UnsupportedGameType);
                return;
            }

            if (placements.Count != gameType.ShipLengths.Count)
            {
                SendRejection(RejectBoardErrorId.WrongShips);
                return;
            }

            var board = new Board(gameType);

            for (var i = 0; i < placements.Count; i++)
            {
                if (board.IsOutOfBounds(placements[i], i))
                {
                    SendRejection(RejectBoardErrorId.OutOfBounds);
                    return;
                }

                if (board.IsOverlapping(placements[i], i))
                {
                    SendRejection(RejectBoardErrorId.ShipOverlap);
                    return;
                }

                if (!board.TryPlace(placements[i], i))
                {
                    // This shouldn't happen because we just checked the error
                    // conditions. If this somehow happens, we want to crash the
                    // server.
                    throw new Exception();
                }
            }

            _sender.Send(new BasicMessage(MessageTypeId.AcceptBoard));

            var userBoard = new UserBoard(_state.Username, board);
            var match     = _matchMaker.FindMatchAsync(userBoard).GetAwaiter().GetResult();

            if (match == null)
            {
                // This could happen if the server somehow ends up in an
                // inconsistent state where it can't add the user to match making.
                throw new Exception();
            }

            _state.Match = match;
            _sender.Send(new BasicMessage(MessageTypeId.FoundGame));
        }