/// <summary> /// Callback for when the user first connects to the server. /// Sends the player name off to the server. /// Sets the new callback to be for when we receive data. /// </summary> /// <param name="state"></param> private void connectCallbackFunc(Preserved_Socket_State state) { base.BeginInvoke(new MethodInvoker(() => updatePanel(false))); actionCallback handler = receivePlayerFunc; state.callback = handler; string name = playerName.Text + '\n'; Network.Send(state.workSocket, name); }
/// <summary> /// Callback for when the user receieves data from the server. /// Sets initial player cube if we don't have it. /// Otherwise it sets all of the new cubes in the world. /// Asks for more data from the server. /// </summary> /// <param name="state"></param> private void receiveDataFunc(Preserved_Socket_State state) { lock (worldInfo) { state.sb.Append(encoding.GetString(state.buffer, 0, state.bytesRead)); string response = state.sb.ToString(); string lastCube = worldInfo.updateCubes(response); state.sb.Replace(response, lastCube); this.Invalidate(); Network.i_want_more_data(state); } }
/// <summary> /// This handles what happens when the connection with the Server has /// been established. When the Server has connected, the player's name /// is sent to the Server so it can establish a Circle object for the player. /// </summary> /// <param name="obj"></param> private void Contact_Established(Preserved_Socket_State obj) { game_timer.Start(); logger.LogInformation("Contact with Server established!"); obj.on_data_received_handler = Get_Player_Circle; Networking.Send(obj.socket, player_name); connected = true; Client_and_GUI.ActiveForm.KeyDown += new KeyEventHandler(Space_Down); if (!obj.Has_More_Data()) { Networking.await_more_data(obj); // * must "await_more_data" if you want to receive messages. } }
/// <summary> /// This is the event for when the "Connect" button is clicked on the Login GUI. When the button is pressed, /// it attempts to establish a connection with the given Server. /// </summary> /// <param name="o"></param> /// <param name="e"></param> private void Connect_To_Server(object o, EventArgs e) { if (this.server != null && this.server.socket.Connected) { logger.LogInformation("Shutting down the connection"); this.server.socket.Shutdown(System.Net.Sockets.SocketShutdown.Both); return; } logger.LogInformation("Asking the network code to connect to the server."); player_name = player_name_box.Text; if (player_name is "") { player_name = $"{new Random()}"; } server_name = server_address_box?.Text; this.server = Networking.Connect_to_Server(Contact_Established, server_name); }
/// <summary> /// Callback that happens when we receive the player data from the /// server. /// </summary> /// <param name="state"></param> private void receivePlayerFunc(Preserved_Socket_State state) { lock (worldInfo) { actionCallback handler = receiveDataFunc; state.callback = handler; state.sb.Append(encoding.GetString(state.buffer, 0, state.bytesRead)); string response = state.sb.ToString(); Cube playerCube = JsonConvert.DeserializeObject <Cube>(response); playerCubeUid = playerCube.uid; worldInfo.addCube(playerCube); hasPlayerCube = true; this.Invalidate(); Network.i_want_more_data(state); } }
/// <summary> /// This handles the first phase of the connection protocol. The first Circle /// sent by the Server should be the Circle designated to the player. Once it is /// received, it is added to the World's collection of objects. /// </summary> /// <param name="obj"></param> private void Get_Player_Circle(Preserved_Socket_State obj) { obj.on_data_received_handler = Get_World_Information; Circle sent_circle = JsonConvert.DeserializeObject <Circle>(obj.Message); if (sent_circle.GetName.Equals(player_name)) { player_circle = sent_circle; player_id = player_circle.ID; } lock (game_world) { if (!game_world.Contains(player_id)) { game_world.Add(player_id, player_circle); } } Networking.await_more_data(obj); }
/// <summary> /// When a request comes in (from a browser) this method will /// be called by the Networking code. When a full message has been /// read (as defined by an empty line in the overall message) send /// a response based on the request. /// </summary> /// <param name="network_message_state"> provided by the Networking code, contains socket and message</param> private static void RequestFromBrowserHandler(Preserved_Socket_State network_message_state) { Console.WriteLine($"{++counter,4}: {network_message_state.Message}"); try { // by definition if there is a new line, then the request is done if (network_message_state.Message == "\r") { Networking.Send(network_message_state.socket, BuildHTTPResponse()); // the message response told the browser to disconnect, but // if they didn't we will do it. if (network_message_state.socket.Connected) { network_message_state.socket.Shutdown(SocketShutdown.Both); network_message_state.socket.Close(); } } } catch (Exception exception) { Console.WriteLine($"Something went wrong... this is a bad error message. {exception}"); } }
/// <summary> /// Basic connect handler - i.e., a browser has connected! /// </summary> /// <param name="state"> Networking state object created by the Networking Code. Contains the socket.</param> private static void OnClientConnect(Preserved_Socket_State state) { state.on_data_received_handler = RequestFromBrowserHandler; Networking.await_more_data(state); }
/// <summary> /// When a request comes in (from a browser) this method will /// be called by the Networking code. When a full message has been /// read (as defined by an empty line in the overall message) send /// a response based on the request. /// </summary> /// <param name="network_message_state"> provided by the Networking code, contains socket and message</param> private static void RequestFromBrowserHandler(Preserved_Socket_State network_message_state) { Console.WriteLine($"{++counter,4}: {network_message_state.Message}"); try { if (network_message_state.Message.Equals("GET / HTTP/1.1\r")) { string main_page = Build_Main_Page(); Send_And_Close_Connection(network_message_state.socket, main_page); } else if (network_message_state.Message.Equals("GET /highscores HTTP/1.1\r")) { string high_scores = Build_HighScore_Page(); Send_And_Close_Connection(network_message_state.socket, high_scores); } else if (network_message_state.Message.Equals("GET /timeinfirst HTTP/1.1\r")) { string first_place_length = Build_First_Place_Length_Page(); Send_And_Close_Connection(network_message_state.socket, first_place_length); } else if (network_message_state.Message.Contains("scores")) { string split_character = "/"; string[] split_message = Regex.Split(network_message_state.Message, split_character); if (split_message.Length == 4) { // grabs the player name from the network message, minus " HTTP" string name = split_message[2].Substring(0, split_message[2].Length - 5); string sent_player_database = Build_Player_Page(name); Send_And_Close_Connection(network_message_state.socket, sent_player_database); } else if (split_message.Length == 8) { float mass; int rank; long start_time; long end_time; string name = split_message[2]; float.TryParse(split_message[3], out mass); int.TryParse(split_message[4], out rank); long.TryParse(split_message[5], out start_time); long.TryParse(split_message[6].Substring(0, split_message[6].Length - 5), out end_time); long total_time = end_time - start_time; TimeSpan converted_time = TimeSpan.FromMilliseconds(total_time); string time_played = string.Format("{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms", converted_time.Hours, converted_time.Minutes, converted_time.Seconds, converted_time.Milliseconds); // Insert networking message into sql table AgarioDatabase database = new AgarioDatabase(); database.Insert_Player_Data(name, mass, rank, time_played); database.Insert_HighScore_Data(name, mass, rank, time_played); string sent_player_database = Build_Confirmation_Page(name); Send_And_Close_Connection(network_message_state.socket, sent_player_database); } } } catch (Exception exception) { Console.WriteLine($"Something went wrong... this is a bad error message. {exception}"); } }
/// <summary> /// This handles the second phase of the connection protocol. After the player's /// Circle has been received, the rest should be all the other /// game objects (food, other players, heartbeats). /// </summary> /// <param name="obj"></param> private void Get_World_Information(Preserved_Socket_State obj) { try { Calculate_Movement(out movement_X, out movement_Y); //Calculates the player's movement based on the mouse's position. Networking.Send(obj.socket, $"(move,{movement_X},{movement_Y})"); //Sends the movement to the Server. logger.LogDebug($"Sent movement: {movement_X} {movement_Y}"); world_circle = JsonConvert.DeserializeObject <Circle>(obj.Message); if (world_circle.Type.ToString().Equals("heartbeat")) { this.Invalidate(); } lock (game_world) { if (!game_world.Contains(world_circle.ID)) { game_world.Add(world_circle.ID, world_circle); } else { if (!world_circle.Location.Equals(game_world[world_circle.ID])) //If the player location has changed from what's already stored { game_world.Remove(world_circle.ID); //Remove the old entry game_world.Add(world_circle.ID, world_circle); //And add in the new one (which is the same "object" via the ID, but in a different location) } if (world_circle.GetMass <= 0 && world_circle.Type.ToString().Equals("food")) { game_world.Remove(world_circle.ID); //Remove the old entry } } } } catch (Exception e) { logger.LogError($"Json convert error."); } try { Networking.await_more_data(obj); } catch (SocketException e) { // If a player has died, stop drawing the game scene and display game over screen logger.LogInformation($"{player_circle.GetName} has been killed."); connected = false; isDead = true; game_timer.Stop(); elapsed_time = game_timer.ElapsedMilliseconds; // We are converting the time in milliseconds into a string of hour:min:seconds format to be added into the database TimeSpan converted_time = TimeSpan.FromMilliseconds(elapsed_time); string time_played = string.Format("{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms", converted_time.Hours, converted_time.Minutes, converted_time.Seconds, converted_time.Milliseconds); database.Insert_Player_Data(player_name, player_circle.GetMass, rank + 1, time_played); database.Insert_HighScore_Data(player_name, player_circle.GetMass, rank + 1, time_played); } // If the user wishes to split, send the coordinates for split if (can_split) { float destination_X = player_circle.Location.X + 100; float destination_Y = player_circle.Location.Y + 100; can_split = false; Networking.Send(obj.socket, $"split,{destination_X},{destination_Y}"); } obj.on_data_received_handler = Get_World_Information; }