From 23fd7acd79f023a7c71c47d9798fd4bd2c62ff1c Mon Sep 17 00:00:00 2001 From: James Puleo Date: Sat, 26 Mar 2022 16:48:58 -0400 Subject: [PATCH] Improve `OnPlayerBuff` logic to properly handle buffs from other players Previously, we checked if the target player was null, before checking if their ID was out of bounds, so the check was moved to be first. We now check if the buff being applied is within bounds. We introduce `AddPlayerBuffWhitelist` to replace `WhitelistBuffMaxTime`, which allows us to specify a maximum amount of ticks a buff can be applied to another player for, and if it can be applied without the target being in PvP. If a buff is not within this array, it is *not* allowed to be applied by other players. When rejecting from `OnPlayerBuff`, we send a `PlayerBuff` instead of `PlayerAddBuff`, to sync the current buffs of the target, without syncing the rejected one. --- TShockAPI/Bouncer.cs | 274 +++++++++++++++++++++++++++++++---- TShockAPI/GetDataHandlers.cs | 12 -- 2 files changed, 244 insertions(+), 42 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 469b6ee9..efe21554 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -44,6 +44,27 @@ namespace TShockAPI internal Handlers.LandGolfBallInCupHandler LandGolfBallInCupHandler { get; private set; } internal Handlers.SyncTilePickingHandler SyncTilePickingHandler { get; private set; } + /// + /// A class that represents the limits for a particular buff when a client applies it with PlayerAddBuff. + /// + internal class BuffLimit + { + /// + /// How many ticks at the maximum a player can apply this to another player for. + /// + public int MaxTicks { get; set; } + /// + /// Can this buff be added without the receiver being hostile (PvP) + /// + public bool CanBeAddedWithoutHostile { get; set; } + /// + /// Can this buff only be applied to the sender? + /// + public bool CanOnlyBeAppliedToSender { get; set; } + } + + internal static BuffLimit[] PlayerAddBuffWhitelist; + /// /// Represents a place style corrector. /// @@ -231,6 +252,172 @@ namespace TShockAPI return actualItemPlaceStyle; } }); + + #region PlayerAddBuff Whitelist + + PlayerAddBuffWhitelist = new BuffLimit[Main.maxBuffTypes]; + PlayerAddBuffWhitelist[BuffID.Poisoned] = new BuffLimit + { + MaxTicks = 60 * 60 + }; + PlayerAddBuffWhitelist[BuffID.OnFire] = new BuffLimit + { + MaxTicks = 60 * 20 + }; + PlayerAddBuffWhitelist[BuffID.Confused] = new BuffLimit + { + MaxTicks = 60 * 4 + }; + PlayerAddBuffWhitelist[BuffID.CursedInferno] = new BuffLimit + { + MaxTicks = 60 * 7 + }; + PlayerAddBuffWhitelist[BuffID.Wet] = new BuffLimit + { + MaxTicks = 60 * 30, + // The Water Gun can be shot at other players and inflict Wet while not in PvP + CanBeAddedWithoutHostile = true + }; + PlayerAddBuffWhitelist[BuffID.Ichor] = new BuffLimit + { + MaxTicks = 60 * 20 + }; + PlayerAddBuffWhitelist[BuffID.Venom] = new BuffLimit + { + MaxTicks = 60 * 30 + }; + PlayerAddBuffWhitelist[BuffID.GelBalloonBuff] = new BuffLimit + { + MaxTicks = 60 * 30, + // The Sparkle Slime Balloon inflicts this while not in PvP + CanBeAddedWithoutHostile = true + }; + PlayerAddBuffWhitelist[BuffID.Frostburn] = new BuffLimit + { + MaxTicks = 60 * 8 + }; + PlayerAddBuffWhitelist[BuffID.Campfire] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.Sunflower] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.WaterCandle] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.BeetleEndurance1] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.BeetleEndurance2] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.BeetleEndurance3] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.BeetleMight1] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.BeetleMight2] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.BeetleMight3] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true, + }; + PlayerAddBuffWhitelist[BuffID.SolarShield1] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = false, + }; + PlayerAddBuffWhitelist[BuffID.SolarShield2] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = false, + }; + PlayerAddBuffWhitelist[BuffID.SolarShield3] = new BuffLimit + { + MaxTicks = 5, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = false, + }; + PlayerAddBuffWhitelist[BuffID.MonsterBanner] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true + }; + PlayerAddBuffWhitelist[BuffID.HeartLamp] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true + }; + PlayerAddBuffWhitelist[BuffID.PeaceCandle] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true + }; + PlayerAddBuffWhitelist[BuffID.StarInBottle] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true + }; + PlayerAddBuffWhitelist[BuffID.CatBast] = new BuffLimit + { + MaxTicks = 2, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true + }; + PlayerAddBuffWhitelist[BuffID.OnFire3] = new BuffLimit + { + MaxTicks = 60 * 5, + CanBeAddedWithoutHostile = false, + CanOnlyBeAppliedToSender = false + }; + PlayerAddBuffWhitelist[BuffID.HeartyMeal] = new BuffLimit + { + MaxTicks = 60 * 7, + CanBeAddedWithoutHostile = true, + CanOnlyBeAppliedToSender = true + }; + PlayerAddBuffWhitelist[BuffID.Frostburn2] = new BuffLimit + { + MaxTicks = 60 * 7, + CanBeAddedWithoutHostile = false, + CanOnlyBeAppliedToSender = false + }; + + #endregion Whitelist } internal void OnGetSection(object sender, GetDataHandlers.GetSectionEventArgs args) @@ -1640,9 +1827,24 @@ namespace TShockAPI int type = args.Type; int time = args.Time; + if (id >= Main.maxPlayers) + { + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected player cap from {0}", args.Player.Name); + args.Handled = true; + return; + } + if (TShock.Players[id] == null) { - TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected null check"); + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected null check from {0}", args.Player.Name); + args.Handled = true; + return; + } + + if (type >= Main.maxBuffTypes) + { + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected invalid buff type {0}", args.Player.Name); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); args.Handled = true; return; } @@ -1650,31 +1852,7 @@ namespace TShockAPI if (args.Player.IsBeingDisabled()) { TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected disabled from {0}", args.Player.Name); - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - args.Handled = true; - return; - } - - if (id >= Main.maxPlayers) - { - TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected player cap from {0}", args.Player.Name); - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - args.Handled = true; - return; - } - - if (!TShock.Players[id].TPlayer.hostile || !Main.pvpBuff[type]) - { - TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected hostile/pvp from {0}", args.Player.Name); - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); - args.Handled = true; - return; - } - - if (!args.Player.IsInRange(TShock.Players[id].TileX, TShock.Players[id].TileY, 50)) - { - TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected range check from {0}", args.Player.Name); - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); args.Handled = true; return; } @@ -1682,15 +1860,51 @@ namespace TShockAPI if (args.Player.IsBouncerThrottled()) { TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected throttled from {0}", args.Player.Name); - args.Player.SendData(PacketTypes.PlayerAddBuff, "", id); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); args.Handled = true; return; } - if (WhitelistBuffMaxTime[type] > 0 && time <= WhitelistBuffMaxTime[type]) + var targetPlayer = TShock.Players[id]; + var buffLimit = PlayerAddBuffWhitelist[type]; + + if (!args.Player.IsInRange(targetPlayer.TileX, targetPlayer.TileY, 50)) { - TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected buff time whitelists from {0}", args.Player.Name); - args.Handled = false; + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected range check from {0}", args.Player.Name); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + args.Handled = true; + return; + } + + if (buffLimit == null) + { + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected non-whitelisted buff {0}", args.Player.Name); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + args.Handled = true; + return; + } + + if (buffLimit.CanOnlyBeAppliedToSender && id != args.Player.Index) + { + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected applied to non-sender from {0}", args.Player.Name); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + args.Handled = true; + return; + } + + if (!buffLimit.CanBeAddedWithoutHostile && !targetPlayer.TPlayer.hostile) + { + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected hostile/pvp from {0}", args.Player.Name); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + args.Handled = true; + return; + } + + if (time <= 0 || time > buffLimit.MaxTicks) + { + TShock.Log.ConsoleDebug("Bouncer / OnPlayerBuff rejected time too long from {0}", args.Player.Name); + args.Player.SendData(PacketTypes.PlayerBuff, "", id); + args.Handled = true; return; } } diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 0770eda0..e1d34934 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -79,20 +79,8 @@ namespace TShockAPI { private static Dictionary GetDataHandlerDelegates; - public static int[] WhitelistBuffMaxTime; - public static void InitGetDataHandler() { - #region Blacklists - - WhitelistBuffMaxTime = new int[Main.maxBuffTypes]; - WhitelistBuffMaxTime[20] = 600; - WhitelistBuffMaxTime[0x18] = 1200; - WhitelistBuffMaxTime[0x1f] = 120; - WhitelistBuffMaxTime[0x27] = 420; - - #endregion Blacklists - GetDataHandlerDelegates = new Dictionary { { PacketTypes.PlayerInfo, HandlePlayerInfo },