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);