/// <summary> /// Does collision detection between the shooter and the player /// </summary> /// <param name="shooter"></param> static void BulletToPlayer(ServerPlayer shooter) { // Get the distance between the player and the shooter foreach (ServerPlayer player in players) { // The shooter can't shoot themself, obviously. if (player != shooter) { // If friendly fire is disabled and the player is // on the same team, don't do collision detection if (!friendlyFire && player.CurrentTeam == shooter.CurrentTeam) { continue; } // Get distance between the player and the enemy Vector2 delta = player.Position - shooter.Position; // Get -2Pi - 2Pi version of the shooter's angle float angle = shooter.Rotation < 0 ? (float)(shooter.Rotation + (2 * Math.PI)) : shooter.Rotation; // Get angle between shooter and player float shooterToPlayerAngle = (float)Math.Atan2(delta.Y, delta.X); // If the angle between the shooter and player is less than 0 radians // add 2 Pi to convert it from -Pi - Pi domain to -2Pi - 2Pi domain shooterToPlayerAngle = shooterToPlayerAngle < 0 ? (float)(shooterToPlayerAngle + (2 * Math.PI)) : shooterToPlayerAngle; // If the angle of the shooter is within 0.2 radians of the // angle between the shooter and the player, it means they are // not aiming in the opposite direction of the player which would // result in the collision detection returning true if (angle > shooterToPlayerAngle - 0.2f && angle < shooterToPlayerAngle + 0.2f) { // Get the direction of the shooter Vector2 direction = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)); // Get distance between the player and any possible obstacles in between the // player and the enemy RayCastResult result = raycaster.RayCastMethod(shooter.Position, direction, 1280, MapData.TileMap, MapData.MapArea, angle); // Get the delta between the collision point and the shooter Vector2 raycastDistance = result.CollisionPos - shooter.Position; // If the raycast had collided with an object in between two players // the distance of the raycast would be shorter, therefore, the player // has no direct line of sight with the other player if (raycastDistance.Length() > delta.Length()) { // If the shot passes through the player and they are alive if (Collision.NonAACollision(shooter.Position, shooter.Rotation, new Rectangle( (int)player.Position.X - 16, (int)player.Position.Y + 16, 32, 32), player.Rotation) && player.State == ServerClientInterface.PlayerState.Alive) { // Deal the correct amount of damage depending on the weapon switch (shooter.CurrentWeapon.Weapon) { case WeaponData.Weapon.Knife: break; case WeaponData.Weapon.Ak47: player.Damage(12, 0); break; case WeaponData.Weapon.Glock: break; case WeaponData.Weapon.Awp: break; case WeaponData.Weapon.Usp: break; case WeaponData.Weapon.M4A1: player.Damage(12, 0); break; } Console.WriteLine("\"" + shooter.UserName + "\" shot \"" + player.UserName + " with " + shooter.CurrentWeapon.Weapon); // If the player's health is less than zero, they died. Let everyone know. if (player.Health <= 0) { player.SetHealth(0); player.SetArmor(0); player.SetState(ServerClientInterface.PlayerState.Dead); Console.WriteLine(shooter.UserName + " killed " + player.UserName + " with " + shooter.CurrentWeapon.Weapon); } // Send data to all players outMsg = server.CreateMessage(); outMsg.Write(ServerClientInterface.DAMAGE); outMsg.Write(player.Identifier); outMsg.Write(player.Health); outMsg.Write(player.Armor); server.SendToAll(outMsg, NetDeliveryMethod.UnreliableSequenced); } } } } } }
/// <summary> /// Checks the collision for a player and their direction /// </summary> /// <param name="player"></param> /// <param name="direction"></param> /// <returns></returns> static bool CheckPlayerCollision(ServerPlayer player, byte direction) { // If the player isn't currently a spectator if (player.CurrentTeam != ServerClientInterface.Team.Spectator) { // If collision between player is enabled if (enableCollision) { // Get the direection and adjust the movement speed float vectorX = 0f; float vectorY = 0f; switch (direction) { case ServerClientInterface.MOVE_UP: vectorY = -ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_DOWN: vectorY = ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_LEFT: vectorX = -ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_RIGHT: vectorX = ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_UPRIGHT: vectorX = ServerClientInterface.MOVEMENT_SPEED; vectorY = -ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_DOWNRIGHT: vectorX = ServerClientInterface.MOVEMENT_SPEED; vectorY = ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_DOWNLEFT: vectorX = -ServerClientInterface.MOVEMENT_SPEED; vectorY = ServerClientInterface.MOVEMENT_SPEED; break; case ServerClientInterface.MOVE_UPLEFT: vectorX = -ServerClientInterface.MOVEMENT_SPEED; vectorY = -ServerClientInterface.MOVEMENT_SPEED; break; } // Circle to Circle collision with the player wishing to move // and every other player on the map. Returning false // prevents the movement byte being sent to the player foreach (ServerPlayer ply in players) { // If team collision is enabled, don't check players who are on the same team if (!teamCollision && ply.CurrentTeam == player.CurrentTeam) { continue; } if (ply.Identifier != player.Identifier && ply.State != ServerClientInterface.PlayerState.Dead) { if (Collision.PlayerToPlayer(new Vector2(player.Position.X + vectorX, player.Position.Y + vectorY), ply.Position, 23f)) { return(false); } } } } // Player to wall collision // Gets the tiles that need to be checked Tile[] tiles = GetTiles(player.Position, direction); // Check each tile that is not null and is a solid // Circle to Rectangle collision. Returns false // if a collision is found foreach (Tile tile in tiles) { if (tile != null && tile.Property == Tile.SOLID) { if (Collision.PlayerToRectangle(player.Position, tile.TileRect, 14f)) { return(false); } } } // If no collisions occur, allow the player to move return(true); } return(true); }
/// <summary> /// Respwans a player at their spawn point /// </summary> /// <param name="player"></param> static void RespawnPlayer(ServerPlayer player) { // Default location Vector2 location = Vector2.Zero; // Randomly determine a spawn point depending on their team and // respawns them there int spawnPoint; switch (player.CurrentTeam) { case ServerClientInterface.Team.CounterTerrorist: while (true) { // Get a random index in the CT spawn points spawnPoint = rand.Next(0, MapData.CTTile.Count); bool empty = true; // Check if nobody is currently on that spawn point foreach (ServerPlayer ply in players) { if (ply.Identifier != player.Identifier) { if (MapData.CTTile[spawnPoint].TileRect.Contains((int)ply.Position.X, (int)ply.Position.Y)) { empty = false; break; } } } if (empty) { location = new Vector2(MapData.CTTile[spawnPoint].TileRect.X + 16, MapData.CTTile[spawnPoint].TileRect.Y + 16); break; } } break; case ServerClientInterface.Team.Terrorist: while (true) { // Get a random index in the T spawn points spawnPoint = rand.Next(0, MapData.TTile.Count); bool empty = true; // Check if nobody is currently on that spawn point foreach (ServerPlayer ply in players) { if (ply.Identifier != player.Identifier) { if (MapData.CTTile[spawnPoint].TileRect.Contains((int)ply.Position.X, (int)ply.Position.Y)) { empty = false; break; } } } // If the spawn point is empty, allow the player to spawn there if (empty) { location = new Vector2(MapData.TTile[spawnPoint].TileRect.X + 16, MapData.TTile[spawnPoint].TileRect.Y + 16); break; } } break; } // Tell everyone the player respawned and their position outMsg = server.CreateMessage(); player.Respawn(location); outMsg.Write(ServerClientInterface.RESPAWN_PLAYER); outMsg.Write(player.Identifier); outMsg.Write(player.Position.X); outMsg.Write(player.Position.Y); server.SendToAll(outMsg, NetDeliveryMethod.ReliableSequenced); }
/// <summary> /// Updates and processes requests by users /// </summary> public static void UpdateNetwork() { // TODO : Updates the network, recieves input. while ((msg = server.ReadMessage()) != null) { outMsg = server.CreateMessage(); ServerPlayer player; byte code; switch (msg.MessageType) { case NetIncomingMessageType.StatusChanged: switch ((NetConnectionStatus)msg.ReadByte()) { case NetConnectionStatus.Connected: // If someone has successfully connected to the server, check // if there are too many connected clients and prevent entry from // the client if the number of users exceed the max number of players if (numPlayers > maxPlayers) { msg.SenderConnection.Deny("Server Is Full"); } // initialize handshake with the client. Give them a unique identifier // which allows the server to differ between multiple clients outMsg.Write(ServerClientInterface.HANDSHAKE); // Send the message server.SendMessage(outMsg, msg.SenderConnection, NetDeliveryMethod.ReliableSequenced); break; case NetConnectionStatus.Disconnected: // Get the player that just disconnected player = players.Find( ply => ply.ConnectionIdentifier == msg.SenderConnection.RemoteUniqueIdentifier); // Tell everyone that the user disconnected outMsg.Write(ServerClientInterface.PLAYER_DISCONNECTED); outMsg.Write(player.Identifier); server.SendToAll(outMsg, NetDeliveryMethod.ReliableSequenced); // Subtract number of players of the associated team switch (player.CurrentTeam) { case ServerClientInterface.Team.CounterTerrorist: numCts--; break; case ServerClientInterface.Team.Terrorist: numTs--; break; } // Subtract one less player on the server numPlayers--; Console.WriteLine("\"" + player.UserName + "\" has left the server"); // Remove the player from the server players.Remove(player); break; } break; case NetIncomingMessageType.Data: // Get identifier byte used to determine message type code = msg.ReadByte(); switch (code) { // A user requested to retrieve information of all players on server case ServerClientInterface.REQUEST_SYNC: string username = msg.ReadString(); // Set up a new player in the server player = new ServerPlayer(username, playerIdentifier, msg.SenderConnection.RemoteUniqueIdentifier); players.Add(player); playerIdentifier++; numPlayers++; // Let the client know their information was recieved and processed outMsg.Write(ServerClientInterface.HANDSHAKE_COMPLETE); outMsg.Write(player.Identifier); server.SendMessage(outMsg, msg.SenderConnection, NetDeliveryMethod.ReliableSequenced); // Resend data about players to everyone in order to stay in sync SyncCurrentPlayers(); Console.WriteLine("\"" + username + "\" has joined the server"); break; case ServerClientInterface.CHANGE_TEAM: // Find the player with the matching unique identifier player = players.Find( ply => ply.ConnectionIdentifier == msg.SenderConnection.RemoteUniqueIdentifier); // Change their team player.SetTeam(msg.ReadByte()); // Increase the number of players currently on the // associated team switch (player.CurrentTeam) { case ServerClientInterface.Team.CounterTerrorist: numCts++; break; case ServerClientInterface.Team.Terrorist: numTs++; break; } // Tell everyone else that the player had switched teams and // what team they switched to outMsg.Write(ServerClientInterface.CHANGE_TEAM); outMsg.Write(player.Identifier); outMsg.Write(ServerClientInterface.TeamToByte(player.CurrentTeam)); server.SendToAll(outMsg, NetDeliveryMethod.ReliableSequenced); Console.WriteLine("\"" + player.UserName + "\" joined the " + player.CurrentTeam); break; // Movement Processing for 8 directions case ServerClientInterface.MOVE_UP: case ServerClientInterface.MOVE_DOWN: case ServerClientInterface.MOVE_LEFT: case ServerClientInterface.MOVE_RIGHT: case ServerClientInterface.MOVE_UPLEFT: case ServerClientInterface.MOVE_UPRIGHT: case ServerClientInterface.MOVE_DOWNRIGHT: case ServerClientInterface.MOVE_DOWNLEFT: Move(code, msg.SenderConnection.RemoteUniqueIdentifier); break; // Rotation processing case ServerClientInterface.ROTATE_PLAYER: Rotate(msg.ReadFloat(), msg.SenderConnection.RemoteUniqueIdentifier); break; // Weapon buying processing case ServerClientInterface.BUY_WEAPON: byte wep = msg.ReadByte(); SpawnWeapon(msg.SenderConnection.RemoteUniqueIdentifier, wep); break; // Weapon firing processing case ServerClientInterface.FIRE_WEAPON: FireWeapon(msg.SenderConnection.RemoteUniqueIdentifier); break; // Flashbang exploding processing case ServerClientInterface.EXPLODE_FLASHBANG: outMsg.Write(ServerClientInterface.EXPLODE_FLASHBANG); server.SendToAll(outMsg, NetDeliveryMethod.UnreliableSequenced); break; // User requested respawn case ServerClientInterface.REQUEST_RESPAWN: // Client requested respawn player = players.Find( ply => ply.ConnectionIdentifier == msg.SenderConnection.RemoteUniqueIdentifier); // If they are dead, respawn the player if (player.State == ServerClientInterface.PlayerState.Dead) { RespawnPlayer(player); } break; } break; } } }
/// <summary> /// Creates a new weapon /// </summary> /// <param name="weapon"></param> /// <param name="owner"></param> public ServerWeapon(WeaponData.Weapon weapon, ServerPlayer owner) { Owner = owner; Weapon = weapon; Fired = false; }
/// <summary> /// Allows a player to pickup the weapon /// </summary> /// <param name="owner"></param> public void Pickup(ServerPlayer owner) { Owner = owner; }