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)); } }
public void Received(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.YouWin) { context.SetState(NetworkStateId.WaitingForBoard); _prompter.PromptYouWin(); _prompter.PromptWaitingForBoard(); return; } context.SetState(NetworkStateId.TheirTurn); switch (message.TypeId) { case MessageTypeId.Hit: _prompter.PromptYouHit(); break; case MessageTypeId.Sunk: _prompter.PromptYouSunk(); break; case MessageTypeId.Miss: _prompter.PromptYouMissed(); break; } _prompter.PromptTheirTurn(); }
public static async Task Main(string[] args) { // Get the IP address to bind to as a command line arguement or default // to 127.0.0.1. var userSuppliedIp = args.Length < 1 ? "127.0.0.1" : args[0]; // Require the IP address be supplied as a command line argument. var localIp = IPAddress.Parse(userSuppliedIp); var localEndPoint = new IPEndPoint(localIp, BspConstants.DefaultPort); // Begin listening for clients attempting to discover the server IP _ = StartUdpListing(localEndPoint); // Create objects used for every connection. var generalLogger = new Logger(Console.Out); var unparser = new MessageUnparser(); var listener = new BspListener(generalLogger); var gameTypeRepo = CreateGameTypeRepository(); var userRepo = CreateUserRepository(); var matchMaker = new MatchMaker(); // The body of this foreach loop is a callback. This body will run for // connection our listener accepts. Here we create objects specific for // each connection. await foreach (var socket in listener.StartListeningAsync(localEndPoint)) { // Create a logger that will log with the client's EndPoint. var logger = new EndPointLogger(Console.Out, socket.RemoteEndPoint); // Create a disconnecter that can clean up a connection. var disconnecter = new ServerDisconnecter(logger, socket, userRepo, matchMaker); // Create a sender for sending messages to the client. var senderHandler = new MultiMessageHandler(); var sender = new BspSender(socket, logger, unparser, senderHandler); // Create a container for this connections state. var container = new ServerNetworkStateContainer(sender, disconnecter, gameTypeRepo, userRepo, matchMaker); // Create a context for our state machine. var context = new NetworkStateContext(container, disconnecter); // Register incoming messages with this context. senderHandler.AddHandler(LoggingMessageHandler.ForSending(logger)); senderHandler.AddHandler(new SentMessageHandler(context)); // Register outgoing messages with this context. var receiverHandler = new MultiMessageHandler(); receiverHandler.AddHandler(LoggingMessageHandler.ForReceiving(logger)); receiverHandler.AddHandler(new ReceiveMessageHandler(context)); // Create a parser for this connection var parser = new MessageParser(receiverHandler, gameTypeRepo); // Begin asynchronously receiving messages var receiver = new BspReceiver(socket, disconnecter, parser, logger); _ = receiver.StartReceivingAsync(); } }
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(); }
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)); }
public void Sent(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.AssignRed) { context.SetState(NetworkStateId.MyTurn); return; } context.SetState(NetworkStateId.TheirTurn); }
public void Sent(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.TheirGuess) { context.SetState(NetworkStateId.MyTurn); return; } context.SetState(NetworkStateId.WaitingForBoard); }
public void Sent(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.AcceptLogOn) { context.SetState(NetworkStateId.WaitingForBoard); } else { context.SetState(NetworkStateId.NotConnected); } }
public void Received(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.AssignRed) { context.SetState(NetworkStateId.MyTurn); _prompter.PromptAssignRed(); _prompter.PromptMyTurn(); return; } context.SetState(NetworkStateId.TheirTurn); _prompter.PromptAssignBlue(); _prompter.PromptTheirTurn(); }
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)); } } }
public void Sent(NetworkStateContext context, IMessage message) { switch (message.TypeId) { case MessageTypeId.AcceptBoard: context.SetState(NetworkStateId.WaitingForGame); return; case MessageTypeId.RejectBoard: context.SetState(NetworkStateId.WaitingForBoard); return; default: throw new ArgumentException(); } }
public void Received(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.YouLose) { context.SetState(NetworkStateId.WaitingForBoard); _prompter.PromptYouLose(); _prompter.PromptWaitingForBoard(); return; } context.SetState(NetworkStateId.MyTurn); var guess = (TheirGuessMessage)message; _prompter.PromptTheirGuess(guess.Position); _prompter.PromptMyTurn(); }
public void Received(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.AcceptLogOn) { context.SetState(NetworkStateId.WaitingForBoard); _prompter.PromptSuccessfulLogOn(); _prompter.PromptWaitingForBoard(); return; } context.SetState(NetworkStateId.NotConnected); var version = ((RejectLogOnMessage)message).Version; _prompter.PromptFailedLogOn(version); _prompter.PromptLogOn(); }
public void Sent(NetworkStateContext context, IMessage message) { switch (message.TypeId) { case MessageTypeId.AcceptGame: context.SetState(NetworkStateId.InitialGame); return; case MessageTypeId.RejectGame: context.SetState(NetworkStateId.WaitingForBoard); return; case MessageTypeId.GameExpired: context.SetState(NetworkStateId.WaitingForBoard); return; } }
public void Received(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.AcceptBoard) { context.SetState(NetworkStateId.WaitingForGame); _prompter.PromptValidBoard(); return; } if (message.TypeId == MessageTypeId.RejectBoard) { context.SetState(NetworkStateId.WaitingForBoard); _prompter.PromptInvalidBoard(); _prompter.PromptWaitingForBoard(); } // Ignore GameType }
public void Received(NetworkStateContext context, IMessage message) { if (message.TypeId == MessageTypeId.AcceptGame) { context.SetState(NetworkStateId.InitialGame); _prompter.PromptOpponentAccepted(); return; } if (message.TypeId == MessageTypeId.RejectGame) { context.SetState(NetworkStateId.WaitingForBoard); _prompter.PromptOpponentRejected(); _prompter.PromptWaitingForBoard(); return; } context.SetState(NetworkStateId.WaitingForBoard); _prompter.PromptMatchExpired(); _prompter.PromptWaitingForBoard(); }
public void Received(NetworkStateContext context, IMessage message) { context.SetState(NetworkStateId.FoundGame); _prompter.PromptFoundGame(); }
public void Received(NetworkStateContext context, IMessage message) { // The only valid receive is RecallBoard context.SetState(NetworkStateId.WaitingForBoard); }
public void Received(NetworkStateContext context, IMessage message) { // There are no valid messages for the server to receive in this state. }
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)); }
public void Sent(NetworkStateContext context, IMessage message) { context.SetState(NetworkStateId.PendingBoard); }
public void Received(NetworkStateContext context, IMessage message) { // This is left intentionally blank. }
public void Sent(NetworkStateContext context, IMessage message) { // There are no valid messages for the server to send in this state. }
public void Sent(NetworkStateContext context, IMessage message) { context.SetState(NetworkStateId.Waiting); }
public ReceiveMessageHandler(NetworkStateContext context) { _context = context; }
public static async Task Main(string[] args) { // Create a logger var logger = new Logger(Console.Out); // If the user did not supply an IP or hostname, attempt to // discover a server on the same subnet. IPEndPoint endPoint; if (args.Length > 0) { if (IPAddress.TryParse(args[0], out var ip)) { endPoint = new IPEndPoint(ip, BspConstants.DefaultPort); } else { // Maybe the user supplied a hostname not an IP var addresses = Dns.GetHostAddresses(args[0]); if (addresses.Length < 1) { Console.WriteLine("Could not find hostname."); return; } endPoint = new IPEndPoint(addresses.Last(), BspConstants.DefaultPort); } } else { logger.LogInfo("Attempting to discover server end point..."); endPoint = await DiscoverServerEndPoint(BspConstants.DefaultPort); } // Attempt to connect to the server. var unparser = new MessageUnparser(); var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); try { logger.LogInfo($"Attempting to connect to {endPoint}"); socket.Connect(endPoint); } catch (SocketException) { logger.LogError($"Failed to connect to {endPoint}"); } // Create a disconnecter that can clean up a connection. var disconnecter = new ClientDisconnecter(logger, socket); // Create a sender for sending to the server. var senderHandler = new MultiMessageHandler(); var sender = new BspSender(socket, logger, unparser, senderHandler); // Create a prompter to handle user interaction. var prompter = new Prompter(sender); // Create a state machine var container = new ClientNetworkStateContainer(prompter); var context = new NetworkStateContext(container, disconnecter); // Register sending messages with our state machine. senderHandler.AddHandler(LoggingMessageHandler.ForSending(logger)); senderHandler.AddHandler(new SentMessageHandler(context)); // Register receiving messages with our state machine. var receiverHandler = new MultiMessageHandler(); receiverHandler.AddHandler(LoggingMessageHandler.ForReceiving(logger)); receiverHandler.AddHandler(new ReceiveMessageHandler(context)); // Create a parser for our connection with the server var parser = new MessageParser(receiverHandler, new GameTypeRepository()); var receiver = new BspReceiver(socket, disconnecter, parser, logger); // Begin receive messages and start the prompt. var receivingTask = receiver.StartReceivingAsync(); prompter.PromptLogOn(); await receivingTask; }
public SentMessageHandler(NetworkStateContext context) { _context = context; }