diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs
index 909a84d68..08d6f98ab 100644
--- a/TShockAPI/Bouncer.cs
+++ b/TShockAPI/Bouncer.cs
@@ -130,6 +130,7 @@ internal Bouncer()
GetDataHandlers.PlaceObject += OnPlaceObject;
GetDataHandlers.PlaceTileEntity += OnPlaceTileEntity;
GetDataHandlers.PlaceItemFrame += OnPlaceItemFrame;
+ GetDataHandlers.WeaponsRackTryPlacing += OnWeaponsRackTryPlacing;
GetDataHandlers.PortalTeleport += OnPlayerPortalTeleport;
GetDataHandlers.GemLockToggle += OnGemLockToggle;
GetDataHandlers.MassWireOperation += OnMassWireOperation;
@@ -137,7 +138,10 @@ internal Bouncer()
GetDataHandlers.KillMe += OnKillMe;
GetDataHandlers.FishOutNPC += OnFishOutNPC;
GetDataHandlers.FoodPlatterTryPlacing += OnFoodPlatterTryPlacing;
+ GetDataHandlers.SyncItemsWithShimmer += OnSyncItemsWithShimmer;
+ GetDataHandlers.SyncItemCannotBeTakenByEnemies += OnSyncItemCannotBeTakenByEnemies;
GetDataHandlers.DisplayJarTryPlacing += OnDisplayJarTryPlacing;
+ GetDataHandlers.LeashedEntityAnchorPlaceItem += OnLeashedEntityAnchorPlaceItem;
OTAPI.Hooks.Chest.QuickStack += OnQuickStack;
HookEvents.Terraria.Projectile.Kill_DirtAndFluidProjectiles_RunDelegateMethodPushUpForHalfBricks += OnProjectileDirtFluidKill;
HookEvents.Terraria.GameContent.CraftingRequests.CanCraftFromChest += OnChestCraftRequest;
@@ -652,6 +656,15 @@ internal void OnTileEdit(object sender, GetDataHandlers.TileEditEventArgs args)
}
}
+ if (tile.type == TileID.WeaponsRack2)
+ {
+ int weaponRackId = TEWeaponsRack.Find(tileX - tile.frameX % 36 / 18, tileY - tile.frameY % 36 / 18);
+ if (weaponRackId != -1)
+ {
+ NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, weaponRackId, 0, 1);
+ }
+ }
+
if (tile.type == TileID.DeadCellsDisplayJar)
{
var displayJar = TEDeadCellsDisplayJar.Find(tileX - tile.frameX % 18 / 18, tileY - tile.frameY % 32 / 18);
@@ -783,6 +796,7 @@ internal void OnTileEdit(object sender, GetDataHandlers.TileEditEventArgs args)
// also add an exception for snake coils, they can be removed when the player places a new one or after x amount of time
// If the tile is part of the breakable when placing set, it might be getting broken by a placement.
else if (tile.type != TileID.ItemFrame &&
+ tile.type != TileID.WeaponsRack2 &&
tile.type != TileID.DeadCellsDisplayJar &&
tile.type != TileID.MysticSnakeRope &&
!ItemID.Sets.Explosives[selectedItem.type] &&
@@ -2696,6 +2710,48 @@ internal void OnPlaceItemFrame(object sender, GetDataHandlers.PlaceItemFrameEven
}
}
+ /// Fired when an weapon rack is placed for anti-cheat detection.
+ /// The object that triggered the event.
+ /// The packet arguments that the event has.
+ internal void OnWeaponsRackTryPlacing(object sender, GetDataHandlers.WeaponsRackTryPlacingEventArgs args)
+ {
+ if (!TShock.Utils.TilePlacementValid(args.X, args.Y))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnWeaponsRackTryPlacing rejected tile placement valid from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+
+ if (args.Player.IsBeingDisabled())
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnWeaponsRackTryPlacing rejected disabled from {0}", args.Player.Name));
+ NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.WeaponRack.ID, 0, 1);
+ args.Handled = true;
+ return;
+ }
+
+ if (!args.Player.HasBuildPermission(args.X, args.Y))
+ {
+ int num = Item.NewItem(null, (args.X * 16) + 8, (args.Y * 16) + 8, args.Player.TPlayer.width, args.Player.TPlayer.height, args.ItemID, args.Stack, noBroadcast: true, args.Prefix, noGrabDelay: true);
+ Main.item[num].playerIndexTheItemIsReservedFor = args.Player.Index;
+ NetMessage.SendData((int)PacketTypes.ItemDrop, args.Player.Index, -1, NetworkText.Empty, num, 1f);
+ NetMessage.SendData((int)PacketTypes.ItemOwner, args.Player.Index, -1, NetworkText.Empty, num);
+
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnWeaponsRackTryPlacing rejected permissions from {0}", args.Player.Name));
+ NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.WeaponRack.ID, 0, 1);
+ args.Handled = true;
+ return;
+ }
+
+ if (!args.Player.IsInRange(args.X, args.Y))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnWeaponsRackTryPlacing rejected range checks from {0}", args.Player.Name));
+ NetMessage.SendData((int)PacketTypes.UpdateTileEntity, -1, -1, NetworkText.Empty, args.WeaponRack.ID, 0, 1);
+ args.Handled = true;
+ return;
+ }
+ }
+
internal void OnPlayerPortalTeleport(object sender, GetDataHandlers.TeleportThroughPortalEventArgs args)
{
//Packet 96 (player teleport through portal) has no validation on whether or not the player id provided
@@ -3055,6 +3111,246 @@ internal void OnFoodPlatterTryPlacing(object sender, GetDataHandlers.FoodPlatter
}
}
+ /// Registered when shimmer items fall to the ground to prevent cheating.
+ /// The object that triggered the event.
+ /// The packet arguments that the event has.
+ internal void OnSyncItemsWithShimmer(object sender, GetDataHandlers.SyncItemsWithShimmerEventArgs args)
+ {
+ short id = args.ID;
+ Vector2 pos = args.Position;
+ Vector2 vel = args.Velocity;
+ short stacks = args.Stacks;
+ short prefix = args.Prefix;
+ bool noDelay = args.NoDelay;
+ short type = args.Type;
+
+ if (!float.IsFinite(pos.X) || !float.IsFinite(pos.Y))
+ {
+ TShock.Log.ConsoleInfo(GetString("Bouncer / OnSyncItemsWithShimmer force kicked (attempted to set position to infinity or NaN) from {0}", args.Player.Name));
+ args.Player.Kick(GetString("Detected DOOM set to ON position."), true, true);
+ args.Handled = true;
+ return;
+ }
+
+ if (!float.IsFinite(vel.X) || !float.IsFinite(vel.Y))
+ {
+ TShock.Log.ConsoleInfo(GetString("Bouncer / OnSyncItemsWithShimmer force kicked (attempted to set velocity to infinity or NaN) from {0}", args.Player.Name));
+ args.Player.Kick(GetString("Detected DOOM set to ON position."), true, true);
+ args.Handled = true;
+ return;
+ }
+
+ // player is attempting to crash clients
+ if (type < -48 || type >= Terraria.ID.ItemID.Count)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from attempt crash from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+
+ // make sure the prefix is a legit value
+ if (prefix > PrefixID.Count)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from prefix check from {0}", args.Player.Name));
+
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ if (type == 0)
+ {
+ if (!args.Player.IsInRange((int)(Main.item[id].position.X / 16f), (int)(Main.item[id].position.Y / 16f)))
+ {
+ // Causes item duplications. Will be re added if necessary
+ //args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from dupe range check from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+
+ args.Handled = false;
+ return;
+ }
+
+ if (!args.Player.IsInRange((int)(pos.X / 16f), (int)(pos.Y / 16f), 128))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from range check from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ // stop the client from changing the item type of a drop
+ if (Main.item[id].active && Main.item[id].type != type &&
+ !(Main.item[id].type == ItemID.EmptyBucket && type == ItemID.WaterBucket)) // Empty bucket turns into Water Bucket on rainy days
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from item drop check from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ Item item = new Item();
+ item.netDefaults(type);
+ if ((stacks > item.maxStack || stacks <= 0) || (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), args.Player) && !args.Player.HasPermission(Permissions.allowdroppingbanneditems)))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from drop item ban check / max stack check / min stack check from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ // TODO: Remove item ban part of this check
+ if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.Settings.LogonDiscardThreshold))
+ {
+ //Player is probably trying to sneak items onto the server in their hands!!!
+ TShock.Log.ConsoleInfo(GetString("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.Name));
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from sneaky from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+
+ }
+
+ if (args.Player.IsBeingDisabled())
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected from disabled from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ if (type == ItemID.GuideVoodooDoll && args.Player.TPlayer.ZoneUnderworldHeight && !args.Player.HasPermission(Permissions.summonboss))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemsWithShimmer rejected Guide Voodoo Doll drop from {0}", args.Player.Name));
+ args.Player.SendErrorMessage(GetString("You do not have permission to summon the Wall of Flesh."));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+ }
+
+ /// Registered when item items fall from enemy strike to the ground to prevent cheating.
+ /// The object that triggered the event.
+ /// The packet arguments that the event has.
+ internal void OnSyncItemCannotBeTakenByEnemies(object sender, GetDataHandlers.SyncItemCannotBeTakenByEnemiesEventArgs args)
+ {
+ short id = args.ID;
+ Vector2 pos = args.Position;
+ Vector2 vel = args.Velocity;
+ short stacks = args.Stacks;
+ short prefix = args.Prefix;
+ bool noDelay = args.NoDelay;
+ short type = args.Type;
+
+ if (!float.IsFinite(pos.X) || !float.IsFinite(pos.Y))
+ {
+ TShock.Log.ConsoleInfo(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies force kicked (attempted to set position to infinity or NaN) from {0}", args.Player.Name));
+ args.Player.Kick(GetString("Detected DOOM set to ON position."), true, true);
+ args.Handled = true;
+ return;
+ }
+
+ if (!float.IsFinite(vel.X) || !float.IsFinite(vel.Y))
+ {
+ TShock.Log.ConsoleInfo(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies force kicked (attempted to set velocity to infinity or NaN) from {0}", args.Player.Name));
+ args.Player.Kick(GetString("Detected DOOM set to ON position."), true, true);
+ args.Handled = true;
+ return;
+ }
+
+ // player is attempting to crash clients
+ if (type < -48 || type >= Terraria.ID.ItemID.Count)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from attempt crash from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+
+ // make sure the prefix is a legit value
+ if (prefix > PrefixID.Count)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from prefix check from {0}", args.Player.Name));
+
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ if (type == 0)
+ {
+ if (!args.Player.IsInRange((int)(Main.item[id].position.X / 16f), (int)(Main.item[id].position.Y / 16f)))
+ {
+ // Causes item duplications. Will be re added if necessary
+ //args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from dupe range check from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+
+ args.Handled = false;
+ return;
+ }
+
+ if (!args.Player.IsInRange((int)(pos.X / 16f), (int)(pos.Y / 16f), 128))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from range check from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ // stop the client from changing the item type of a drop
+ if (Main.item[id].active && Main.item[id].type != type &&
+ !(Main.item[id].type == ItemID.EmptyBucket && type == ItemID.WaterBucket)) // Empty bucket turns into Water Bucket on rainy days
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from item drop check from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.ItemDrop, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ Item item = new Item();
+ item.netDefaults(type);
+ if ((stacks > item.maxStack || stacks <= 0) || (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(item.type), args.Player) && !args.Player.HasPermission(Permissions.allowdroppingbanneditems)))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from drop item ban check / max stack check / min stack check from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ // TODO: Remove item ban part of this check
+ if ((Main.ServerSideCharacter) && (DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - args.Player.LoginMS < TShock.ServerSideCharacterConfig.Settings.LogonDiscardThreshold))
+ {
+ //Player is probably trying to sneak items onto the server in their hands!!!
+ TShock.Log.ConsoleInfo(GetString("Player {0} tried to sneak {1} onto the server!", args.Player.Name, item.Name));
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from sneaky from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+
+ }
+
+ if (args.Player.IsBeingDisabled())
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected from disabled from {0}", args.Player.Name));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+
+ if (type == ItemID.GuideVoodooDoll && args.Player.TPlayer.ZoneUnderworldHeight && !args.Player.HasPermission(Permissions.summonboss))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnSyncItemCannotBeTakenByEnemies rejected Guide Voodoo Doll drop from {0}", args.Player.Name));
+ args.Player.SendErrorMessage(GetString("You do not have permission to summon the Wall of Flesh."));
+ args.Player.SendData(PacketTypes.SyncItemDespawn, "", id);
+ args.Handled = true;
+ return;
+ }
+ }
+
///
/// Called when dirt/fluid projectiles (dirt bombs, liquid bombs, liquid rockets) are killed and attempt to place tiles or liquids.
///
@@ -3124,6 +3420,72 @@ internal void OnDisplayJarTryPlacing(object sender, GetDataHandlers.DisplayJarTr
return;
}
}
+
+ ///
+ /// Called when a player is trying to put an leashed entity
+ ///
+ ///
+ ///
+ internal void OnLeashedEntityAnchorPlaceItem(object sender, GetDataHandlers.LeashedEntityAnchorPlaceItemEventArgs args)
+ {
+ int tileX = args.TileX;
+ int tileY = args.TileY;
+
+ if (!TShock.Utils.TilePlacementValid(tileX, tileY))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from (tile placement valid) {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+ if (args.Player.IsBeingDisabled())
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from disabled from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+ if (args.Player.Dead && TShock.Config.Settings.PreventDeadModification)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from deadmod from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+ if (!args.Player.HasBuildPermission(tileX, tileY))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from permissions from {0}", args.Player.Name));
+ args.Handled = true;
+ return;
+ }
+ if (!args.Player.IsInRange(tileX, tileY))
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from range checks from {0}", args.Player.Name));
+ args.Player.SendTileSquareCentered(tileX, tileY, 1);
+ args.Handled = true;
+ return;
+ }
+ if (!args.Player.ItemInHand.IsAir && args.Player.ItemInHand.type != args.EntityID)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from item not placed by hand from {0}", args.Player.Name));
+ args.Player.SendTileSquareCentered(tileX, tileY, 1);
+ args.Handled = true;
+ return;
+ }
+ if (!args.Player.SelectedItem.IsAir && args.Player.SelectedItem.type != args.EntityID)
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from item not selected from {0}", args.Player.Name));
+ args.Player.SendTileSquareCentered(tileX, tileY, 1);
+ args.Handled = true;
+ return;
+ }
+
+ //valid item
+ if (!ItemID.Sets.PlaceTileOnAltUse[args.EntityID])
+ {
+ TShock.Log.ConsoleDebug(GetString("Bouncer / OnLeashedEntityAnchorPlaceItem rejected from invalid item alt use from {0}", args.Player.Name));
+ args.Player.SendTileSquareCentered(tileX, tileY, 1);
+ args.Handled = true;
+ return;
+ }
+ }
///
/// Called when a player is trying to put an item into chest through Quick Stack.
@@ -3296,6 +3658,7 @@ internal static int GetMaxPlaceStyle(int tileID)
TileID.Womannequin,
TileID.MinecartTrack,
TileID.WeaponsRack,
+ TileID.WeaponsRack2,
TileID.ItemFrame,
TileID.LunarMonolith,
TileID.TargetDummy,
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index ef4b0c2e9..b444329d2 100644
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -1,4 +1,4 @@
-/*
+/*
TShock, a server mod for Terraria
Copyright (C) 2011-2019 Pryaxis & TShock Contributors
@@ -16,20 +16,21 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+using Microsoft.Xna.Framework;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.IO.Streams;
using System.Linq;
-using Microsoft.Xna.Framework;
using Terraria;
using Terraria.DataStructures;
using Terraria.GameContent.Tile_Entities;
using Terraria.ID;
using Terraria.Localization;
-using TShockAPI.Models.PlayerUpdate;
using TShockAPI.Configuration;
+using TShockAPI.Models.PlayerUpdate;
namespace TShockAPI
{
@@ -136,15 +137,19 @@ public static void InitGetDataHandler()
{ PacketTypes.Emoji, HandleEmoji },
{ PacketTypes.TileEntityDisplayDollItemSync, HandleTileEntityDisplayDollItemSync },
{ PacketTypes.RequestTileEntityInteraction, HandleRequestTileEntityInteraction },
+ { PacketTypes.WeaponsRackTryPlacing, HandleWeaponsRackTryPlacing },
{ PacketTypes.SyncTilePicking, HandleSyncTilePicking },
{ PacketTypes.SyncRevengeMarker, HandleSyncRevengeMarker },
{ PacketTypes.LandGolfBallInCup, HandleLandGolfBallInCup },
{ PacketTypes.FishOutNPC, HandleFishOutNPC },
{ PacketTypes.FoodPlatterTryPlacing, HandleFoodPlatterTryPlacing },
{ PacketTypes.SyncCavernMonsterType, HandleSyncCavernMonsterType },
+ { PacketTypes.SyncItemsWithShimmer, HandleSyncItemsWithShimmer },
{ PacketTypes.SyncLoadout, HandleSyncLoadout },
{ PacketTypes.TeamChangeFromUI, HandlePlayerTeam }, // Same packet as PlayerTeam
- { PacketTypes.TEDeadCellsDisplayJar, HandleDisplayJar }
+ { PacketTypes.SyncItemCannotBeTakenByEnemies, HandleSyncItemCannotBeTakenByEnemies },
+ { PacketTypes.TEDeadCellsDisplayJar, HandleDisplayJar },
+ { PacketTypes.TELeashedEntityAnchorPlaceItem, HandleLeashedEntityAnchorPlaceItem }
};
}
@@ -2321,6 +2326,50 @@ private static bool OnRequestTileEntityInteraction(TSPlayer player, MemoryStream
RequestTileEntityInteraction.Invoke(null, args);
return args.Handled;
}
+ ///
+ /// For use in an OnWeaponsRackTryPlacing event.
+ ///
+ public class WeaponsRackTryPlacingEventArgs : GetDataHandledEventArgs
+ {
+ /// The X coordinate of the weapon rack.
+ public short X { get; set; }
+
+ /// The Y coordinate of the weapon rack.
+ public short Y { get; set; }
+
+ /// The ItemID of the weapon rack.
+ public short ItemID { get; set; }
+
+ /// The prefix.
+ public byte Prefix { get; set; }
+
+ /// The stack.
+ public short Stack { get; set; }
+
+ /// The ItemFrame object associated with this event.
+ public TEWeaponsRack WeaponRack { get; set; }
+ }
+ /// Fired when an WeaponRack is placed.
+ public static HandlerList WeaponsRackTryPlacing = new HandlerList();
+ private static bool OnWeaponsRackTryPlacing(TSPlayer player, MemoryStream data, short x, short y, short itemID, byte prefix, short stack, TEWeaponsRack weaponRack)
+ {
+ if (WeaponsRackTryPlacing == null)
+ return false;
+
+ var args = new WeaponsRackTryPlacingEventArgs
+ {
+ Player = player,
+ Data = data,
+ X = x,
+ Y = y,
+ ItemID = itemID,
+ Prefix = prefix,
+ Stack = stack,
+ WeaponRack = weaponRack
+ };
+ WeaponsRackTryPlacing.Invoke(null, args);
+ return args.Handled;
+ }
///
/// For use in a SyncTilePicking event.
@@ -2499,6 +2548,127 @@ private static bool OnFoodPlatterTryPlacing(TSPlayer player, MemoryStream data,
FoodPlatterTryPlacing.Invoke(null, args);
return args.Handled;
}
+
+ ///
+ /// For use in an SyncItemsWithShimmer event
+ ///
+ public class SyncItemsWithShimmerEventArgs : GetDataHandledEventArgs
+ {
+ ///
+ /// ID of the item.
+ /// If below 400 and NetID(Type) is 0 Then Set Null. If ItemID is 400 Then New Item
+ ///
+ public short ID { get; set; }
+ ///
+ /// Position of the item
+ ///
+ public Vector2 Position { get; set; }
+ ///
+ /// Velocity at which the item is deployed
+ ///
+ public Vector2 Velocity { get; set; }
+ ///
+ /// Stacks
+ ///
+ public short Stacks { get; set; }
+ ///
+ /// Prefix of the item
+ ///
+ public byte Prefix { get; set; }
+ ///
+ /// No Delay on pickup
+ ///
+ public bool NoDelay { get; set; }
+ ///
+ /// Item type
+ ///
+ public short Type { get; set; }
+ }
+
+ ///
+ /// SyncItemsWithShimmer - Called when an item is sync on shimmer
+ ///
+ public static HandlerList SyncItemsWithShimmer = new HandlerList();
+ private static bool OnSyncItemsWithShimmer(TSPlayer player, MemoryStream data, short id, Vector2 pos, Vector2 vel, short stacks, byte prefix, bool noDelay, short type)
+ {
+ if (SyncItemsWithShimmer == null)
+ return false;
+
+ var args = new SyncItemsWithShimmerEventArgs
+ {
+ Player = player,
+ Data = data,
+ ID = id,
+ Position = pos,
+ Velocity = vel,
+ Stacks = stacks,
+ Prefix = prefix,
+ NoDelay = noDelay,
+ Type = type,
+ };
+ SyncItemsWithShimmer.Invoke(null, args);
+ return args.Handled;
+ }
+
+ ///
+ /// For use in an SyncItemCannotBeTakenByEnemies event
+ ///
+ public class SyncItemCannotBeTakenByEnemiesEventArgs : GetDataHandledEventArgs
+ {
+ ///
+ /// ID of the item.
+ /// If below 400 and NetID(Type) is 0 Then Set Null. If ItemID is 400 Then New Item
+ ///
+ public short ID { get; set; }
+ ///
+ /// Position of the item
+ ///
+ public Vector2 Position { get; set; }
+ ///
+ /// Velocity at which the item is deployed
+ ///
+ public Vector2 Velocity { get; set; }
+ ///
+ /// Stacks
+ ///
+ public short Stacks { get; set; }
+ ///
+ /// Prefix of the item
+ ///
+ public byte Prefix { get; set; }
+ ///
+ /// No Delay on pickup
+ ///
+ public bool NoDelay { get; set; }
+ ///
+ /// Item type
+ ///
+ public short Type { get; set; }
+ }
+ ///
+ /// SyncItemCannotBeTakenByEnemies - Called when an item is dropped
+ ///
+ public static HandlerList SyncItemCannotBeTakenByEnemies = new HandlerList();
+ private static bool OnSyncItemCannotBeTakenByEnemies(TSPlayer player, MemoryStream data, short id, Vector2 pos, Vector2 vel, short stacks, byte prefix, bool noDelay, short type)
+ {
+ if (SyncItemCannotBeTakenByEnemies == null)
+ return false;
+
+ var args = new SyncItemCannotBeTakenByEnemiesEventArgs
+ {
+ Player = player,
+ Data = data,
+ ID = id,
+ Position = pos,
+ Velocity = vel,
+ Stacks = stacks,
+ Prefix = prefix,
+ NoDelay = noDelay,
+ Type = type,
+ };
+ SyncItemCannotBeTakenByEnemies.Invoke(null, args);
+ return args.Handled;
+ }
public class DisplayJarTryPlacingEventArgs : GetDataHandledEventArgs
{
@@ -2579,7 +2749,43 @@ private static bool OnReadNetModule(TSPlayer player, MemoryStream data, NetModul
ReadNetModule.Invoke(null, args);
return args.Handled;
}
+
+ public class LeashedEntityAnchorPlaceItemEventArgs : GetDataHandledEventArgs
+ {
+ ///
+ /// The X tile position of the placement action.
+ ///
+ public ushort TileX { get; set; }
+ ///
+ /// The Y tile position of the placement action.
+ ///
+ public ushort TileY { get; set; }
+ ///
+ /// The Entity ID that is being placed in the display jar.
+ ///
+ public short EntityID { get; set; }
+ }
+ ///
+ /// Called when a player is placing an item in a Leashed Entity Anchor.
+ ///
+ public static HandlerList LeashedEntityAnchorPlaceItem = new HandlerList();
+ private static bool OnLeashedEntityAnchorPlaceItem(TSPlayer player, MemoryStream data, ushort tileX, ushort tileY, short EntityID)
+ {
+ if (LeashedEntityAnchorPlaceItem == null)
+ return false;
+ var args = new LeashedEntityAnchorPlaceItemEventArgs
+ {
+ Player = player,
+ Data = data,
+ TileX = tileX,
+ TileY = tileY,
+ EntityID = EntityID,
+ };
+ LeashedEntityAnchorPlaceItem.Invoke(null, args);
+ return args.Handled;
+ }
+
#endregion
private static bool HandlePlayerInfo(GetDataHandlerArgs args)
@@ -4811,6 +5017,23 @@ private static bool HandleRequestTileEntityInteraction(GetDataHandlerArgs args)
return false;
}
+ private static bool HandleWeaponsRackTryPlacing(GetDataHandlerArgs args)
+ {
+ short x = args.Data.ReadInt16();
+ short y = args.Data.ReadInt16();
+ short itemID = args.Data.ReadInt16();
+ byte prefix = args.Data.ReadInt8();
+ short stack = args.Data.ReadInt16();
+ TEWeaponsRack WeaponRack = (TEWeaponsRack)TileEntity.ByID[TEWeaponsRack.Find(x, y)];
+
+ if (OnWeaponsRackTryPlacing(args.Player, args.Data, x, y, itemID, prefix, stack, WeaponRack))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
private static bool HandleSyncTilePicking(GetDataHandlerArgs args)
{
byte playerIndex = args.Data.ReadInt8();
@@ -4886,6 +5109,22 @@ private static bool HandleSyncCavernMonsterType(GetDataHandlerArgs args)
return true;
}
+ private static bool HandleSyncItemsWithShimmer(GetDataHandlerArgs args)
+ {
+ var id = args.Data.ReadInt16();
+ var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
+ var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
+ var stacks = args.Data.ReadInt16();
+ var prefix = args.Data.ReadInt8();
+ var noDelay = args.Data.ReadInt8() == 1;
+ var type = args.Data.ReadInt16();
+
+ if (OnSyncItemsWithShimmer(args.Player, args.Data, id, pos, vel, stacks, prefix, noDelay, type))
+ return true;
+
+ return false;
+ }
+
private static bool HandleSyncLoadout(GetDataHandlerArgs args)
{
var playerIndex = args.Data.ReadInt8();
@@ -4974,6 +5213,22 @@ Tuple GetDyeSlotsForLoadoutIndex(int index)
return false;
}
+ private static bool HandleSyncItemCannotBeTakenByEnemies(GetDataHandlerArgs args)
+ {
+ var id = args.Data.ReadInt16();
+ var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
+ var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
+ var stacks = args.Data.ReadInt16();
+ var prefix = args.Data.ReadInt8();
+ var noDelay = args.Data.ReadInt8() == 1;
+ var type = args.Data.ReadInt16();
+
+ if (OnSyncItemCannotBeTakenByEnemies(args.Player, args.Data, id, pos, vel, stacks, prefix, noDelay, type))
+ return true;
+
+ return false;
+ }
+
private static bool HandleDisplayJar(GetDataHandlerArgs args)
{
ushort tileX = args.Data.ReadUInt16();
@@ -4988,6 +5243,20 @@ private static bool HandleDisplayJar(GetDataHandlerArgs args)
return false;
}
+ private static bool HandleLeashedEntityAnchorPlaceItem(GetDataHandlerArgs args)
+ {
+ var x = args.Data.ReadUInt16();
+ var y = args.Data.ReadUInt16();
+ var EntityID = args.Data.ReadInt16();
+ //var leashedEntityAnchor = (TELeashedEntityAnchor)TileEntity.ByID[TELeashedEntityAnchor.fi(x, y)];
+
+ if (OnLeashedEntityAnchorPlaceItem(args.Player, args.Data, x, y, EntityID))
+ {
+ return true;
+ }
+
+ return false;
+ }
public enum DoorAction
{