From bcbea04002d1a1fe3a7db774f1ee04b371189992 Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sat, 20 Oct 2018 17:48:50 +0800 Subject: [PATCH 1/8] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79f36e88..e97338de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Added filtering and validation on packet 96 (Teleport player through portal) (@QuiCM) * Update tracker now uses TLS (@pandabear41) * When deleting an user account, any player logged in to that account is now logged out properly (@Enerdy) +* Add NPCAddBuff data handler and bouncer (@AxeelAnder) ## 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. From 6b8f346868fb98d664710f5e83dc7512b90c1239 Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sat, 20 Oct 2018 12:48:05 +0800 Subject: [PATCH 2/8] add NPCAddBuff GetDataHandler --- TShockAPI/GetDataHandlers.cs | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index c59ce1a7..b3769e4e 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1003,6 +1003,46 @@ namespace TShockAPI NPCHome.Invoke(null, args); return args.Handled; } + + /// + /// For use in a NPCAddBuff event + /// + public class NPCAddBuffEventArgs : GetDataHandledEventArgs + { + /// + /// The ID of the npc + /// + public short ID { get; set; } + /// + /// Buff Type + /// + public byte Type { get; set; } + /// + /// Time the buff lasts + /// + public short Time { get; set; } + } + /// + /// NPCAddBuff - Called when a npc is buffed + /// + public static HandlerList NPCAddBuff = new HandlerList(); + + private static bool OnNPCAddBuff(TSPlayer player, MemoryStream data, short id, byte type, short time) + { + if (NPCAddBuff == null) + return false; + + var args = new NPCAddBuffEventArgs + { + Player = player, + Data = data, + ID = id, + Type = type, + Time = time + }; + NPCAddBuff.Invoke(null, args); + return args.Handled; + } /// /// For use in a PlayerBuff event @@ -1455,6 +1495,7 @@ namespace TShockAPI { PacketTypes.PlayerSlot, HandlePlayerSlot }, { PacketTypes.TileGetSection, HandleGetSection }, { PacketTypes.UpdateNPCHome, UpdateNPCHome }, + { PacketTypes.NpcAddBuff, HandleNPCAddBuff }, { PacketTypes.PlayerAddBuff, HandlePlayerAddBuff }, { PacketTypes.ItemDrop, HandleItemDrop }, { PacketTypes.UpdateItemDrop, HandleItemDrop }, @@ -2627,6 +2668,19 @@ namespace TShockAPI } return false; } + + private static bool HandleNPCAddBuff(GetDataHandlerArgs args) + { + var id = args.Data.ReadInt16(); + var type = args.Data.ReadInt8(); + var time = args.Data.ReadInt16(); + + if (OnNPCAddBuff(args.Player, args.Data, id, type, time)) + return true; + + args.Player.SendData(PacketTypes.NpcAddBuff, "", id); + return true; + } private static bool HandlePlayerAddBuff(GetDataHandlerArgs args) { From 87915b70b0e6be7484263bdebc19b5f208750ff8 Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sat, 20 Oct 2018 14:41:58 +0800 Subject: [PATCH 3/8] add ignoreNpcAddBuffPermission --- TShockAPI/Permissions.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index 7733f110..dec457d3 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -169,6 +169,9 @@ namespace TShockAPI [Description("Prevents you from being disabled by abnormal MP.")] public static readonly string ignoremp = "tshock.ignore.mp"; + + [Description("Prevents you from being disabled by add buffs to npcs abnormally.")] + public static readonly string ignorenpcaddbuffdetection = "tshock.ignore.npcaddbuff"; // tshock.item nodes From fc38521dbd4538cd0e644265799a141d9b6ba815 Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sat, 20 Oct 2018 13:21:38 +0800 Subject: [PATCH 4/8] add NPCAddBuff bouncer --- TShockAPI/Bouncer.cs | 32 ++++++++++++++++++++++++++++++++ TShockAPI/GetDataHandlers.cs | 3 +-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 223de05b..b71c7de8 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -49,6 +49,7 @@ namespace TShockAPI GetDataHandlers.PlayerAnimation += OnPlayerAnimation; GetDataHandlers.NPCStrike += OnNPCStrike; GetDataHandlers.ItemDrop += OnItemDrop; + GetDataHandlers.NPCAddBuff += OnNPCAddBuff; GetDataHandlers.PlayerBuff += OnPlayerBuff; GetDataHandlers.ChestItemChange += OnChestItemChange; GetDataHandlers.NPCHome += OnUpdateNPCHome; @@ -453,6 +454,37 @@ namespace TShockAPI return; } } + + /// Handles NPCAddBuff events. + /// The object that triggered the event. + /// The packet arguments that the event has. + internal void OnNPCAddBuff(object sender, GetDataHandlers.NPCAddBuffEventArgs args) + { + short id = args.ID; + byte type = args.Type; + short time = args.Time; + + if (id >= Main.npc.Length) + { + args.Handled = true; + return; + } + + NPC npc = Main.npc[id]; + + if (npc == null) + { + args.Handled = true; + return; + } + + if (args.Player.IsBeingDisabled()) + { + args.Player.SendData(PacketTypes.NpcAddBuff, "", id); + args.Handled = true; + return; + } + } /// Handles Buff events. /// The object that triggered the event. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index b3769e4e..6673dd64 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2677,8 +2677,7 @@ namespace TShockAPI if (OnNPCAddBuff(args.Player, args.Data, id, type, time)) return true; - - args.Player.SendData(PacketTypes.NpcAddBuff, "", id); + return true; } From b9dedd77dcb03a0e47ae0beeb12a7f19568beaad Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sat, 20 Oct 2018 17:44:34 +0800 Subject: [PATCH 5/8] add some anti-cheat code --- TShockAPI/Bouncer.cs | 60 +++++++++++++++++++++++++++++++++++- TShockAPI/GetDataHandlers.cs | 2 +- TShockAPI/TShock.cs | 32 +++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index b71c7de8..79dce7d1 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -480,10 +480,68 @@ namespace TShockAPI if (args.Player.IsBeingDisabled()) { - args.Player.SendData(PacketTypes.NpcAddBuff, "", id); args.Handled = true; return; } + + if (!args.Player.HasPermission(Permissions.ignorenpcaddbuffdetection)) + { + bool cheat = false; + + if(TShock.NPCAddBuffTimeMax.ContainsKey(type)) + { + if(time > TShock.NPCAddBuffTimeMax[type]) + { + cheat = true; + } + + if(npc.townNPC && npc.netID != NPCID.Guide && npc.netID != NPCID.Clothier) + { + if(type != BuffID.Lovestruck && type != BuffID.Stinky && type != BuffID.DryadsWard && + type != BuffID.Wet && type != BuffID.Slimed) + { + cheat = true; + } + } + // Want to check voodoo doll but it may be wrong. + //else if(npc.netID == NPCID.Guide) + //{ + // bool hasDoll = false; + // foreach (var item in args.Player.Accessories) + // { + // if (item.netID == ItemID.GuideVoodooDoll) + // { + // hasDoll = true; + // break; + // } + // } + // cheat = !hasDoll; + //} + //else if (npc.netID == NPCID.Clothier) + //{ + // bool hasDoll = false; + // foreach (var item in args.Player.Accessories) + // { + // if (item.netID == ItemID.ClothierVoodooDoll) + // { + // hasDoll = true; + // break; + // } + // } + // cheat = !hasDoll; + //} + } + else + { + cheat = true; + } + + if (cheat) + { + args.Player.Disable("Add buff to NPC abnormally.", DisableFlags.WriteToLogAndConsole); + args.Handled = true; + } + } } /// Handles Buff events. diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 6673dd64..a7792569 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2678,7 +2678,7 @@ namespace TShockAPI if (OnNPCAddBuff(args.Player, args.Data, id, type, time)) return true; - return true; + return false; } private static bool HandlePlayerAddBuff(GetDataHandlerArgs args) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index f839019d..18cff28e 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -131,6 +131,9 @@ namespace TShockAPI /// public static Dictionary RESTStartupTokens = new Dictionary(); + /// The longest time of buffs players can add to NPCs. + public static Dictionary NPCAddBuffTimeMax; + /// The TShock anti-cheat/anti-exploit system. internal Bouncer Bouncer; @@ -323,6 +326,7 @@ namespace TShockAPI RestApi = new SecureRest(Netplay.ServerIP, Config.RestApiPort); RestManager = new RestManager(RestApi); RestManager.RegisterRestfulCommands(); + NPCAddBuffTimeMax = InitNPCAddBuffTimeMax(); Bouncer = new Bouncer(); RegionSystem = new RegionHandler(Regions); @@ -385,6 +389,34 @@ namespace TShockAPI } } + private Dictionary InitNPCAddBuffTimeMax() + { + var dict = new Dictionary(); + + dict.Add(BuffID.Poisoned, 3600); + dict.Add(BuffID.OnFire, 1200); + dict.Add(BuffID.CursedInferno, 420); + dict.Add(BuffID.Frostburn, 900); + dict.Add(BuffID.Ichor, 1200); + dict.Add(BuffID.Venom, 1260); + dict.Add(BuffID.Midas, 120); + dict.Add(BuffID.Wet, 1500); + dict.Add(BuffID.Slimed, 1500); + dict.Add(BuffID.Lovestruck, 1800); + dict.Add(BuffID.Stinky, 1800); + dict.Add(BuffID.SoulDrain, 30); + dict.Add(BuffID.ShadowFlame, 660); + dict.Add(BuffID.DryadsWard, 120); + dict.Add(BuffID.BoneJavelin, 900); + dict.Add(BuffID.StardustMinionBleed, 900); + dict.Add(BuffID.DryadsWardDebuff, 120); + dict.Add(BuffID.Daybreak, 300); + dict.Add(BuffID.BetsysCurse, 600); + dict.Add(BuffID.Oiled, 540); + + return dict; + } + protected void CrashReporter_HeapshotRequesting(object sender, EventArgs e) { foreach (TSPlayer player in TShock.Players) From 6efa0d2bb6d0c53cc2094ca681236261429788b7 Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sat, 20 Oct 2018 20:07:04 +0800 Subject: [PATCH 6/8] better code --- TShockAPI/Bouncer.cs | 97 +++++++++++++++++++--------------------- TShockAPI/Permissions.cs | 3 -- TShockAPI/TShock.cs | 32 ------------- 3 files changed, 46 insertions(+), 86 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 79dce7d1..ba7c2c85 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -36,6 +36,31 @@ namespace TShockAPI /// Bouncer is the TShock anti-hack and anti-cheat system. internal sealed class Bouncer { + static Dictionary NPCAddBuffTimeMax = new Dictionary() + { + { BuffID.Poisoned, 3600 }, + { BuffID.OnFire, 1200 }, + { BuffID.CursedInferno, 420 }, + { BuffID.Frostburn, 900 }, + { BuffID.Ichor, 1200 }, + { BuffID.Venom, 1260 }, + { BuffID.Midas, 120 }, + { BuffID.Wet, 1500 }, + { BuffID.Slimed, 1500 }, + { BuffID.Lovestruck, 1800 }, + { BuffID.Stinky, 1800 }, + { BuffID.SoulDrain, 30 }, + { BuffID.ShadowFlame, 660 }, + { BuffID.DryadsWard, 120 }, + { BuffID.BoneJavelin, 900 }, + { BuffID.StardustMinionBleed, 900 }, + { BuffID.DryadsWardDebuff, 120 }, + { BuffID.Daybreak, 300 }, + { BuffID.BetsysCurse, 600 }, + { BuffID.Oiled, 540 } + }; + + /// Constructor call initializes Bouncer and related functionality. /// A new Bouncer. internal Bouncer() @@ -454,7 +479,7 @@ namespace TShockAPI return; } } - + /// Handles NPCAddBuff events. /// The object that triggered the event. /// The packet arguments that the event has. @@ -484,64 +509,34 @@ namespace TShockAPI return; } - if (!args.Player.HasPermission(Permissions.ignorenpcaddbuffdetection)) + bool cheat = false; + + if (NPCAddBuffTimeMax.ContainsKey(type)) { - bool cheat = false; - - if(TShock.NPCAddBuffTimeMax.ContainsKey(type)) - { - if(time > TShock.NPCAddBuffTimeMax[type]) - { - cheat = true; - } - - if(npc.townNPC && npc.netID != NPCID.Guide && npc.netID != NPCID.Clothier) - { - if(type != BuffID.Lovestruck && type != BuffID.Stinky && type != BuffID.DryadsWard && - type != BuffID.Wet && type != BuffID.Slimed) - { - cheat = true; - } - } - // Want to check voodoo doll but it may be wrong. - //else if(npc.netID == NPCID.Guide) - //{ - // bool hasDoll = false; - // foreach (var item in args.Player.Accessories) - // { - // if (item.netID == ItemID.GuideVoodooDoll) - // { - // hasDoll = true; - // break; - // } - // } - // cheat = !hasDoll; - //} - //else if (npc.netID == NPCID.Clothier) - //{ - // bool hasDoll = false; - // foreach (var item in args.Player.Accessories) - // { - // if (item.netID == ItemID.ClothierVoodooDoll) - // { - // hasDoll = true; - // break; - // } - // } - // cheat = !hasDoll; - //} - } - else + if (time > NPCAddBuffTimeMax[type]) { cheat = true; } - if (cheat) + if (npc.townNPC && npc.netID != NPCID.Guide && npc.netID != NPCID.Clothier) { - args.Player.Disable("Add buff to NPC abnormally.", DisableFlags.WriteToLogAndConsole); - args.Handled = true; + if (type != BuffID.Lovestruck && type != BuffID.Stinky && type != BuffID.DryadsWard && + type != BuffID.Wet && type != BuffID.Slimed) + { + cheat = true; + } } } + else + { + cheat = true; + } + + if (cheat) + { + args.Player.Disable("Add buff to NPC abnormally.", DisableFlags.WriteToLogAndConsole); + args.Handled = true; + } } /// Handles Buff events. diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index dec457d3..7733f110 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -169,9 +169,6 @@ namespace TShockAPI [Description("Prevents you from being disabled by abnormal MP.")] public static readonly string ignoremp = "tshock.ignore.mp"; - - [Description("Prevents you from being disabled by add buffs to npcs abnormally.")] - public static readonly string ignorenpcaddbuffdetection = "tshock.ignore.npcaddbuff"; // tshock.item nodes diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 18cff28e..f839019d 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -131,9 +131,6 @@ namespace TShockAPI /// public static Dictionary RESTStartupTokens = new Dictionary(); - /// The longest time of buffs players can add to NPCs. - public static Dictionary NPCAddBuffTimeMax; - /// The TShock anti-cheat/anti-exploit system. internal Bouncer Bouncer; @@ -326,7 +323,6 @@ namespace TShockAPI RestApi = new SecureRest(Netplay.ServerIP, Config.RestApiPort); RestManager = new RestManager(RestApi); RestManager.RegisterRestfulCommands(); - NPCAddBuffTimeMax = InitNPCAddBuffTimeMax(); Bouncer = new Bouncer(); RegionSystem = new RegionHandler(Regions); @@ -389,34 +385,6 @@ namespace TShockAPI } } - private Dictionary InitNPCAddBuffTimeMax() - { - var dict = new Dictionary(); - - dict.Add(BuffID.Poisoned, 3600); - dict.Add(BuffID.OnFire, 1200); - dict.Add(BuffID.CursedInferno, 420); - dict.Add(BuffID.Frostburn, 900); - dict.Add(BuffID.Ichor, 1200); - dict.Add(BuffID.Venom, 1260); - dict.Add(BuffID.Midas, 120); - dict.Add(BuffID.Wet, 1500); - dict.Add(BuffID.Slimed, 1500); - dict.Add(BuffID.Lovestruck, 1800); - dict.Add(BuffID.Stinky, 1800); - dict.Add(BuffID.SoulDrain, 30); - dict.Add(BuffID.ShadowFlame, 660); - dict.Add(BuffID.DryadsWard, 120); - dict.Add(BuffID.BoneJavelin, 900); - dict.Add(BuffID.StardustMinionBleed, 900); - dict.Add(BuffID.DryadsWardDebuff, 120); - dict.Add(BuffID.Daybreak, 300); - dict.Add(BuffID.BetsysCurse, 600); - dict.Add(BuffID.Oiled, 540); - - return dict; - } - protected void CrashReporter_HeapshotRequesting(object sender, EventArgs e) { foreach (TSPlayer player in TShock.Players) From e9372be276a79eefba10187ce6aa8a94bce35dfc Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Sat, 20 Oct 2018 09:14:38 -0700 Subject: [PATCH 7/8] Rename cheat var to detectedNPCBuffTimeCheat. --- TShockAPI/Bouncer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index ba7c2c85..395ecc36 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -509,13 +509,13 @@ namespace TShockAPI return; } - bool cheat = false; + bool detectedNPCBuffTimeCheat = false; if (NPCAddBuffTimeMax.ContainsKey(type)) { if (time > NPCAddBuffTimeMax[type]) { - cheat = true; + detectedNPCBuffTimeCheat = true; } if (npc.townNPC && npc.netID != NPCID.Guide && npc.netID != NPCID.Clothier) @@ -523,18 +523,18 @@ namespace TShockAPI if (type != BuffID.Lovestruck && type != BuffID.Stinky && type != BuffID.DryadsWard && type != BuffID.Wet && type != BuffID.Slimed) { - cheat = true; + detectedNPCBuffTimeCheat = true; } } } else { - cheat = true; + detectedNPCBuffTimeCheat = true; } - if (cheat) + if (detectedNPCBuffTimeCheat) { - args.Player.Disable("Add buff to NPC abnormally.", DisableFlags.WriteToLogAndConsole); + args.Player.Disable("Added buff to NPC abnormally.", DisableFlags.WriteToLogAndConsole); args.Handled = true; } } From f715d91dc6682991c11a941c6367af39d1bb1f53 Mon Sep 17 00:00:00 2001 From: AxeelAnder <1491773534@qq.com> Date: Sun, 21 Oct 2018 11:01:08 +0800 Subject: [PATCH 8/8] disable -> kick --- TShockAPI/Bouncer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 395ecc36..7287924f 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -534,7 +534,7 @@ namespace TShockAPI if (detectedNPCBuffTimeCheat) { - args.Player.Disable("Added buff to NPC abnormally.", DisableFlags.WriteToLogAndConsole); + args.Player.Kick("Added buff to NPC abnormally.", true); args.Handled = true; } }