diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9b2cfe8b..b5880543 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
## TShock 4.3.26
* Removed the stat tracking system. (@hakusaro)
+* Updated SQLite binaries. (@hakusaro)
+* Removed server-sided healing when disabled. (@QuiCM)
+* Patched an exploit that allowed users to kill town NPCs (@QuiCM)
+* [API] Added a patch for the 0-length crash (@QuiCM)
## 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/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index 0bb216e1..99264206 100644
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -1230,8 +1230,7 @@ namespace TShockAPI
{ PacketTypes.ProjectileNew, HandleProjectileNew },
{ PacketTypes.TogglePvp, HandleTogglePvp },
{ PacketTypes.PlayerTeam, HandlePlayerTeam },
- { PacketTypes.TileKill, HandleTileKill },
- { PacketTypes.PlayerKillMe, HandlePlayerKillMe },
+ { PacketTypes.PlaceChest, HandlePlaceChest },
{ PacketTypes.LiquidSet, HandleLiquidSet },
{ PacketTypes.PlayerSpawn, HandleSpawn },
{ PacketTypes.ChestGetContents, HandleChestOpen },
@@ -1247,7 +1246,7 @@ namespace TShockAPI
{ PacketTypes.ItemOwner, HandleItemOwner },
{ PacketTypes.PlayerHp, HandlePlayerHp },
{ PacketTypes.PlayerMana, HandlePlayerMana },
- { PacketTypes.PlayerDamage, HandlePlayerDamage },
+ { PacketTypes.NpcItemStrike, HandleNpcItemStrike },
{ PacketTypes.NpcStrike, HandleNpcStrike },
{ PacketTypes.NpcSpecial, HandleSpecial },
{ PacketTypes.PlayerAnimation, HandlePlayerAnimation },
@@ -2861,14 +2860,6 @@ namespace TShockAPI
var type = Main.projectile[index].type;
- // Players can no longer destroy projectiles that are not theirs as of 1.1.2
- /*if (args.Player.Index != Main.projectile[index].owner && type != 102 && type != 100 && !TShock.Config.IgnoreProjKill) // workaround for skeletron prime projectiles
- {
- args.Player.Disable(String.Format("Owner ({0}) and player ID ({1}) does not match to kill projectile of type: {3}", Main.projectile[index].owner, args.Player.Index, type));
- args.Player.RemoveProjectile(ident, owner);
- return true;
- }*/
-
if (TShock.CheckIgnores(args.Player))
{
args.Player.RemoveProjectile(ident, owner);
@@ -2893,71 +2884,6 @@ namespace TShockAPI
return false;
}
- private static bool HandlePlayerKillMe(GetDataHandlerArgs args)
- {
- var id = args.Data.ReadInt8();
- var direction = (byte)(args.Data.ReadInt8() - 1);
- var dmg = args.Data.ReadInt16();
- var pvp = args.Data.ReadInt8() == 0;
- var text = args.Data.ReadString();
- if (dmg > 20000) //Abnormal values have the potential to cause infinite loops in the server.
- {
- TShock.Utils.ForceKick(args.Player, "Crash Exploit Attempt", true);
- TShock.Log.ConsoleError("Death Exploit Attempt: Damage {0}", dmg);
- return false;
- }
-
- if (id >= Main.maxPlayers)
- {
- return true;
- }
-
- if (OnKillMe(id, direction, dmg, pvp))
- return true;
-
- if (text.Length > 500)
- {
- TShock.Utils.Kick(TShock.Players[id], "Crash attempt", true);
- return true;
- }
-
- args.Player.Dead = true;
- args.Player.RespawnTimer = TShock.Config.RespawnSeconds;
-
- foreach (NPC npc in Main.npc)
- {
- if (npc.active && (npc.boss || npc.type == 13 || npc.type == 14 || npc.type == 15) &&
- Math.Abs(args.TPlayer.Center.X - npc.Center.X) + Math.Abs(args.TPlayer.Center.Y - npc.Center.Y) < 4000f)
- {
- args.Player.RespawnTimer = TShock.Config.RespawnBossSeconds;
- break;
- }
- }
-
- if (args.TPlayer.difficulty == 2 && (TShock.Config.KickOnHardcoreDeath || TShock.Config.BanOnHardcoreDeath))
- {
- if (TShock.Config.BanOnHardcoreDeath)
- {
- if (!TShock.Utils.Ban(args.Player, TShock.Config.HardcoreBanReason, false, "hardcore-death"))
- TShock.Utils.ForceKick(args.Player, "Death results in a ban, but you are immune to bans.", true);
- }
- else
- {
- TShock.Utils.ForceKick(args.Player, TShock.Config.HardcoreKickReason, true, false);
- }
- }
-
- if (args.TPlayer.difficulty == 2 && Main.ServerSideCharacter && args.Player.IsLoggedIn)
- {
- if (TShock.CharacterDB.RemovePlayer(args.Player.User.ID))
- {
- TShock.CharacterDB.SeedInitialData(args.Player.User);
- }
- }
-
- return false;
- }
-
private static bool HandlePlayerKillMeV2(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt8();
@@ -3021,6 +2947,8 @@ namespace TShockAPI
}
}
+ //Attempt to resolve issue where player's slected items sometime fail to stop rendering when they die (eg chainsaws)
+ NetMessage.SendData((int)PacketTypes.PlayerUpdate, -1, args.Player.Index, NetworkText.Empty, args.Player.Index);
return false;
}
@@ -3149,7 +3077,7 @@ namespace TShockAPI
return false;
}
- private static bool HandleTileKill(GetDataHandlerArgs args)
+ private static bool HandlePlaceChest(GetDataHandlerArgs args)
{
int flag = args.Data.ReadByte();
int tileX = args.Data.ReadInt16();
@@ -3550,76 +3478,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();
@@ -3649,8 +3507,6 @@ namespace TShockAPI
{
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;
}
@@ -3663,22 +3519,16 @@ namespace TShockAPI
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;
}
@@ -3690,6 +3540,69 @@ namespace TShockAPI
return false;
}
+ private static bool HandleNpcItemStrike(GetDataHandlerArgs args)
+ {
+ var npcId = args.Data.ReadInt16();
+
+ if (npcId < 0 || npcId > Main.npc.Length)
+ {
+ //Need a valid npc
+ return true;
+ }
+
+ if (Main.npc[npcId] == null || Main.npc[npcId].active == false)
+ {
+ //Only allow striking valid NPCs
+ return true;
+ }
+
+ var item = args.Player.SelectedItem ?? args.Player.ItemInHand;
+ if (item == null)
+ {
+ //Shouldn't be able to strike an NPC without holding an item
+ return true;
+ }
+
+ var direction = args.TPlayer.direction;
+ var dmg = item.damage;
+ var knockback = item.knockBack;
+
+ //Clients can spoof item damage and it won't be reflected on the server. There's no point checking item damage unless this is changed
+
+ if (OnNPCStrike(npcId, (byte)direction, (short)item.damage, item.knockBack, 0))
+ {
+ return true;
+ }
+
+ if (TShock.CheckIgnores(args.Player))
+ {
+ args.Player.SendData(PacketTypes.NpcUpdate, "", npcId);
+ return true;
+ }
+
+ if (Main.npc[npcId].townNPC && !args.Player.HasPermission(Permissions.hurttownnpc))
+ {
+ args.Player.SendErrorMessage("You do not have permission to hurt this NPC.");
+ args.Player.SendData(PacketTypes.NpcUpdate, "", npcId);
+ return true;
+ }
+
+ if (TShock.Config.RangeChecks &&
+ TShock.CheckRangePermission(args.Player, (int)(Main.npc[npcId].position.X / 16f), (int)(Main.npc[npcId].position.Y / 16f), 128))
+ {
+ args.Player.SendData(PacketTypes.NpcUpdate, "", npcId);
+ return true;
+ }
+
+ if ((DateTime.UtcNow - args.Player.LastThreat).TotalMilliseconds < 5000)
+ {
+ args.Player.SendData(PacketTypes.NpcUpdate, "", npcId);
+ return true;
+ }
+
+ return false;
+ }
+
private static bool HandleNpcStrike(GetDataHandlerArgs args)
{
var id = args.Data.ReadInt16();
@@ -3769,6 +3682,12 @@ namespace TShockAPI
return true;
}
+ if (type == 4 && (id < 0 || id > Main.npc.Length))
+ {
+ //Type == 4 -> 'BigMimicSpawnSmoke'. This access Main.npc without any bounds checking on Terraria's side.
+ return true;
+ }
+
return false;
}
diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj
index 64aad29d..46bee4d8 100644
--- a/TShockAPI/TShockAPI.csproj
+++ b/TShockAPI/TShockAPI.csproj
@@ -68,9 +68,8 @@
..\packages\MySql.Data.6.9.8\lib\net45\MySql.Data.dll
True
-
- ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
False
@@ -203,7 +202,7 @@
-
+