Merge pull request #3134 from ACaiCat/fix-portal-exploit

feat(Bouncer): add portal validation to block portal exploit
This commit is contained in:
Chris 2026-01-18 15:47:59 +10:30 committed by GitHub
commit 30a79250d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1308,6 +1308,35 @@ namespace TShockAPI
return;
}
// Portal Gun Gate projectiles must meet several validation criteria:
// 1. The angle must be within valid discrete directions (45 degree increments)
// 2. Must have an active PortalGunBolt projectile associated
if (type == ProjectileID.PortalGunGate)
{
// Validate the gate angle is one of 8 possible cardinal directions (every 45 degrees)
var wrappedAngle = MathHelper.WrapAngle(ai[0]);
var discreteDirection = (int)Math.Round(wrappedAngle / (MathF.PI / 4f));
if (discreteDirection is < -3 or > 4)
{
TShock.Log.ConsoleDebug(GetString("Bouncer / OnNewProjectile rejected from portal gate from {0} (invalid angle: {1})", args.Player.Name, discreteDirection));
args.Player.RemoveProjectile(ident, owner);
args.Handled = true;
return;
}
// Validate we found an active bolt projectile
var boltProjectileData = args.Player.RecentlyCreatedProjectiles.FirstOrDefault(p => Main.projectile[p.Index].type == ProjectileID.PortalGunBolt);
if (boltProjectileData.Type == 0 || boltProjectileData.Killed)
{
TShock.Log.ConsoleDebug(GetString("Bouncer / OnNewProjectile rejected from portal gate from {0} (missing active Portal Gun bolt)", args.Player.Name, discreteDirection));
args.Player.RemoveProjectile(ident, owner);
args.Handled = true;
return;
}
boltProjectileData.Killed = true;
}
if (!TShock.Config.Settings.IgnoreProjUpdate && !args.Player.HasPermission(Permissions.ignoreprojectiledetection))
{
if (type == ProjectileID.BlowupSmokeMoonlord