diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs
index f32099ab..c0227d05 100755
--- a/TShockAPI/ConfigFile.cs
+++ b/TShockAPI/ConfigFile.cs
@@ -295,6 +295,10 @@ namespace TShockAPI
[Description("Disable a player if this number of projectiles is created within 1 second.")]
public int ProjectileThreshold = 50;
+ /// HealOtherThreshold - Disables a player if this number of HealOtherPlayer packets is sent within 1 second.
+ [Description("Disables a player if this number of HealOtherPlayer packets is sent within 1 second.")]
+ public int HealOtherThreshold = 50;
+
/// ProjIgnoreShrapnel - Whether or not to ignore shrapnel from crystal bullets for the projectile threshold count.
[Description("Ignore shrapnel from crystal bullets for projectile threshold.")]
public bool ProjIgnoreShrapnel = true;
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index 88b33fef..aae3839b 100755
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -1261,7 +1261,8 @@ namespace TShockAPI
{ PacketTypes.PlaceItemFrame, HandlePlaceItemFrame },
{ PacketTypes.SyncExtraValue, HandleSyncExtraValue },
{ PacketTypes.LoadNetModule, HandleLoadNetModule },
- { PacketTypes.ToggleParty, HandleToggleParty }
+ { PacketTypes.ToggleParty, HandleToggleParty },
+ { PacketTypes.PlayerHealOther, HandleHealOther }
};
}
@@ -1283,6 +1284,37 @@ namespace TShockAPI
return false;
}
+ private static bool HandleHealOther(GetDataHandlerArgs args)
+ {
+ byte plr = args.Data.ReadInt8();
+ short amount = args.Data.ReadInt16();
+
+ if (amount <= 0 || Main.player[plr] == null || !Main.player[plr].active)
+ {
+ return true;
+ }
+
+ if (amount > TShock.Config.MaxDamage * 0.2)
+ {
+ args.Player.Disable("HealOtherPlayer cheat attempt!", DisableFlags.WriteToLogAndConsole);
+ return true;
+ }
+
+ if (args.Player.HealOtherThreshold > TShock.Config.HealOtherThreshold)
+ {
+ args.Player.Disable("Reached HealOtherPlayer threshold.", DisableFlags.WriteToLogAndConsole);
+ return true;
+ }
+
+ if (TShock.CheckIgnores(args.Player) || (DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000)
+ {
+ return true;
+ }
+
+ args.Player.HealOtherThreshold++;
+ return false;
+ }
+
private static bool HandlePlayerSlot(GetDataHandlerArgs args)
{
byte plr = args.Data.ReadInt8();
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index ee2348f6..5addd336 100755
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -93,7 +93,12 @@ namespace TShockAPI
/// The number of projectiles created by the player in the last second.
///
public int ProjectileThreshold { get; set; }
-
+
+ ///
+ /// The number of HealOtherPlayer packets sent by the player in the last second.
+ ///
+ public int HealOtherThreshold { get; set; }
+
///
/// A timer to keep track of whether or not the player has recently thrown an explosive
///
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index ae5f7889..be37a462 100755
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -1030,6 +1030,15 @@ namespace TShockAPI
player.PaintThreshold = 0;
}
+ if (player.HealOtherThreshold >= TShock.Config.HealOtherThreshold)
+ {
+ player.Disable("Reached HealOtherPlayer threshold", flags);
+ }
+ if (player.HealOtherThreshold > 0)
+ {
+ player.HealOtherThreshold = 0;
+ }
+
if (player.RespawnTimer > 0 && --player.RespawnTimer == 0 && player.Difficulty != 2)
{
player.Spawn();
@@ -1458,7 +1467,7 @@ namespace TShockAPI
/// The CommandEventArgs object
private void ServerHooks_OnCommand(CommandEventArgs args)
{
- if (args.Handled)
+ if (args.Handled || string.IsNullOrWhiteSpace(args.Command))
return;
// Damn you ThreadStatic and Redigit