diff --git a/CHANGELOG.md b/CHANGELOG.md index a84786df..ba907aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Putting this stuff down here so things don't conflict as often. * Added `TSPlayer` to `GetDataHandlers.ChestItemChanged`. (@hakusaro) * Fixed chest item changes not triggering any range checks, tile checks, or correct chest checks. (@hakusaro) * Added `TSPlayer` to `GetDataHandlers.PlayerBuff`. (@hakusaro) +* Added `TSPlayer` and `PlayerDeathReason` to `GetDataHandlers.PlayerDamage`. (@hakusaro) ## TShock 4.3.25 * Fixed a critical exploit in the Terraria protocol that could cause massive unpreventable world corruption as well as a number of other problems. Thanks to @bartico6 for reporting. Fixed by the efforts of @QuiCM, @hakusaro, and tips in the right directioon from @bartico6. diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 90b2e461..dfc53968 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -28,7 +28,6 @@ using TShockAPI.Localization; using static TShockAPI.GetDataHandlers; using TerrariaApi.Server; using Terraria.ObjectData; -using Terraria.ID; using Terraria.DataStructures; namespace TShockAPI @@ -36,7 +35,7 @@ namespace TShockAPI /// Bouncer is the TShock anti-hack and build guardian system internal sealed class Bouncer { - /// Constructor call initializes Bouncer & related functionality. + /// Constructor call initializes Bouncer and related functionality. /// A new Bouncer. internal Bouncer(TerrariaPlugin pluginInstance) { @@ -59,6 +58,75 @@ namespace TShockAPI GetDataHandlers.TileEdit.Register(OnTileEdit); } + /// Called when a player is damaged. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnPlayerDamage(object sender, GetDataHandlers.PlayerDamageEventArgs args) + { + byte id = args.ID; + short dmg = args.Damage; + bool pvp = args.PVP; + bool crit = args.Critical; + byte direction = args.Direction; + + if (id >= Main.maxPlayers || TShock.Players[id] == null) + { + args.Handled = true; + return; + } + + if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) + { + if (TShock.Config.KickOnDamageThresholdBroken) + { + TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); + args.Handled = true; + return; + } + else + { + args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); + } + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if (!TShock.Players[id].TPlayer.hostile && pvp && id != args.Player.Index) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if (TShock.CheckIgnores(args.Player)) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) + { + args.Player.SendData(PacketTypes.PlayerHp, "", id); + args.Player.SendData(PacketTypes.PlayerUpdate, "", id); + args.Handled = true; + return; + } + + } + /// Registered when items fall to the ground to prevent cheating. /// The object that triggered the event. /// The packet arguments that the event has. @@ -498,7 +566,7 @@ namespace TShockAPI } } - /// Handles ProjectileKill events for throttling & out of bounds projectiles. + /// Handles ProjectileKill events for throttling and out of bounds projectiles. /// The object that triggered the event. /// The packet arguments that the event has. internal void OnProjectileKill(object sender, GetDataHandlers.ProjectileKillEventArgs args) @@ -524,7 +592,7 @@ namespace TShockAPI } } - /// Handles disabling enforcement & minor anti-exploit stuff + /// Handles disabling enforcement and minor anti-exploit stuff /// The object that triggered the event. /// The packet arguments that the event has. internal void OnPlayerUpdate(object sender, GetDataHandlers.PlayerUpdateEventArgs args) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index cc472d38..27bd2dd8 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1161,6 +1161,7 @@ namespace TShockAPI /// public class PlayerDamageEventArgs : HandledEventArgs { + public TSPlayer Player { get; set; } /// /// The Terraria playerID of the player /// @@ -1181,24 +1182,28 @@ namespace TShockAPI /// Is the damage critical? /// public bool Critical { get; set; } + /// The reason the player took damage and/or died. + public PlayerDeathReason PlayerDeathReason { get; set; } } /// /// PlayerDamage - Called when a player is damaged /// public static HandlerList PlayerDamage; - private static bool OnPlayerDamage(byte id, byte dir, short dmg, bool pvp, bool crit) + private static bool OnPlayerDamage(TSPlayer player, byte id, byte dir, short dmg, bool pvp, bool crit, PlayerDeathReason playerDeathReason) { if (PlayerDamage == null) return false; var args = new PlayerDamageEventArgs { + Player = player, ID = id, Direction = dir, Damage = dmg, PVP = pvp, Critical = crit, + PlayerDeathReason = playerDeathReason, }; PlayerDamage.Invoke(null, args); return args.Handled; @@ -1421,7 +1426,6 @@ namespace TShockAPI { PacketTypes.ItemOwner, HandleItemOwner }, { PacketTypes.PlayerHp, HandlePlayerHp }, { PacketTypes.PlayerMana, HandlePlayerMana }, - { PacketTypes.PlayerDamage, HandlePlayerDamage }, { PacketTypes.NpcStrike, HandleNpcStrike }, { PacketTypes.NpcSpecial, HandleSpecial }, { PacketTypes.PlayerAnimation, HandlePlayerAnimation }, @@ -2560,76 +2564,6 @@ namespace TShockAPI return false; } - private static bool HandlePlayerDamage(GetDataHandlerArgs args) - { - var id = args.Data.ReadInt8(); - var direction = (byte)(args.Data.ReadInt8() - 1); - var dmg = args.Data.ReadInt16(); - args.Data.ReadString(); // don't store damage text - var bits = (BitsByte)args.Data.ReadInt8(); - var pvp = bits[0]; - var crit = bits[1]; - - if (OnPlayerDamage(id, direction, dmg, pvp, crit)) - return true; - - if (id >= Main.maxPlayers || TShock.Players[id] == null) - { - return true; - } - - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) - { - if (TShock.Config.KickOnDamageThresholdBroken) - { - TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); - return true; - } - else - { - args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); - } - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (!TShock.Players[id].TPlayer.hostile && pvp && id != args.Player.Index) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.Players[id].GodMode) - { - TShock.Players[id].Heal(args.TPlayer.statLifeMax); - } - - return false; - } - private static bool HandlePlayerDamageV2(GetDataHandlerArgs args) { var id = args.Data.ReadInt8(); @@ -2640,58 +2574,9 @@ namespace TShockAPI var crit = bits[0]; var pvp = bits[1]; - if (OnPlayerDamage(id, direction, dmg, pvp, crit)) + if (OnPlayerDamage(args.Player, id, direction, dmg, pvp, crit, playerDeathReason)) return true; - if (id >= Main.maxPlayers || TShock.Players[id] == null) - { - return true; - } - - if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) - { - if (TShock.Config.KickOnDamageThresholdBroken) - { - TShock.Utils.Kick(args.Player, string.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage)); - return true; - } - else - { - args.Player.Disable(String.Format("Player damage exceeded {0}.", TShock.Config.MaxDamage), DisableFlags.WriteToLogAndConsole); - } - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (!TShock.Players[id].TPlayer.hostile && pvp && id != args.Player.Index) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckIgnores(args.Player)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if (TShock.CheckRangePermission(args.Player, TShock.Players[id].TileX, TShock.Players[id].TileY, 100)) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - - if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000) - { - args.Player.SendData(PacketTypes.PlayerHp, "", id); - args.Player.SendData(PacketTypes.PlayerUpdate, "", id); - return true; - } - if (TShock.Players[id].GodMode) { TShock.Players[id].Heal(args.TPlayer.statLifeMax);