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;