/// <summary> /// Processes the message received from the server. If it is a json object, it updates the world accordingly. /// Otherwise, it is either the player id or world size, and thus sets those accordingly. /// </summary> private void ProcessMessage(SocketState state) { if (state.ErrorOccured) { return; } //Gets data and parts from data string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); foreach (string s in parts) { //If the part has a length of 0, then it is not a complete message if (s.Length <= 0) { continue; } //If the part does not end with newline, then the message is incomplete if (s[s.Length - 1] != '\n') { break; } //If the part is a json, deserialize if (s[0] == '{') { lock (world) { //Get the json object out of the part JObject obj = JObject.Parse(s); JToken type; //Wall is not loaded if (!world.WallsLoaded) { type = obj["wall"]; if (type != null) { Wall w = JsonConvert.DeserializeObject <Wall>(s); world.AddWall(w.ID, w.p1, w.p2); } else { //As soon as we reach a JSON that isn't a wall, the walls are loaded world.LoadWalls(); WorldLoaded(); } } //If it a tank, update the world type = obj["tank"]; if (type != null) { Tank t = JsonConvert.DeserializeObject <Tank>(s); world.UpdateTank(t.ID, t.location, t.orientation, t.aiming, t.name, t.hitPoints, t.score, t.died, t.disconnected); } //Projectile type = obj["proj"]; if (type != null) { Projectile p = JsonConvert.DeserializeObject <Projectile>(s); world.UpdateProjectile(p.ID, p.location, p.orientation, p.owner, p.died); } //Powerup type = obj["power"]; if (type != null) { Powerup p = JsonConvert.DeserializeObject <Powerup>(s); world.UpdatePowerup(p.ID, p.location, p.died); } //Beam type = obj["beam"]; if (type != null) { Beam b = JsonConvert.DeserializeObject <Beam>(s); BeamFired(b); } } } //If it is not a json object, then it must be the world size or player id else { //If player id is not set, then the part is the player id if (PlayerID < 0) { PlayerID = Int32.Parse(s); IDLoaded(); } //Otherwise, the part must be the world else { world = new World(Int32.Parse(s)); } } lock (state) { //Remove the processed part state.RemoveData(0, s.Length); } //If OnUpdate is set, call it if (OnUpdate != null) { OnUpdate(); } } }
/// <summary> /// Updates the world based off of commands and game logic. /// </summary> private void updateWorld() { lock (world) { //Powerup logic if (powerUpTimer == 0 && new List <Powerup>(world.GetPowerups()).Count < world.maxPowers) { Random r = new Random(); Vector2D RandLoc = new Vector2D(r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16), r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16)); while (CheckPowerupWallCollision(RandLoc)) { RandLoc = new Vector2D(r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16), r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16)); } world.UpdatePowerup(powerupCount++, RandLoc, false); resetPowerupTimer(); } else if (powerUpTimer != 0) { powerUpTimer--; } //Tank logic foreach (Tank t in new List <Tank>(tanksFired.Keys)) { int temp = tanksFired[t]; if (temp > 1) { tanksFired[t]--; } else { tanksFired.Remove(t); } } foreach (Tank t in new List <Tank>(tanksRespawning.Keys)) { if (t.died) { world.UpdateTank(t.ID, t.location, t.orientation, t.aiming, t.name, t.hitPoints, t.score, false, t.disconnected); } int temp = tanksRespawning[t]; if (temp > 1) { tanksRespawning[t]--; } else { tanksRespawning.Remove(t); Random r = new Random(); Vector2D RandLoc = new Vector2D(r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16), r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16)); while (CheckTankWallCollision(RandLoc)) { RandLoc = new Vector2D(r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16), r.Next(-world.GetSize() / 2 + 16, world.GetSize() / 2 - 16)); } t.beams = 0; world.UpdateTank(t.ID, RandLoc, new Vector2D(0, 1), new Vector2D(0, 1), t.name, 3, t.score, t.died, t.disconnected); } } foreach (Tank t in new List <Tank>(world.GetTanks())) { if (t.disconnected == true) { world.UpdateTank(t.ID, new Vector2D(0, 0), new Vector2D(0, 1), new Vector2D(0, 1), t.name, t.hitPoints, 0, t.died, t.disconnected); } } //Disconnect logic foreach (SocketState s in new List <SocketState>(users.Keys)) { if (s.ErrorOccured) { if (world.GetTank(users[s], out Tank t)) { t.setDisconnected(); } } } //Control command logic foreach (int i in new List <int>(controls.Keys)) { if (world.GetTank(i, out Tank t)) { if (t.hitPoints != 0 && !tanksRespawning.ContainsKey(t)) { ControlCommand c = controls[i]; Vector2D orientation = new Vector2D(1, 0); switch (c.moving) { case "none": orientation = t.orientation; t.velocity = new Vector2D(0, 0); break; case "up": orientation = new Vector2D(0, -1); t.velocity = new Vector2D(0, -world.tankSpeed); break; case "down": orientation = new Vector2D(0, 1); t.velocity = new Vector2D(0, world.tankSpeed); break; case "left": orientation = new Vector2D(-1, 0); t.velocity = new Vector2D(-world.tankSpeed, 0); break; case "right": orientation = new Vector2D(1, 0); t.velocity = new Vector2D(world.tankSpeed, 0); break; } Vector2D loc = t.location + t.velocity; if (CheckTankWallCollision(loc)) { loc = t.location; } loc = TankWraparound(loc); orientation.Normalize(); c.direction.Normalize(); world.UpdateTank(t.ID, loc, orientation, c.direction, t.name, t.hitPoints, t.score, t.died, t.disconnected); if (c.fire == "main" && !tanksFired.ContainsKey(t)) { world.UpdateProjectile(projCount++, t.location, c.direction, t.ID, false); tanksFired.Add(t, world.projectileDelay); } else if (c.fire == "alt" && t.beams > 0) { world.AddBeam(beamCount++, t.location, c.direction, t.ID); t.beams--; } controls.Remove(i); } } } //beam logic beams = new List <Beam>(world.GetBeams()); foreach (Beam b in new List <Beam>(world.GetBeams())) { List <Tank> temp = CheckBeamTankCollision(b); foreach (Tank hitTank in temp) { if (hitTank.ID != b.owner && !tanksRespawning.ContainsKey(hitTank)) { if (world.GetTank(b.owner, out Tank t)) { world.UpdateTank(hitTank.ID, hitTank.location, hitTank.orientation, hitTank.aiming, hitTank.name, 0, hitTank.score, true, t.disconnected); tanksRespawning.Add(hitTank, world.respawnTime); t.kill(); } } } world.RemoveBeam(b.ID); } //projectile logic foreach (Projectile p in new List <Projectile>(world.GetProjectiles())) { Vector2D loc = p.location + p.orientation * world.projectileSpeed; world.UpdateProjectile(p.ID, loc, p.orientation, p.owner, p.died); if (!p.died) { if (CheckProjectileWallCollision(loc)) { p.setDied(); } else if (CheckProjectileTankCollision(loc, out Tank hitTank)) { if (hitTank.ID != p.owner && !tanksRespawning.ContainsKey(hitTank)) { p.setDied(); hitTank.hit(); if (world.GetTank(p.owner, out Tank t) && hitTank.hitPoints == 0) { world.UpdateTank(hitTank.ID, hitTank.location, hitTank.orientation, hitTank.aiming, hitTank.name, hitTank.hitPoints, hitTank.score, true, t.disconnected); tanksRespawning.Add(hitTank, world.respawnTime); t.kill(); } } } } } //powerup logic foreach (Powerup p in new List <Powerup>(world.GetPowerups())) { world.UpdatePowerup(p.ID, p.location, p.died); if (!p.died) { if (CheckProjectileTankCollision(p.location, out Tank hitTank)) { if (!tanksRespawning.ContainsKey(hitTank)) { p.setDied(); hitTank.beams++; } } } } //create lists for send (beams is done before these) tanks = new List <Tank>(world.GetTanks()); projs = new List <Projectile>(world.GetProjectiles()); powerups = new List <Powerup>(world.GetPowerups()); } }