diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs
index 7287924f..bb9937a6 100644
--- a/TShockAPI/Bouncer.cs
+++ b/TShockAPI/Bouncer.cs
@@ -83,6 +83,7 @@ namespace TShockAPI
GetDataHandlers.LiquidSet += OnLiquidSet;
GetDataHandlers.ProjectileKill += OnProjectileKill;
GetDataHandlers.PlayerUpdate += OnPlayerUpdate;
+ GetDataHandlers.PlayerZone += OnPlayerZone;
GetDataHandlers.KillMe += OnKillMe;
GetDataHandlers.NewProjectile += OnNewProjectile;
GetDataHandlers.PlaceObject += OnPlaceObject;
@@ -1000,6 +1001,40 @@ namespace TShockAPI
return;
}
+ /// Handles PlayerZone events for preventing spawning NPC maliciously.
+ /// The object that triggered the event.
+ /// The packet arguments that the event has.
+ internal void OnPlayerZone(object sender, GetDataHandlers.PlayerZoneEventArgs args)
+ {
+ bool hasSolarTower = false;
+ bool hasVortexTower = false;
+ bool hasNebulaTower = false;
+ bool hasStardustTower = false;
+
+ // May need to optimize
+ foreach (var npc in Main.npc)
+ {
+ if (npc.netID == NPCID.LunarTowerSolar)
+ hasSolarTower = true;
+ else if (npc.netID == NPCID.LunarTowerVortex)
+ hasVortexTower = true;
+ else if (npc.netID == NPCID.LunarTowerNebula)
+ hasNebulaTower = true;
+ else if (npc.netID == NPCID.LunarTowerStardust)
+ hasStardustTower = true;
+ }
+
+ if((args.Zone2[1] && !hasSolarTower)
+ || (args.Zone2[2] && !hasVortexTower)
+ || (args.Zone2[3] && !hasNebulaTower)
+ || (args.Zone2[4] && !hasStardustTower)
+ )
+ {
+ args.Handled = true;
+ return;
+ }
+ }
+
/// Bouncer's KillMe hook stops crash exploits from out of bounds values.
/// The object that triggered the event.
/// The packet arguments that the event has.
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index a7792569..dd18e502 100644
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -550,6 +550,56 @@ namespace TShockAPI
return args.Handled;
}
+ ///
+ /// For use in a PlayerZone event
+ ///
+ public class PlayerZoneEventArgs : GetDataHandledEventArgs
+ {
+ ///
+ /// The Terraria playerID of the player
+ ///
+ public byte PlayerId { get; set; }
+ ///
+ /// 0 = Dungeon, 1 = Corruption,2 =Holy, 3 = Meteor, 4 = Jungle, 5 = Snow, 6 = Crimson, 7 = Water Candle
+ ///
+ public BitsByte Zone1 { get; set; }
+ ///
+ /// 0 = Peace Candle, 1 = Solar Tower, 2 = Vortex Tower, 3 = Nebula Tower, 4 = Stardust Tower, 5 = Desert, 6 = Glowshroom, 7 = Underground Desert
+ ///
+ public BitsByte Zone2 { get; set; }
+ ///
+ /// 0 = Overworld, 1 = Dirt Layer, 2 = Rock Layer, 3 = Underworld, 4 = Beach, 5 = Rain, 6 = Sandstorm
+ ///
+ public BitsByte Zone3 { get; set; }
+ ///
+ /// 0 = Old One's Army
+ ///
+ public BitsByte Zone4 { get; set; }
+ }
+ ///
+ /// PlayerZone - When the player sends it's zone/biome information to the server
+ ///
+ public static HandlerList PlayerZone = new HandlerList();
+
+ private static bool OnPlayerZone(TSPlayer player, MemoryStream data, byte plr, BitsByte zone1, BitsByte zone2, BitsByte zone3, BitsByte zone4)
+ {
+ if (PlayerZone == null)
+ return false;
+
+ var args = new PlayerZoneEventArgs
+ {
+ Player = player,
+ Data = data,
+ PlayerId = plr,
+ Zone1 = zone1,
+ Zone2 = zone2,
+ Zone3 = zone3,
+ Zone4 = zone4
+ };
+ PlayerZone.Invoke(null, args);
+ return args.Handled;
+ }
+
/// The event args object for the HealOtherPlayer event
public class HealOtherPlayerEventArgs : GetDataHandledEventArgs
{
@@ -1479,6 +1529,7 @@ namespace TShockAPI
{
{ PacketTypes.PlayerInfo, HandlePlayerInfo },
{ PacketTypes.PlayerUpdate, HandlePlayerUpdate },
+ { PacketTypes.Zones, HandlePlayerZone },
{ PacketTypes.Tile, HandleTile },
{ PacketTypes.PlaceObject, HandlePlaceObject },
{ PacketTypes.TileSendSquare, HandleSendTileSquare },
@@ -2402,6 +2453,25 @@ namespace TShockAPI
return true;
}
+ private static bool HandlePlayerZone(GetDataHandlerArgs args)
+ {
+ if (args.Player == null || args.TPlayer == null || args.Data == null)
+ {
+ return true;
+ }
+
+ var plr = args.Data.ReadInt8();
+ BitsByte zone1 = args.Data.ReadInt8();
+ BitsByte zone2 = args.Data.ReadInt8();
+ BitsByte zone3 = args.Data.ReadInt8();
+ BitsByte zone4 = args.Data.ReadInt8();
+
+ if (OnPlayerZone(args.Player, args.Data, plr, zone1, zone2, zone3, zone4))
+ return true;
+
+ return false;
+ }
+
private static bool HandleProjectileNew(GetDataHandlerArgs args)
{
short ident = args.Data.ReadInt16();