/// <summary> /// Used to continually recieve data, after everything has been loaded in and drawn initially. /// </summary> /// <param name="state"></param> private void ReceiveWorld(SocketState state) { //If the conncetion was lost if (state.getID() == -1 || state.theSocket == null) { MessageBox.Show("Connection with host was lost.", "Connection Failure", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign); this.Invoke((Action)(() => { NameTextBox.Enabled = true; ServerIPTextBox.Enabled = true; ConnectButton.Enabled = true; })); return; } //save the string to read in our data string message = state.sb.ToString(); SnakeUtilities.Snake newSnake = null; SnakeUtilities.Food newFood = null; bool worldChange = false; string jsObj = null; //Used to seperate each line into our message array. string[] remove = { "\n" }; try { // Console.WriteLine(state.sb.ToString()); //Split the message in the sb, and deserialize the json objects. string[] theMsg = message.Split(remove, StringSplitOptions.RemoveEmptyEntries); //used to determine how much we should read. int totalMsg = theMsg.Length; //If the end of the message is not complete, we do not want to process it yet. if (state.sb.ToString()[state.sb.Length - 1] != '\n') { totalMsg--; } //Loop through each obj in the message until complete. for (int iter = 0; iter < totalMsg; iter++) { jsObj = theMsg[iter]; //Console.WriteLine(jsObj); //If the message is contained in braces, it is a valid Json if (jsObj[0] == '{' && jsObj[jsObj.Length - 1] == '}') { Console.WriteLine("JSON:" + jsObj); //Parse the message and check for the attributes JObject findAttr = JObject.Parse(jsObj); JToken verts = findAttr["vertices"]; JToken foodloc = findAttr["loc"]; JToken removesnake = findAttr["rem"]; //Check if msg was a vertice or not if (verts != null) { newSnake = JsonConvert.DeserializeObject <SnakeUtilities.Snake>(theMsg[iter]); // Console.WriteLine(theMsg[iter]); } //Check if msg was a food or not if (foodloc != null) { newFood = JsonConvert.DeserializeObject <SnakeUtilities.Food>(jsObj); // Console.WriteLine(theMsg[iter]); } if (removesnake != null) { var dict = JsonConvert.DeserializeObject <Dictionary <string, string> >(jsObj); string tid = dict["ID"]; int tempid; if (Int32.TryParse(tid, out tempid)) { Console.WriteLine("Removing from client world:" + tempid); if (world.getAllSnakes().ContainsKey(tempid)) { world.getAllSnakes()[tempid].killSnake(); } } } //Lock here due to drawing -- source of crazy race condition and weird bug with writing the json message to console. lock (this.world) { if (newFood != null) { worldChange = true; //Add food or delete it from world if (newFood.isFoodAlive()) { //Set in our food dictionary world.getAllFood()[newFood.getID()] = newFood; } else { //Remove from food dictionary so it is no longer redrawn. world.getAllFood().Remove(newFood.getID()); } } if (newSnake != null) { worldChange = true; //Check if snake is alive or dead, then set it accordingly if (newSnake.isSnakeAlive()) { world.getAllSnakes()[newSnake.getID()] = newSnake; } else { world.getAllSnakes().Remove(newSnake.getID()); } } } //Only remove if the message was indeed processed correctly state.sb.Remove(0, jsObj.Length + 1); } else { //Console.WriteLine("MSG RET:" + theMsg[iter]); if (theMsg[iter].Equals("!DIED!")) { this.Invoke((Action)(() => { RespawnButton.Enabled = true; })); } state.sb.Remove(0, theMsg[iter].Length + 1); } } } catch (Exception e) { Console.WriteLine("EXCEPTION:" + e.Message); } //Only draw the panel if the world was changed in some form. Used specifically to not waste time invalidating the screen if the message was empty. if (worldChange) { this.Invoke((Action)(() => { drawingPanel.Invalidate(); } )); } //Recieve more data. NetworkHandler.AwaitDataFromServer(state); }