Exemple #1
0
    /// <summary>
    /// Updates the world at the current FPS.
    /// </summary>
    private void Update()
    {
        lock (serverWorld)
        {
            serverWorld.UpdateWorld();
            serverWorld.CheckCollision();

            foreach (SocketState state in clients.Values.ToList())
            {
                Networking.Send(state.TheSocket, serverWorld.GetWorld() + "\n");
            }
        }
    }
Exemple #2
0
        /// <summary>
        /// "This is a ("callMe") delegate that implements the server's part of the initial
        /// handshake."
        /// </summary>
        /// <param name="state">The client's socket information</param>
        private static void ReceiveName(SocketState state)
        {
            lock (World)
            {
                // Create a new Ship with the given name and a new unique ID
                Ship   newShip = new Ship();
                Random rand    = new Random();

                newShip.ID  = ShipID;
                newShip.loc = new Vector2D(rand.Next(-(UniverseSize / 2), UniverseSize / 2),
                                           rand.Next(-(UniverseSize / 2), UniverseSize / 2));
                newShip.dir    = new Vector2D(rand.Next(-180, 180), rand.Next(-180, 180));
                newShip.thrust = false;
                newShip.name   = state.sb.ToString().Trim();
                newShip.hp     = StartingHitPoints;
                newShip.score  = 0;
                newShip.alive  = true;

                newShip.velocity = new Vector2D(0, 0);
                newShip.dir.Normalize();

                newShip.projFired = 0;
                newShip.projHit   = 0;

                // Add the new ship to World
                World.Ships.Add(newShip.ID, newShip);

                // Alter ShipID for next incoming Ship
                ShipID++;

                // Setting the state's ID to match the newly added Ship
                state.ID = newShip.ID;
                // Prepare the startup info to the client(ID and world size)
                state.sb.Clear();
                state.sb.Append(newShip.ID + "\n");
                state.sb.Append(UniverseSize + "\n");
                state.callMe = HandleData;

                // Send the starup info to the client
                Networking.Send(state.theSocket, state.sb.ToString());

                // Add the client's socket to the list of all clients
                Clients.Add(state);
                Console.WriteLine("A new client has connected to the server...");

                // "Then ask the client for data"
                Networking.GetData(state);
            }
        }
        //Send the walls to the player on initial connect
        private void Sendwalls(SocketState state)
        {
            StringBuilder sb = new StringBuilder();

            lock (world)
            {
                foreach (Wall w in world.GetWalls())
                {
                    sb.Append(JsonConvert.SerializeObject(w) + "\n");
                }
            }
            Networking.Send(state.TheSocket, sb.ToString());
            //Console.WriteLine(sb.ToString());
            sb.Clear();
        }
Exemple #4
0
        /// <summary>
        /// This method updates the state of the world.
        /// </summary>
        private static void Update()
        {
            StringBuilder sb = new StringBuilder();

            //lock the world
            lock (world)
            {
                //for all star in star collection we appenfd to sb.
                foreach (Star s in world.starCollection.Values)
                {
                    sb.Append(s.ToString() + "\n");
                }
                //method to update ships.
                updateships(sb);
                //methods that handles collisons.
                Collisons();
                //method that updates projctile.
                updateProjectile(sb);
            }

            lock (world)
            {
                //copy of the list to remove it from the ss.
                List <SocketState> copy = new List <SocketState>(list);

                foreach (SocketState ss in list)
                {
                    //if the client window is closed.
                    if ((Networking.Send(ss.theSocket, sb.ToString())) == false)
                    {
                        lock (world)
                        {
                            int id = ss.ID;
                            //set the ships hp tp zero.
                            world.shipCollection[ss.ID].setShipHp(0);
                            //and set ship disconnected to true.
                            world.shipCollection[ss.ID].setDisconnected(true);
                            //remove the ship from the ss.
                            copy.Remove(ss);
                        }
                    }
                }
                //after removing ship from the client we set list back to copy.
                list = copy;
            }
        }
        private void NewPlayer(SocketState state)
        {
            string worldSizeString = worldSize.ToString();
            string playerIDString  = state.ID.ToString();

            if (state.ErrorOccured)
            {
                return;
            }
            lock (playerSockets)
            {
                playerSockets[state.ID] = state;
            }
            Networking.Send(state.TheSocket, playerIDString + "\n");
            Networking.Send(state.TheSocket, worldSizeString + "\n");

            state.OnNetworkAction = ProcessMessage;
            Networking.GetData(state);
        }
Exemple #6
0
        /// <summary>
        /// Callback method for after the server receives the name
        /// </summary>
        /// <param name="sock"></param>
        static void ReceiveName(SocketState sock)
        {
            //Create the players tank and assign its name and ID
            Tank mainPlayer = new Tank();

            mainPlayer.name = sock.GetData().Trim();
            mainPlayer.ID   = (int)sock.ID;

            //Add the tank to both tank classes
            lock (tanks)
            {
                allTanksEver.Add(mainPlayer.ID, mainPlayer);
                tanks.Add(mainPlayer.ID, mainPlayer);
            }

            //Assign the health of the tank and spawn the tank
            mainPlayer.hitPoints = StartingHitPoints;
            tankRespawn(mainPlayer);

            //Change the callback to CommandRequestHandler and clear the sock's data
            sock.OnNetworkAction = CommandRequestHandler;
            sock.ClearData();

            //Get the startup data, serialize it, and send it to the client
            string startupData = mainPlayer.ID + "\n" + serverWorld.worldSize + "\n";

            foreach (Wall w in walls.Values)
            {
                startupData += JsonConvert.SerializeObject(w) + "\n";
            }
            startupData += GetWorldData();
            Networking.Send(sock.TheSocket, startupData);

            //Add the client to the connectedClients list and ask for more data
            lock (connectedClients)
            {
                connectedClients.Add(sock.ID, sock);
            }
            Console.WriteLine(mainPlayer.name + " has Joined the Game");
            mainPlayer.joined = true;
            Networking.GetData(sock);
        }
Exemple #7
0
        /// <summary>
        /// Callback to receive player name.
        /// </summary>
        /// <param name="state"></param>
        private void ReceivePlayerName(SocketState state)
        {
            // If a Socket disconnects, return.
            if (state.ErrorOccured)
            {
                return;
            }

            // Add tank to the world if it doesnt exist yet
            if (!clients.ContainsKey(state.ID))
            {
                lock (serverWorld)
                {
                    serverWorld.AddTank(state.ID, state.GetData());
                }
            }

            state.OnNetworkAction = HandleRequests;

            // Send start-up info; Lock the socket to avoid race conditions
            lock (state.TheSocket)
            {
                if (!clients.ContainsKey(state.ID))
                {
                    Networking.Send(state.TheSocket, $"{ state.ID }\n{ WORLD_SIZE }\n");
                    Networking.Send(state.TheSocket, serverWorld.GetWalls() + "\n");
                }
            }

            // Add client to clients list
            lock (clients)
            {
                if (!clients.ContainsKey(state.ID))
                {
                    clients.Add(state.ID, state);
                    Console.WriteLine($"Player({ state.ID }): { state.GetData().TrimEnd('\n') } Has Joined The Game!");
                }
            }

            Networking.GetData(state);
        }
Exemple #8
0
        /// <summary>
        /// Gets the player's name and sends startup info
        /// </summary>
        /// <param name="s"></param>
        private void HandlePlayerName(SocketState s)
        {
            string data = s.GetData();

            string[] parts = Regex.Split(data, @"(?<=[\n])");

            // Check if a full message has been received
            if (parts.Length > 1)
            {
                // Generate a new tank for the client
                Tank t = new Tank((int)s.ID, parts[0].Substring(0, parts[0].Length - 1), new TankWars.Vector2D(50, 50));
                spawnTank(t);

                lock (world) {
                    // Add the tank to the world
                    world.setTankData(t);
                    s.RemoveData(0, parts[0].Length);

                    //Send the player's id
                    Networking.Send(s.TheSocket, s.ID + "\n");

                    // Send world size
                    Networking.Send(s.TheSocket, world.UniverseSize + "\n");

                    // Send all the walls
                    foreach (Wall w in world.Walls.Values)
                    {
                        Networking.Send(s.TheSocket, JsonConvert.SerializeObject(w) + '\n');
                    }
                }

                // Add the tank to the dictionary so it can start receiving frames
                lock (clients) {
                    clients.Add(s, t);
                }
                s.OnNetworkAction = HandleClientCommands;
            }
            Networking.GetData(s);
        }
Exemple #9
0
        /// <summary>
        /// This methods recieves the name and does the first handshake with the
        /// client.
        /// </summary>
        /// <param name="ss"></param>
        public static void RecieveName(SocketState ss)
        {
            string name = "";

            //totalData uses string builder to store all the string from the ss.
            string totalData = ss.sb.ToString();

            //this method splits totalData by nextline.
            String[] parts = totalData.Split('\n');
            //the first string sent is the players name.
            name = parts[0];
            Ship ship;

            //lock the world
            lock (world)
            {
                //calls generate new ship from world and sets it to ship.
                ship = world.generatenewShip(name);
                //sets ss.ID to ships id.
                ss.setSocketStateID(ship.getShipId());
            }

            ss.callMe = callBack;

            //lock the list and add the socketstate.
            lock (list)
            {
                list.Add(ss);
            }
            int universe = UniverseSize;

            //removes the name from the socketstate.
            ss.sb.Remove(0, parts[0].Length + 1);
            //sends data to the specific socket.
            Networking.Send(ss.theSocket, ss.ID.ToString() + "" + "\n" + universe + "\n");
            //calling get data to get more data.
            Networking.GetData(ss);
        }
Exemple #10
0
        /// <summary>
        /// Sends the client the world according to where every object is
        /// </summary>
        static void Update()
        {
            //Lists to hold objects that will be removed
            List <SocketState> disconectedClients = new List <SocketState>();
            List <Object>      expiredObjects     = new List <object>();

            lock (projectiles)
            {
                //For every object in projectiles, Find where it is and update its location
                foreach (Projectile p in projectiles.Values)
                {
                    //Calculate the object's new location
                    p.orientation.Normalize();
                    Vector2D projAngle = new Vector2D(p.orientation.GetX() * ProjectileSpeed, p.orientation.GetY() * ProjectileSpeed);
                    p.location = p.location + projAngle;

                    //If the projectile has collided with anything or is dead, add it to the expired objects list
                    if (collisionCheck(p.location.GetX(), p.location.GetY()))
                    {
                        p.died = true;
                        expiredObjects.Add(p);
                    }
                    if (p.location.GetX() > serverWorld.worldSize / 2 || p.location.GetY() > serverWorld.worldSize / 2 || p.location.GetX() < -serverWorld.worldSize / 2 || p.location.GetY() < -serverWorld.worldSize / 2)
                    {
                        p.died = true;
                        expiredObjects.Add(p);
                    }
                }
            }

            lock (tanks)
            {
                //For every object in Tanks, find it's status and update the object
                foreach (Tank t in tanks.Values)
                {
                    //If the time to respawn counter is still going, drop it down by one
                    if (t.timeToRespawn > 0)
                    {
                        t.timeToRespawn--;
                    }
                    //If the timer is over, respawn the tank
                    else if (t.hitPoints == 0 && !t.disconnected)
                    {
                        tankRespawn(t);
                    }

                    //If the status of the tank is dead, set it to be alive
                    if (t.died)
                    {
                        t.died = false;
                    }
                    //If the tank is disconnected however, is has died
                    if (t.disconnected)
                    {
                        t.died      = true;
                        t.hitPoints = 0;
                    }

                    t.shotTimer--;

                    lock (beams)
                    {
                        //Check to see if any beams currently on screen have hit a tank
                        foreach (Beam b in beams.Values)
                        {
                            //If the beam has hit a tank, the tank is dead
                            if (Intersects(b.origin, b.direction, t.location, 30) && t.hitPoints > 0)
                            {
                                t.hitPoints     = 0;
                                t.died          = true;
                                t.timeToRespawn = RespawnRate;
                                tanks[b.tankID].tankShotsHit++;
                                tanks[b.tankID].score++;
                            }
                        }
                    }

                    lock (projectiles)
                    {
                        //Check to see if any projectiles on screen have hit a tank
                        foreach (Projectile p in projectiles.Values)
                        {
                            //If the projectile hit a tank then lower the hitpoints by one for that tank
                            if (p.tankID != t.ID && objectCollisionCheck(t.location, p.location) && t.hitPoints > 0 && !p.died)
                            {
                                p.died = true;
                                expiredObjects.Add(p);
                                t.hitPoints -= 1;
                                tanks[p.tankID].tankShotsHit++;

                                //If the tank has no hitpoints left, it has died
                                if (t.hitPoints == 0)
                                {
                                    t.died          = true;
                                    t.timeToRespawn = RespawnRate;
                                    tanks[p.tankID].score++;
                                }
                            }
                        }
                    }

                    lock (powerups)
                    {
                        //Check to see if any powerups on screen have hit a tank
                        foreach (Powerup p in powerups.Values)
                        {
                            //If a powerup has hit a tank, increase the beam amount for that tank and destroy the powerup
                            if (objectCollisionCheck(t.location, p.location) && t.hitPoints > 0 && !p.died)
                            {
                                Random rand = new Random();
                                p.died         = true;
                                p.respawnTimer = rand.Next(10, MaxPowerupDelay);
                                t.railgunShots++;
                            }
                        }
                    }
                }
            }

            int powerupRespawnCount = 0;

            lock (powerups)
            {
                //Check all powerups to see if they can respawn
                foreach (Powerup p in powerups.Values)
                {
                    //If the timer is up for a powerup to respawn, add one to the count
                    if (p.respawnTimer == 0)
                    {
                        p.respawnTimer = -1;
                        powerupRespawnCount++;
                        expiredObjects.Add(p);
                    }
                    p.respawnTimer--;
                }
            }

            lock (powerups)
            {
                //Respawn all powerups
                for (int i = 0; i < powerupRespawnCount; i++)
                {
                    powerRespawn();
                }
            }

            //Send the data to all connected clients, if the send fails, add that client to the
            //disconnectedClients list to be removed later
            String dataToSend = GetWorldData();

            lock (connectedClients)
            {
                foreach (SocketState sock in connectedClients.Values)
                {
                    if (!Networking.Send(sock.TheSocket, dataToSend))
                    {
                        lock (disconectedClients)
                        {
                            disconectedClients.Add(sock);
                        }
                    }
                }
            }

            lock (connectedClients)
            {
                //Remove the disconnected client and destroy its tank
                foreach (SocketState sock in disconectedClients)
                {
                    connectedClients.Remove(sock.ID);
                    tanks[(int)sock.ID].died         = true;
                    tanks[(int)sock.ID].hitPoints    = 0;
                    tanks[(int)sock.ID].disconnected = true;
                }
            }

            lock (beams)
            {
                //Destroy all active beams
                beams.Clear();
            }

            lock (expiredObjects)
            {
                //Remove all expired objects from their respective lists
                foreach (Object o in expiredObjects)
                {
                    if (o is Projectile)
                    {
                        lock (projectiles)
                        {
                            Projectile p = (Projectile)o;
                            projectiles.Remove(p.ID);
                        }
                    }

                    if (o is Powerup)
                    {
                        lock (powerups)
                        {
                            Powerup p = (Powerup)o;
                            powerups.Remove(p.ID);
                        }
                    }
                }
                expiredObjects.Clear();
            }
        }
Exemple #11
0
        /// <summary>
        /// This part sets up a tank with the player name and sends the startup info to the client including the world size, player ID,
        /// and walls.
        /// </summary>
        /// <param name="ss">Socket state for the connection</param>
        private static void SendStartupInfo(SocketState ss)
        {
            if (ss.ErrorOccured == true)
            {
                Console.WriteLine("Error occured while accepting: \"" + ss.ErrorMessage + "\"");
                return;
            }

            //Gets the name and ID from the socket and removes the name from the socket
            string tankName = ss.GetData();
            int    tankID   = (int)ss.ID;

            ss.RemoveData(0, tankName.Length);


            lock (TheWorld)
            {
                /*This sets up the tank, sets the cooldown frames so it can fire, adds a filler command to the dictionary, and
                 * spawns the tank at a random location.*/
                Tank t = new Tank(tankName.Substring(0, tankName.Length - 1), tankID);
                TheWorld.UpdateTank(t);
                TheWorld.TankSetCooldownFrames(t.ID, FramesPerShot);
                TheWorld.UpdateCommand(tankID, new ControlCommands());
                SpawnTank(t);

                Console.WriteLine("Player(" + tankID + ") " + "\"" + t.Name + "\" joined");
            }

            //Changes the delegate
            ss.OnNetworkAction = ReceiveCommandData;


            //Sends the tank ID and the world size
            string message = tankID + "\n" + UniverseSize.ToString() + "\n";

            if (!Networking.Send(ss.TheSocket, message))
            {
                Console.WriteLine("Error occured while sending data");
            }

            //Sends the walls to the client
            lock (TheWorld)
            {
                StringBuilder wallMessage = new StringBuilder();
                foreach (Wall w in TheWorld.Walls.Values)
                {
                    wallMessage.Append(JsonConvert.SerializeObject(w) + "\n");
                }
                if (!Networking.Send(ss.TheSocket, wallMessage.ToString()))
                {
                    Console.WriteLine("Error occured while sending data");
                }
            }


            //Adds the socket state to the list of connections
            SocketConnections.Add(ss);


            Networking.GetData(ss);
        }
Exemple #12
0
        /// <summary>
        /// Method for sending the data to the client sockets. It goes through the list of tanks, powerups, projectiles, and beams
        /// and appends them to a stringbuilder to send. It also handles sockets that have disconnected.
        /// </summary>
        private static void SendDataToSockets()
        {
            lock (TheWorld)
            {
                foreach (SocketState s in SocketConnections.ToList())
                {
                    if (!s.TheSocket.Connected)
                    {
                        int tankID = (int)s.ID;

                        //Makes sure that the dictionary contains the right key. If not, the tank must have died and rage quit
                        if (TheWorld.Tanks.ContainsKey(tankID))
                        {
                            Console.WriteLine("Player(" + tankID + ") " + "\"" + TheWorld.Tanks[(int)s.ID].Name + "\" disconnected");

                            TheWorld.TankDisconnect(tankID);
                            TheWorld.TankKill(tankID);
                        }

                        if (TheWorld.DeadTanks.ContainsKey(tankID))
                        {
                            Console.WriteLine("Player(" + tankID + ") " + "\"" + TheWorld.DeadTanks[(int)s.ID].Name + "\" disconnected");
                            TheWorld.TankDeadRemove(tankID);
                        }

                        SocketConnections.Remove(s);
                    }
                }

                foreach (SocketState s in SocketConnections.ToList())
                {
                    StringBuilder frameMessage = new StringBuilder();


                    lock (TheWorld)
                    {
                        foreach (Tank t in TheWorld.Tanks.Values)
                        {
                            frameMessage.Append(JsonConvert.SerializeObject(t) + "\n");
                        }

                        foreach (PowerUp p in TheWorld.PowerUps.Values)
                        {
                            frameMessage.Append(JsonConvert.SerializeObject(p) + "\n");
                        }

                        foreach (Projectile p in TheWorld.Projectiles.Values)
                        {
                            frameMessage.Append(JsonConvert.SerializeObject(p) + "\n");
                        }

                        foreach (Beam b in TheWorld.Beams.Values)
                        {
                            frameMessage.Append(JsonConvert.SerializeObject(b) + "\n");
                        }
                    }

                    if (!Networking.Send(s.TheSocket, frameMessage.ToString()))
                    {
                        Console.WriteLine("Error occured while sending data");
                    }
                }
            }
        }
        private void SendData()
        {
            while (true)
            {
                List <SocketState> playerSocketCopy = new List <SocketState>(playerSockets.Values);
                StringBuilder      sb           = new StringBuilder();
                List <long>        listToRemove = new List <long>();
                var prev = DateTime.Now;

                //For every socket connected to this server send a frame
                foreach (SocketState state in playerSocketCopy)
                {
                    foreach (Tank t in world.GetTanks())
                    {
                        t.projectileDelay += 1;
                    }
                    if (powerUpTracker < powerupCount)
                    {
                        timeSinceLastPowerUp += FPS;
                    }
                    if (timeSinceLastPowerUp > randPowerupTime)
                    {
                        SpawnPowerup();
                        randPowerupTime      = rand.Next(0, maxPowerupSpawnTime);
                        timeSinceLastPowerUp = 0;
                    }

                    //Seems innefficient to do this for every tank but.. TODO
                    lock (world)
                    {
                        foreach (Tank t in world.GetTanks())
                        {
                            sb.Append(JsonConvert.SerializeObject(t) + "\n");
                            if (t.IsDead())
                            {
                                RespawnTank(t);
                            }
                            if (t.IsDisconnected())
                            {
                                listToRemove.Add(t.GetID());
                            }
                        }

                        foreach (long ID in listToRemove)
                        {
                            world.RemoveTankByID((int)ID);
                        }
                        listToRemove.Clear();

                        foreach (Projectile p in world.GetProjectiles())
                        {
                            MoveProjectile(p);
                            sb.Append(JsonConvert.SerializeObject(p) + "\n");
                            if (p.IsDead())
                            {
                                listToRemove.Add(p.GetID());
                            }
                        }
                        foreach (long ID in listToRemove)
                        {
                            world.RemoveProjectile(ID);
                        }

                        listToRemove.Clear();
                        foreach (Beam b in world.GetBeams())
                        {
                            sb.Append(JsonConvert.SerializeObject(b) + "\n");
                            listToRemove.Add(b.GetID());
                        }
                        foreach (long ID in listToRemove)
                        {
                            world.RemoveBeam(ID);
                        }
                        listToRemove.Clear();
                        foreach (Powerup up in world.GetPowerups())
                        {
                            sb.Append(JsonConvert.SerializeObject(up) + "\n");
                            if (up.IsDead())
                            {
                                listToRemove.Add(up.GetID());
                            }
                        }
                        if (!working)
                        {
                            foreach (long ID in listToRemove)
                            {
                                world.RemovePowerup(ID);
                                powerUpTracker--;
                            }
                        }
                    }
                    listToRemove.Clear();
                    List <SocketState> mySockets = new List <SocketState>(playerSockets.Values);
                    foreach (SocketState player in mySockets)
                    {
                        Networking.Send(player.TheSocket, sb.ToString());
                    }

                    //Console.WriteLine(sb.ToString());
                    sb.Clear();
                }
                //managing the framerate for when this loop repeats
                var now = DateTime.Now;
                if (now <= prev.AddMilliseconds(FPS))
                {
                    TimeSpan timeSpan = prev.AddMilliseconds(FPS) - now;
                    System.Threading.Thread.Sleep((int)timeSpan.TotalMilliseconds);
                }
                prev = DateTime.Now;
            }
        }
Exemple #14
0
        /// <summary>
        /// Invoked every iteration through the frame loop.
        /// Update World, then sends it to each client.
        /// </summary>
        private static void Update()
        {
            // Updated world
            StringBuilder sb = new StringBuilder();

            lock (World)
            {
                // For all Stars in World
                foreach (Star star in World.Stars.Values)
                {
                    // Append each Star
                    sb.Append(JsonConvert.SerializeObject(star) + "\n");

                    // Destroy all Ships colliding with Star
                    foreach (Ship ship in World.Ships.Values)
                    {
                        Vector2D distance = star.loc - ship.loc;
                        if (distance.Length() < StarSize)
                        {
                            ship.hp = 0;
                            if (GAMEMODE_RandomDeadlyStar)
                            {
                                ship.score--;
                            }
                            ship.alive = false;
                            DeadShips.Add(ship);
                        }
                    }

                    // Destroy all Projectiles colliding with Star
                    foreach (Projectile p in World.Projectiles.Values)
                    {
                        Vector2D distance = star.loc - p.loc;
                        if (distance.Length() < StarSize)
                        {
                            p.alive = false;
                            DeadProjectiles.Add(p.ID);
                        }
                    }
                }

                // For all Ships in World
                foreach (Ship ship in World.Ships.Values)
                {
                    // Thrust Ship
                    if (ship.up)
                    {
                        ship.thrust    = true;
                        ship.velocity += Acceleration(Thrust(ship.dir), Gravity(ship.loc));
                        ship.loc      += ship.velocity;
                        ship.up        = false;
                    }
                    // Non-thrusting Ship
                    else
                    {
                        ship.velocity += Gravity(ship.loc);
                        ship.loc      += ship.velocity;
                        ship.thrust    = false;
                    }
                    // Rotate Left
                    if (ship.left)
                    {
                        ship.dir  = RotateLeft(ship.dir);
                        ship.left = false;
                    }
                    // Rotate right
                    if (ship.right)
                    {
                        ship.dir   = RotateRight(ship.dir);
                        ship.right = false;
                    }
                    // Fire projectile
                    if (ship.space && ship.alive)
                    {
                        // Begin spacing projectiles
                        ship.projectileTimer++;
                        if (ship.projectileTimer >= ProjectileFiringDelay)
                        {
                            Projectile p = new Projectile();
                            p.ID    = ProjectileID;
                            p.loc   = ship.loc;
                            p.dir   = ship.dir;
                            p.alive = true;
                            p.owner = ship.ID;

                            p.velocity = (p.dir * ProjectileSpeed) + ship.velocity;

                            World.Projectiles.Add(p.ID, p);

                            ship.projFired++;
                            ship.projectileTimer = 0;
                            ProjectileID++;
                        }
                        ship.space = false;
                    }

                    // If Ship exits World's bounds
                    if (ship.loc.GetX() >= UniverseSize / 2 || ship.loc.GetX() <= -(UniverseSize / 2) ||
                        ship.loc.GetY() >= UniverseSize / 2 || ship.loc.GetY() <= -(UniverseSize / 2))
                    {
                        // Wrap around Ship
                        ship.loc = WrapAround(ship.loc);
                    }

                    // Destroy all Projectiles colliding with Ship and vise-versa
                    foreach (Projectile p in World.Projectiles.Values)
                    {
                        Vector2D distance = ship.loc - p.loc;

                        if (distance.Length() < ShipSize && ship.ID != p.owner && ship.alive)
                        {
                            p.alive = false;
                            ship.hp--;

                            ShipHits.Add(World.Ships[p.owner]);
                            if (ship.hp <= 0)
                            {
                                ship.alive = false;
                                DeadShips.Add(ship);
                                ScoringShips.Add(p.owner);
                            }
                            DeadProjectiles.Add(p.ID);
                        }
                    }

                    sb.Append(JsonConvert.SerializeObject(ship) + "\n");
                }

                // For all Projectiles in World
                foreach (Projectile p in World.Projectiles.Values)
                {
                    // Update projectile location with constant velocity
                    p.loc += p.velocity;

                    // If Projectile exits World's bounds
                    if (p.loc.GetX() >= UniverseSize / 2 || p.loc.GetX() <= -(UniverseSize / 2) ||
                        p.loc.GetY() >= UniverseSize / 2 || p.loc.GetY() <= -(UniverseSize / 2))
                    {
                        // Destroy Projectile
                        p.alive = false;
                        DeadProjectiles.Add(p.ID);
                    }

                    sb.Append(JsonConvert.SerializeObject(p) + "\n");
                }

                // All Projectiles-to-destroy are removed from World
                foreach (int i in DeadProjectiles)
                {
                    World.Projectiles.Remove(i);
                }
                DeadProjectiles.Clear();

                // All Ships-to-score have score increased
                foreach (int i in ScoringShips)
                {
                    Ship s = World.Ships.Values.ElementAt(i);
                    s.score++;
                }
                ScoringShips.Clear();

                // All Ships-to-destroy are removed from World and respawned
                foreach (Ship ship in DeadShips)
                {
                    if (ship.hp <= 0)
                    {
                        // Incremental value has a further effect on respawn rate
                        ship.respawnTimer += 20;
                    }
                    if (ship.respawnTimer >= RespawnDelay * TimePerFrame)
                    {
                        ship.respawnTimer = 0;
                        ResetShip(ship);
                        ResurrectedShips.Add(ship);
                    }
                }

                // Respawn dead Ship
                foreach (Ship ship in ResurrectedShips)
                {
                    DeadShips.Remove(ship);
                }
                ResurrectedShips.Clear();

                // Add hit projectiles to Ship
                foreach (Ship ship in ShipHits)
                {
                    World.Ships[ship.ID].projHit++;
                }
                ShipHits.Clear();

                // Each client is updated with appended World information
                foreach (SocketState state in Clients)
                {
                    Networking.Send(state.theSocket, sb.ToString());
                }
            }
        }