Merge remote-tracking branch 'drunderscore/fix/add-player-buff' into general-devel

This commit is contained in:
Lucas Nicodemus 2022-10-14 23:49:15 -07:00
commit 20fb5023c1
No known key found for this signature in database
3 changed files with 251 additions and 44 deletions

View file

@ -49,6 +49,12 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
* Allowed the Axe of Regrowth and the Rubblemaker to pass Bouncer checks. (@drunderscore)
* The Axe of Regrowth places a `Saplings` where a tree used to be, which previously failed.
* The Rubblemaker places rubble (which are echo piles), of varying styles, which previously failed.
* Fixed `HandlePlayerAddBuff` data handler always being marked as `Handled`, and therefore never allowing the `PlayerAddBuff` to be sent to anyone. (@drunderscore)
* Improved `OnPlayerBuff` logic to properly handle players adding buffs to other players. (@drunderscore)
* Check if the target ID is within bounds as the first thing to check.
* Check if the buff type being applied is within bounds.
* Introduce `AddPlayerBuffWhitelist` (replacing `WhitelistBuffMaxTime`), which allows us to specify the maximum amount of ticks a buff can be applied for, and if it can be applied without the target being in PvP.
* When rejecting from `OnPlayerBuff`, instead of sending a `PlayerAddBuff` packet with the rejected buff (essentially a no-op, as the sender implicitly applies the buff to the target, and causes desync as the buff was rejected), send a `PlayerBuff` to re-sync the target's buffs, without the buff we just rejected.
## TShock 4.5.18
* Fixed `TSPlayer.GiveItem` not working if the player is in lava. (@PotatoCider)

View file

@ -44,6 +44,27 @@ namespace TShockAPI
internal Handlers.LandGolfBallInCupHandler LandGolfBallInCupHandler { get; private set; }
internal Handlers.SyncTilePickingHandler SyncTilePickingHandler { get; private set; }
/// <summary>
/// A class that represents the limits for a particular buff when a client applies it with PlayerAddBuff.
/// </summary>
internal class BuffLimit
{
/// <summary>
/// How many ticks at the maximum a player can apply this to another player for.
/// </summary>
public int MaxTicks { get; set; }
/// <summary>
/// Can this buff be added without the receiver being hostile (PvP)
/// </summary>
public bool CanBeAddedWithoutHostile { get; set; }
/// <summary>
/// Can this buff only be applied to the sender?
/// </summary>
public bool CanOnlyBeAppliedToSender { get; set; }
}
internal static BuffLimit[] PlayerAddBuffWhitelist;
/// <summary>
/// Represents a place style corrector.
/// </summary>
@ -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)
@ -1675,9 +1862,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;
}
@ -1685,31 +1887,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;
}
@ -1717,15 +1895,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;
}
}

View file

@ -79,20 +79,8 @@ namespace TShockAPI
{
private static Dictionary<PacketTypes, GetDataHandlerDelegate> 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, GetDataHandlerDelegate>
{
{ PacketTypes.PlayerInfo, HandlePlayerInfo },
@ -3467,8 +3455,7 @@ namespace TShockAPI
if (OnPlayerBuff(args.Player, args.Data, id, type, time))
return true;
args.Player.SendData(PacketTypes.PlayerAddBuff, "", id);
return true;
return false;
}
private static bool HandleUpdateNPCHome(GetDataHandlerArgs args)