diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 488abe61..bf37110d 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -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 diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index fc6cebfe..1a51fc94 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -2734,8 +2734,11 @@ namespace TShockAPI if (OnPlayerSpawn(args.Player, args.Data, player, spawnX, spawnY, respawnTimer, numberOfDeathsPVE, numberOfDeathsPVP, context)) return true; - - args.Player.Dead = respawnTimer > 0; + + if (!Main.ServerSideCharacter || context != PlayerSpawnContext.SpawningIntoWorld) + { + args.Player.Dead = respawnTimer > 0; + } if (Main.ServerSideCharacter) { diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 99153deb..276ad338 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1263,6 +1263,11 @@ namespace TShockAPI /// True if allowed, otherwise false private bool OnCreep(int tileType) { + if (WorldGen.generatingWorld) + { + return true; + } + if (!Config.Settings.AllowCrimsonCreep && (tileType == TileID.Dirt || tileType == TileID.CrimsonGrass || TileID.Sets.Crimson[tileType])) { @@ -1456,7 +1461,7 @@ namespace TShockAPI if (!tsplr.FinishedHandshake) { - tsplr.Kick(GetString("Your client didn't send the right connection information."), true); + tsplr.Kick(GetString("Your client didn't send the right connection information."), true, true); args.Handled = true; return; }