/// <summary> /// Determines whether to block damage if they have recently used a banned item or modifies damage /// if the projectile is on the modifications list. /// </summary> /// <param name="args">The GetDataHandlerArgs object containing the player who sent the packet and the /// data in it</param> /// <returns>Whether or not the packet was handled (and should therefore not be processed /// by anything else</returns> private bool HandleDamage(GetDataHandlerArgs args) { if (args.Player == null) { return(false); } var index = args.Player.Index; var playerId = (byte)args.Data.ReadByte(); var damageSourceFlags = (BitsByte)args.Data.ReadByte(); var sourceItemType = -1; var sourceProjectileType = -1; var sourceItemPrefix = -1; if (damageSourceFlags[0]) { var sourcePlayerIndex = args.Data.ReadInt16(); } if (damageSourceFlags[1]) { var sourceNPCIndex = args.Data.ReadInt16(); } if (damageSourceFlags[2]) { var sourceProjectileIndex = args.Data.ReadInt16(); } if (damageSourceFlags[3]) { var sourceOtherIndex = args.Data.ReadByte(); } if (damageSourceFlags[4]) { sourceProjectileType = args.Data.ReadInt16(); } if (damageSourceFlags[5]) { sourceItemType = args.Data.ReadInt16(); } if (damageSourceFlags[6]) { sourceItemPrefix = args.Data.ReadByte(); } var damage = args.Data.ReadInt16(); var dir = args.Data.ReadByte(); var flags = args.Data.ReadByte(); args.Data.ReadByte(); if (TShock.Players[playerId] == null || sourceItemType == -1 || args.Player.IsDead || Controller.Players[playerId].IsDead) { return(true); } // The sourceItemType is only reliable if no projectile is involved // as sourceItemType is simply the active slot item // TODO: Change this to use active slot item of server Item weapon = new Item(); if (sourceProjectileType == -1) { weapon.SetDefaults(sourceItemType); weapon.Prefix(sourceItemPrefix); weapon.owner = args.Player.Index; } else if (args.Player.ProjectileWeapon[sourceProjectileType] != null) { Item bestWeaponGuess = args.Player.ProjectileWeapon[sourceProjectileType]; weapon.SetDefaults(bestWeaponGuess.netID); weapon.Prefix(bestWeaponGuess.prefix); weapon.owner = args.Player.Index; } double internalDamage = Main.player[args.Player.Index].GetWeaponDamage(weapon); // Check whether the source of damage is banned if (Controller.Weapons.Count(p => p.netID == weapon.netID && p.banned) > 0 || Controller.Projectiles.Count(p => p.netID == sourceProjectileType && p.banned) > 0) { args.Player.TshockPlayer.SendData(PacketTypes.PlayerHp, "", playerId); return(true); } internalDamage = DamageController.DecideDamage(args.Player, Controller.Players[playerId], weapon, sourceProjectileType, internalDamage); // Send Damage and Damage Text int realDamage = (int)Math.Round(DamageUtils.GetRealDamageFromInternalDamage(Main.player[playerId], internalDamage)); Color msgColor = new Color(162, 0, 255); NetMessage.SendData(119, index, -1, NetworkText.FromLiteral($"{realDamage}"), (int)msgColor.PackedValue, Main.player[playerId].position.X, Main.player[playerId].position.Y - 32); var killer = new PlayerKiller(args.Player.TshockPlayer, weapon); Controller.Players[playerId].ApplyPlayerDamage(killer, weapon, dir, (int)internalDamage, realDamage); NetMessage.SendData((int)PacketTypes.PlayerHp, -1, playerId, NetworkText.Empty, playerId); // Update spectating time so they cannot simply hide from their attacker if (Controller.Players[playerId].LastSpectating < DateTime.UtcNow.AddSeconds(-15)) { Controller.Players[playerId].LastSpectating = DateTime.UtcNow.AddSeconds(-15); } return(true); }