Add permission to ignore max HP/MP, add config option for max HP/MP, possibly fix SSC

Fixing SSC is done by sending packet 39 (item disown) to the client.
Until a response, which is packet 22, is received from the client, all
SSC-related packets are completely ignored. This ensures that the SSC
data which is sent is not dirtied due to packets which are processed
during RestoreCharacter or slightly afterwards.
This commit is contained in:
MarioE 2014-07-28 23:40:27 -04:00
parent 7a8422de5c
commit fd5c696656
5 changed files with 56 additions and 36 deletions

View file

@ -382,6 +382,12 @@ namespace TShockAPI
[Description("Whether bosses or invasions should be anonymously spawned.")] [Description("Whether bosses or invasions should be anonymously spawned.")]
public bool AnonymousBossInvasions = true; 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;
/// <summary> /// <summary>
/// Reads a configuration file from a given path /// Reads a configuration file from a given path
/// </summary> /// </summary>

View file

@ -1229,6 +1229,7 @@ namespace TShockAPI
{ PacketTypes.UpdateNPCHome, UpdateNPCHome }, { PacketTypes.UpdateNPCHome, UpdateNPCHome },
{ PacketTypes.PlayerAddBuff, HandlePlayerAddBuff }, { PacketTypes.PlayerAddBuff, HandlePlayerAddBuff },
{ PacketTypes.ItemDrop, HandleItemDrop }, { PacketTypes.ItemDrop, HandleItemDrop },
{ PacketTypes.ItemOwner, HandleItemOwner },
{ PacketTypes.PlayerHp, HandlePlayerHp }, { PacketTypes.PlayerHp, HandlePlayerHp },
{ PacketTypes.PlayerMana, HandlePlayerMana }, { PacketTypes.PlayerMana, HandlePlayerMana },
{ PacketTypes.PlayerDamage, HandlePlayerDamage }, { PacketTypes.PlayerDamage, HandlePlayerDamage },
@ -1283,19 +1284,9 @@ namespace TShockAPI
bypassTrashCanCheck = true; 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; 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? // Garabage? Or will it cause some internal initialization or whatever?
var item = new Item(); var item = new Item();
item.netDefaults(type); item.netDefaults(type);
@ -1305,10 +1296,9 @@ namespace TShockAPI
{ {
args.Player.PlayerData.StoreSlot(slot, type, prefix, stack); args.Player.PlayerData.StoreSlot(slot, type, prefix, stack);
} }
else if ( else if (Main.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck &&
Main.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck && args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassssc))
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. // The player might have moved an item to their trash can before they performed a single login attempt yet.
args.Player.IgnoreActionsForClearingTrashCan = true; args.Player.IgnoreActionsForClearingTrashCan = true;
} }
@ -1328,16 +1318,12 @@ namespace TShockAPI
var cur = args.Data.ReadInt16(); var cur = args.Data.ReadInt16();
var max = 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; return true;
if (args.Player.FirstMaxHP == 0) if ((max > TShock.Config.MaxHP || cur > max) && !args.Player.Group.HasPermission(Permissions.ignorehp))
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.
{ {
TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true); args.Player.Disable("Maximum HP beyond limit");
Log.ConsoleError("HP Exploit Attempt: Current HP {0}, Max HP {0}", cur, max);
return true; return true;
} }
@ -1350,9 +1336,8 @@ namespace TShockAPI
if (args.Player.GodMode && (cur < max)) if (args.Player.GodMode && (cur < max))
{ {
args.Player.Heal(args.TPlayer.statLifeMax); args.Player.Heal(args.TPlayer.statLifeMax2);
} }
return false; return false;
} }
@ -1362,11 +1347,14 @@ namespace TShockAPI
var cur = args.Data.ReadInt16(); var cur = args.Data.ReadInt16();
var max = 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; return true;
if (args.Player.FirstMaxMP == 0) if ((max > TShock.Config.MaxMP || cur > max) && !args.Player.Group.HasPermission(Permissions.ignoremp))
args.Player.FirstMaxMP = max; {
args.Player.Disable("Maximum MP beyond limit");
return true;
}
if (args.Player.IsLoggedIn) if (args.Player.IsLoggedIn)
{ {
@ -1374,7 +1362,6 @@ namespace TShockAPI
args.Player.TPlayer.statManaMax = max; args.Player.TPlayer.statManaMax = max;
args.Player.PlayerData.maxMana = max; args.Player.PlayerData.maxMana = max;
} }
return false; return false;
} }
@ -3126,6 +3113,23 @@ namespace TShockAPI
return false; 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) private static bool HandlePlayerDamage(GetDataHandlerArgs args)
{ {
var id = args.Data.ReadInt8(); var id = args.Data.ReadInt8();

View file

@ -154,6 +154,12 @@ namespace TShockAPI
[Description("Allow dropping banned items without the item being eaten.")] [Description("Allow dropping banned items without the item being eaten.")]
public static readonly string allowdroppingbanneditems = "tshock.ignore.dropbanneditem"; 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 // tshock.item nodes
[Description("User can spawn items.")] [Description("User can spawn items.")]

View file

@ -69,17 +69,20 @@ namespace TShockAPI
/// A timer to keep track of whether or not the player has recently thrown an explosive /// A timer to keep track of whether or not the player has recently thrown an explosive
/// </summary> /// </summary>
public int RecentFuse = 0; public int RecentFuse = 0;
/// <summary>
/// Whether to ignore packets that are SSC-relevant.
/// </summary>
public bool IgnoreSSCPackets { get; set; }
/// <summary> /// <summary>
/// A system to delay Remembered Position Teleports a few seconds /// A system to delay Remembered Position Teleports a few seconds
/// </summary> /// </summary>
public int RPPending = 0; public int RPPending = 0;
public int sX = -1; public int sX = -1;
public int sY = -1; public int sY = -1;
/// <summary> /// <summary>
/// A queue of tiles destroyed by the player for reverting. /// A queue of tiles destroyed by the player for reverting.
/// </summary> /// </summary>
@ -90,10 +93,6 @@ namespace TShockAPI
/// </summary> /// </summary>
public Dictionary<Vector2, Tile> TilesCreated { get; protected set; } public Dictionary<Vector2, Tile> TilesCreated { get; protected set; }
public int FirstMaxHP { get; set; }
public int FirstMaxMP { get; set; }
/// <summary> /// <summary>
/// The player's group. /// The player's group.
/// </summary> /// </summary>
@ -1300,6 +1299,9 @@ namespace TShockAPI
public void RestoreCharacter(TSPlayer player) 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.statLife = this.health;
player.TPlayer.statLifeMax = this.maxHealth; player.TPlayer.statLifeMax = this.maxHealth;
player.TPlayer.statMana = this.maxMana; 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, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
NetMessage.SendData(50, player.Index, -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(76, -1, -1, "", player.Index);
NetMessage.SendData(39, player.Index, -1, "", 400);
} }
} }

View file

@ -1166,7 +1166,7 @@ namespace TShockAPI
} }
if ((player.State < 10 || player.Dead) && (int) type > 12 && (int) type != 16 && (int) type != 42 && (int) type != 50 && 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; e.Handled = true;
return; return;