/// <summary> /// This method acts as the callback from Accepting_A_New_Client method. It takes in the state object and updates the callback to be /// RecievePlayerName and then it requests more data from the server to actually recieve the player name. /// </summary> /// <param name="state">The state obj of the about to about to be added player.</param> static void HandleNewClient(PreservedState state) { // Update the call back and request more data, aka the player name. state.callBack = ReceivePlayerName; Network.i_want_more_data(state); }
/// <summary> /// Called when information is recieved from the server. /// </summary> /// <param name="State"></param> void Receive(PreservedState State) { // Initial receive if (GameState == 0) { if (State.sb.ToString() != "Could not connect!") { // Send player name Network.Send(State.TheSocket, NameTextBox.Text); this.Invoke(new MethodInvoker(delegate { // Update form views LogInPanel.Visible = false; })); GameState = 1; } else { MessageBox.Show("Could not connect to server!"); State.sb.Clear(); } } else // Receive data { string[] SplitString = null; lock (TheState.sb) { // Split String SplitString = State.sb.ToString().Split('\n'); State.sb.Clear(); } // Go through every split string item. foreach (string Item in SplitString) { // See if the item is a complete string if (Item.StartsWith("{") && Item.EndsWith("}")) { lock (TheWorld) { TheWorld.makeCube(Item); } } else // The item is not complete. { if (!Item.StartsWith("\0\0\0")) { // Append the incomplete item to the string builder. State.sb.Append(Item); } } } // Get more data. Network.i_want_more_data(State); } }
/// <summary> /// Sends a web browser an html page saying their request could not be understood, and gives valid options for a /// proper request. /// <param name="state">The state obj containing the callback to end the socket.</param> /// </summary> private static void SendErrorMessage(PreservedState state) { // Generate the help message and some useful information for correct places to go. string msgToBrowser = "<h1>Whoops! There was an error...</h1><br><h2>The address you entered doesn't exist, try entering a address such as the following:</h2><br><h3>To see statistics for all games : /scores</h3>" + "<h3>To see all games by a particular player (e.g. Joe) : /games?player=Joe</h3><h3>To see results for a particular session (e.g. Session 4) : /eaten?id=4</h3>"; // Send the information to the webpage and close the socket. Network.Send(state.socket, HttpResponseHeader); Network.Send(state.socket, msgToBrowser, (Object) => { Console.WriteLine("Sent HTML"); state.socket.Close(); return; }); }
/// <summary> /// Called when a key is entered in a textbox. If the Enter key, attempts to connect to server. /// </summary> private void checkKeyPress(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { /// Player entered data for Player Name and Server if (!PlayerNameTextBox.Text.Equals("") && !HostNameTextBox.Text.Equals("")) { PlayerName = PlayerNameTextBox.Text; state = Network.Connect_to_Server(() => InitialConnection(), HostNameTextBox.Text); } } }
/// <summary> /// Creates the game world and establishes a connection with the server. /// </summary> void StartConnect() { // Make new world TheWorld = new World(1000, 1000); // Delagate called when connection is made ReceiveDelegate ReceiveCallBack = new ReceiveDelegate(Receive); Socket NewSocket = Network.Connect_to_Server(ReceiveCallBack, ServerTextBox.Text); TheState = new Network_Controller.PreservedState(NewSocket, ReceiveCallBack); }
/// <summary> /// Constructor for AgCubio's GUI. Initializes World and Cube. /// DoubleBuffered is set to true to avoid flickering. /// The size of the Window is set to World's default. /// </summary> public GameForm(PreservedState state, string playerName) { InitializeComponent(); world = new World(); this.state = state; PlayerName = playerName; Size = new Size(world.Width + STATS_WIDTH, world.Height); // todo only want actual game part of display to be that size statsRect = new Rectangle(Size.Width - STATS_WIDTH, 0, STATS_WIDTH, Size.Height); cubeNamesFont = new Font("Times New Roman", 14); infoContainerFont = new Font("Times New Roman", 11, FontStyle.Bold); // Send off playerName, wait for data to come back state.callback = () => WantMoreData(); Network.Send(state, PlayerName + "\n"); WantMoreData(); }
/// <summary> /// Send a web brower and html page stating all the current game statistics of all games ever played. /// <param name="state">The state obj containing the callback to end the socket.</param> /// </summary> private static void SendScores(PreservedState state) { // Begin generating the information for the html page. String html = "<h1>Scores</h1><table border = 1><tr><td><b>Player</b></td><td><b>Max Mass</b></td><td><b>Rank</b></td><td><b>Cubes Eaten</b></td><td><b>Time Alive (MM:SS)</b></td></tr>"; // Access our database using (MySqlConnection conn = new MySqlConnection(DbConnectionString)) { try { conn.Open(); MySqlCommand command = conn.CreateCommand(); // Generate teh command of what information we want from the database. command.CommandText = "select Name, Maximum_Mass, Rank, Number_Of_Cubes_Eaten, Lifespan from Player_Games"; // Retrive the information from the database and attach it to the string going to the web browser. using (MySqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { html += "<tr><td><a href = \"http://localhost:11100/games?player=" + reader["Name"] + "\">" + reader["Name"] + "</a>" + "</td><td>" + reader["Maximum_Mass"] + "</td><td>" + reader["Rank"] + "</td><td>" + reader["Number_Of_Cubes_Eaten"] + "</td><td>" + ToDateFormat(reader["Lifespan"].ToString()) + "</td></tr>"; } html += "</table>"; } } // Send the error html page if there is an issue. catch (Exception e) { SendErrorMessage(state); } } // Send the information to the webpage and close the socket. Network.Send(state.socket, HttpResponseHeader); Network.Send(state.socket, html, (Object) => { Console.WriteLine("Sent HTML"); state.socket.Close(); return; }); }
/// <summary> /// Responds to web requests asking for information about historical games, player stats, etc. /// Valid url requests include: "/scores", "games?player=Jack", and "eaten?id=22" where Jack could be /// any name, and 22 could be any number. If the request doesn't follow this format, or if the name or /// id doesn't exist in the database, we respond with an error page /// </summary> private static void HandleWebRequest(PreservedState state) { if (state.strBuilder == null || state.strBuilder.ToString() == "") { state.socket.Close(); return; } String request = state.strBuilder.ToString(); // Pull out just the query from all the info we get from the request // E.g. "GET /games?player=Joe HTTP/1.1..." --> "games?player=Joe" String temp = request.Substring(request.IndexOf('/') + 1); String urlQuery = temp.Substring(0, temp.IndexOf('/') - 5); // Depending on the query (scores, games?player=..., or eaten?id=...), we call the corresponding helper method // that gets info from our DB and responds to the browser if (urlQuery == "scores") { SendScores(state); } // if the query is of the form "games?player=..." else if (urlQuery[0] == 'g') { SendGamesByPlayer(state, urlQuery); } else if (urlQuery[0] == 'e') { SendEatenCubes(state, urlQuery); } else { SendErrorMessage(state); } }
/// <summary> /// When called form TitleForm, switches to a running GameForm. /// </summary> public void startGameForm(PreservedState state, string playerName) { CurrentForm = new GameForm(state, playerName); }
/// <summary> /// Called whenever we receive a move or split request from a client. /// </summary> /// <param name="state">The state object of aplayer, it contains its socket, callback and str builder.</param> static void HandleClientGameRequests(PreservedState state) { // Declare these variable to add in the decoding of the string from the network. String requests; String[] requestArray; int team_id; String command; // Find out what the client's message is requests = state.strBuilder.ToString(); // Pull out and process the first valid request from the network request string. String request; // Ensure the the request is in a valid format to be processed. if (requests[0] == '(') { request = requests.Substring(1, requests.IndexOf('\n') - 2); } // If it is a partial message, look at the next request. else { String temp = requests.Substring(requests.IndexOf('\n') + 1); if (temp.Length > 0) { request = temp.Substring(1, temp.IndexOf('\n') - 2); } else { return; } } // Clear the remaining duplicate requests. state.strBuilder.Clear(); // Get the team_id of the player from the ClientSockets Set. team_id = ClientSockets[state.socket]; // Split of the request to process all its individual peices. requestArray = request.Split(','); // Pull out the main command of the request - move or split command = requestArray[0]; // Try and parse the request into the desired double destination values. try { double destX = Convert.ToDouble(requestArray[1].Trim()); double destY = Convert.ToDouble(requestArray[2].Trim()); lock (world) { if (command == "move") { world.MovePlayer(destX, destY, world.Teams[team_id]); } else // command == "split" { world.Split(destX, destY, team_id); lock (mergeTimerLocker) { StartMergeTimer(team_id); } } } } catch (Exception e) { Console.WriteLine("Bad Data: " + request); } // Continue listening for more requests Network.i_want_more_data(state); }
/// <summary> /// A Callback that's called when a new client connects. /// Gets the client's desired player name, sends the client /// their player and the world, and then starts listening /// for move and split requests. /// </summary> /// <param name="state">The state object of the newly added player, it contains its socket, callback and str builder.</param> static void ReceivePlayerName(PreservedState state) { // Pull the player name from the state obj str builder and then clear it. String playerName = state.strBuilder.ToString(); state.strBuilder.Clear(); // Remove the \n from the end of the player name. playerName = playerName.Substring(0, playerName.Length - 1); // Declare team id and player cube out here so it can be used in all the locks. int team_id; Cube playerCube; // Lock the world in order to generate information to build the player cube. lock (world) { // Create the player's cube atributes Point playerXY = world.GetPlayerSpawnLoc(); int argb_color = world.SetCubeColor(); double mass = world.INITIAL_PLAYER_MASS; int playerUid = world.GetNextUID(); team_id = playerUid; // Generate the player cube and add it to the world, new players list, and teams list. playerCube = new Cube(playerXY.X, playerXY.Y, argb_color, playerUid, team_id, false, playerName, mass); world.AddOrUpdateCube(playerCube); // Create a team for the player world.Teams.Add(team_id, new List <Cube>() { playerCube }); // Start tracking the player's team's stats PlayerSessionStats session = new PlayerSessionStats(); session.MaximumMass = world.INITIAL_PLAYER_MASS; session.CurrentMass = world.INITIAL_PLAYER_MASS; world.TeamStatistics.Add(team_id, session); } // Lock the client sockets set inorder to add the newly created players socket to it. lock (clientSocketsLocker) { ClientSockets.Add(state.socket, team_id); } // Serialize the player cube to send it to the client. String playerCubeStr = JsonConvert.SerializeObject(playerCube) + "\n"; // Send player their cube Network.Send(state.socket, playerCubeStr); // Update the callback in order to handle more players potentially adding. state.callBack = HandleClientGameRequests; // Since there are now players in the game, set this to false so updates can happen. noPlayersJoined = false; // Send player the current state of the world lock (world) { StringBuilder worldCubes = new StringBuilder(); foreach (Cube cube in world.Cubes) { worldCubes.Append(JsonConvert.SerializeObject(cube) + '\n'); } Network.Send(state.socket, worldCubes.ToString()); } // Request more data from the server. Network.i_want_more_data(state); }
/// <summary> /// /// /// Send a web brower and html page stating all the game statistics of a certain game session. /// <param name="state">The state obj containing the callback to end the socket.</param> /// </summary> private static void SendEatenCubes(PreservedState state, String req) { // The game session id requested by the browser string id = ""; // Make sure url has valid format, and pull out the id try { if (req.Substring(0, 9) != "eaten?id=") { SendErrorMessage(state); return; } id = req.Substring(req.IndexOf('=') + 1); } // If there is an error send the error html page to the browser catch (Exception e) { SendErrorMessage(state); return; } // begin generating the string to be sent to the web browser. String html = "<h1>Cubes Eaten During Games Session " + id + "</h1>"; html += "<table border = 1><tr><td><b>Name</b></td><td><b>Players Eaten</b></td><td><b>Max Mass</b></td><td><b>Rank</b></td><td><b>Cubes Eaten</b></td><td><b>Players Eaten</b></td><td><b>Time Alive (mm:ss)</b></td><td><b>Time Of Death</b></td></tr>"; String namesOfEatenPlayers = ""; // Begin requesting information from the database by opening the connection. using (MySqlConnection conn = new MySqlConnection(DbConnectionString)) { try { conn.Open(); MySqlCommand command = conn.CreateCommand(); // First, get the names of players eaten, if any exist command.CommandText = "SELECT Players_Eaten FROM Names_Of_Players_Eaten WHERE Names_Of_Players_Eaten.Session_ID = " + id; // Retrive all the eaten players. using (MySqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { namesOfEatenPlayers += reader["Players_Eaten"]; } } // Then, get all the rest of the info for the session from the main table command.CommandText = "SELECT Name, Maximum_Mass, Rank, Number_Of_Cubes_Eaten, Number_Of_Player_Cubes_Eaten, Lifespan, Time_Of_Death FROM Player_Games WHERE Player_Games.ID = " + id; using (MySqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { html += "<tr><td>" + reader["Name"] + "</td><td>" + namesOfEatenPlayers + "</td><td>" + reader["Maximum_Mass"] + "</td><td>" + reader["Rank"] + "</td><td>" + reader["Number_Of_Cubes_Eaten"] + "</td><td>" + reader["Number_Of_Player_Cubes_Eaten"] + "</td><td>" + ToDateFormat(reader["Lifespan"].ToString()) + "</td><td>" + reader["Time_Of_Death"] + "</td></tr>"; } html += "</table>"; } } // If there is an error send the error html page to the browser catch (Exception e) { SendErrorMessage(state); return; } } // Send the information to the webpage and close the socket. Network.Send(state.socket, HttpResponseHeader); Network.Send(state.socket, html, (Object) => { Console.WriteLine("Sent HTML"); state.socket.Close(); return; }); }
/// <summary> /// /// Send a web brower and html page stating all the game statistics of a certain player for all games they have played. /// <param name="state">The state obj containing the callback to end the socket.</param> /// </summary> private static void SendGamesByPlayer(PreservedState state, String req) { try { // Retrive the palyer name from the request of whose information we need to pull. If it doesn't exist send an error message. if (req.Substring(0, 13) != "games?player=") { SendErrorMessage(state); return; } // Retrieve the player name and begin generating the string to be sent to the web browser. string player = req.Substring(req.IndexOf('=') + 1); String html = "<h1>Games for " + player + "</h1>"; html += "<table border = 1><tr><td><b>Max Mass</b></td><td><b>Rank</b></td><td><b>Cubes Eaten</b></td><td><b>Players Eaten</b></td><td><b>Time Alive</b></td><td><b>Time Of Death</b></td></tr>"; // Access our database using (MySqlConnection conn = new MySqlConnection(DbConnectionString)) { try { conn.Open(); MySqlCommand command = conn.CreateCommand(); // Generate the command for the desired information we seek from the database. command.CommandText = "select Maximum_Mass, Rank, Number_Of_Cubes_Eaten, Number_Of_Player_Cubes_Eaten, Lifespan, Time_Of_Death from Player_Games where Name = \"" + player + "\""; // Retrieve that inforamtion from the database using (MySqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { html += "<tr><td>" + reader["Maximum_Mass"] + "</td><td>" + reader["Rank"] + "</td><td>" + reader["Number_Of_Cubes_Eaten"] + "</td><td>" + reader["Number_Of_Player_Cubes_Eaten"] + "</td><td>" + ToDateFormat(reader["Lifespan"].ToString()) + "</td><td>" + reader["Time_Of_Death"] + "</td></tr>"; } html += "</table><br><a href = \"http://localhost:11100/scores\">" + "Go To All Scores" + "</a>"; } } // If there is an error send the error html page to the browser catch (Exception e) { SendErrorMessage(state); return; } } // Send the information to the webpage and close the socket. Network.Send(state.socket, HttpResponseHeader); Network.Send(state.socket, html, (Object) => { Console.WriteLine("Sent HTML"); state.socket.Close(); return; }); } // If there is an error send the error html page to the browser catch (Exception e) { SendErrorMessage(state); } }
/// <summary> /// Uses AgCubio's Network class to begin receiving the web request. Changes the /// callback fcn of the state object so that HandleWebRequest will be called to process /// the request info. /// </summary> static void GetWebRequest(PreservedState state) { state.callBack = HandleWebRequest; Network.i_want_more_data(state); }
public static void Main(string[] args) { Console.WriteLine("Begin Connect"); state = Network.Connect_to_Server(() => rightAfterConnected(), "localhost"); Console.Read(); }