diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs
index 64a0bec7..51e909e2 100755
--- a/TShockAPI/ConfigFile.cs
+++ b/TShockAPI/ConfigFile.cs
@@ -382,6 +382,12 @@ namespace TShockAPI
[Description("Whether bosses or invasions should be anonymously spawned.")]
public bool AnonymousBossInvasions = true;
+ [Description("The maximum allowable HP, before equipment buffs.")]
+ public int MaxHP = 500;
+
+ [Description("The maximum allowable MP, before equipment buffs.")]
+ public int MaxMP = 200;
+
///
/// Reads a configuration file from a given path
///
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index 88724a27..e4f1b684 100755
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -1229,6 +1229,7 @@ namespace TShockAPI
{ PacketTypes.UpdateNPCHome, UpdateNPCHome },
{ PacketTypes.PlayerAddBuff, HandlePlayerAddBuff },
{ PacketTypes.ItemDrop, HandleItemDrop },
+ { PacketTypes.ItemOwner, HandleItemOwner },
{ PacketTypes.PlayerHp, HandlePlayerHp },
{ PacketTypes.PlayerMana, HandlePlayerMana },
{ PacketTypes.PlayerDamage, HandlePlayerDamage },
@@ -1283,19 +1284,9 @@ namespace TShockAPI
bypassTrashCanCheck = true;
}
- if (OnPlayerSlot(plr, slot, stack, prefix, type))
+ if (OnPlayerSlot(plr, slot, stack, prefix, type) || plr != args.Player.Index || slot < 0 || slot > NetItem.maxNetInventory || args.Player.IgnoreSSCPackets)
return true;
- if (plr != args.Player.Index)
- {
- return true;
- }
-
- if (slot < 0 || slot > NetItem.maxNetInventory)
- {
- return true;
- }
-
// Garabage? Or will it cause some internal initialization or whatever?
var item = new Item();
item.netDefaults(type);
@@ -1305,10 +1296,9 @@ namespace TShockAPI
{
args.Player.PlayerData.StoreSlot(slot, type, prefix, stack);
}
- else if (
- Main.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck &&
- args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassssc)
- ) {
+ else if (Main.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck &&
+ args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassssc))
+ {
// The player might have moved an item to their trash can before they performed a single login attempt yet.
args.Player.IgnoreActionsForClearingTrashCan = true;
}
@@ -1328,16 +1318,12 @@ namespace TShockAPI
var cur = args.Data.ReadInt16();
var max = args.Data.ReadInt16();
- if (OnPlayerHP(plr, cur, max) || cur <= 0)
+ if (OnPlayerHP(plr, cur, max) || cur <= 0 || max <= 0 || args.Player.IgnoreSSCPackets)
return true;
- if (args.Player.FirstMaxHP == 0)
- args.Player.FirstMaxHP = max;
-
- if (cur < 0 || cur > 600 || max < 100 || max > 600) //Abnormal values have the potential to cause infinite loops in the server.
+ if ((max > TShock.Config.MaxHP || cur > max) && !args.Player.Group.HasPermission(Permissions.ignorehp))
{
- TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
- Log.ConsoleError("HP Exploit Attempt: Current HP {0}, Max HP {0}", cur, max);
+ args.Player.Disable("Maximum HP beyond limit");
return true;
}
@@ -1350,9 +1336,8 @@ namespace TShockAPI
if (args.Player.GodMode && (cur < max))
{
- args.Player.Heal(args.TPlayer.statLifeMax);
+ args.Player.Heal(args.TPlayer.statLifeMax2);
}
-
return false;
}
@@ -1362,11 +1347,14 @@ namespace TShockAPI
var cur = args.Data.ReadInt16();
var max = args.Data.ReadInt16();
- if (OnPlayerMana(plr, cur, max))
+ if (OnPlayerMana(plr, cur, max) || cur < 0 || max < 0 || args.Player.IgnoreSSCPackets)
return true;
- if (args.Player.FirstMaxMP == 0)
- args.Player.FirstMaxMP = max;
+ if ((max > TShock.Config.MaxMP || cur > max) && !args.Player.Group.HasPermission(Permissions.ignoremp))
+ {
+ args.Player.Disable("Maximum MP beyond limit");
+ return true;
+ }
if (args.Player.IsLoggedIn)
{
@@ -1374,7 +1362,6 @@ namespace TShockAPI
args.Player.TPlayer.statManaMax = max;
args.Player.PlayerData.maxMana = max;
}
-
return false;
}
@@ -3126,6 +3113,23 @@ namespace TShockAPI
return false;
}
+ private static bool HandleItemOwner(GetDataHandlerArgs args)
+ {
+ var id = args.Data.ReadInt16();
+ var owner = args.Data.ReadInt8();
+
+ if (id < 0 || id > 400)
+ return true;
+
+ if (id == 400 && owner == 255)
+ {
+ args.Player.IgnoreSSCPackets = false;
+ return true;
+ }
+
+ return false;
+ }
+
private static bool HandlePlayerDamage(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt8();
diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs
index 3edd76aa..4bb2b858 100644
--- a/TShockAPI/Permissions.cs
+++ b/TShockAPI/Permissions.cs
@@ -154,6 +154,12 @@ namespace TShockAPI
[Description("Allow dropping banned items without the item being eaten.")]
public static readonly string allowdroppingbanneditems = "tshock.ignore.dropbanneditem";
+ [Description("Prevents you from being disabled by abnormal HP.")]
+ public static readonly string ignorehp = "tshock.ignore.hp";
+
+ [Description("Prevents you from being disabled by abnormal MP.")]
+ public static readonly string ignoremp = "tshock.ignore.mp";
+
// tshock.item nodes
[Description("User can spawn items.")]
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index 1fa34a48..158dc5d7 100755
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -69,17 +69,20 @@ namespace TShockAPI
/// A timer to keep track of whether or not the player has recently thrown an explosive
///
public int RecentFuse = 0;
-
+
+ ///
+ /// Whether to ignore packets that are SSC-relevant.
+ ///
+ public bool IgnoreSSCPackets { get; set; }
+
///
/// A system to delay Remembered Position Teleports a few seconds
///
-
public int RPPending = 0;
public int sX = -1;
public int sY = -1;
-
///
/// A queue of tiles destroyed by the player for reverting.
///
@@ -90,10 +93,6 @@ namespace TShockAPI
///
public Dictionary TilesCreated { get; protected set; }
- public int FirstMaxHP { get; set; }
-
- public int FirstMaxMP { get; set; }
-
///
/// The player's group.
///
@@ -1300,6 +1299,9 @@ namespace TShockAPI
public void RestoreCharacter(TSPlayer player)
{
+ // Start ignoring SSC-related packets! This is critical so that we don't send or receive dirty data!
+ player.IgnoreSSCPackets = true;
+
player.TPlayer.statLife = this.health;
player.TPlayer.statLifeMax = this.maxHealth;
player.TPlayer.statMana = this.maxMana;
@@ -1461,6 +1463,8 @@ namespace TShockAPI
NetMessage.SendData(50, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(50, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(76, -1, -1, "", player.Index);
+
+ NetMessage.SendData(39, player.Index, -1, "", 400);
}
}
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index dc6b6843..3e7e66e5 100755
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -1166,7 +1166,7 @@ namespace TShockAPI
}
if ((player.State < 10 || player.Dead) && (int) type > 12 && (int) type != 16 && (int) type != 42 && (int) type != 50 &&
- (int) type != 38 && (int) type != 21)
+ (int) type != 38 && (int) type != 21 && (int) type != 22)
{
e.Handled = true;
return;