public bool Equals(ItemData other)
 {
     return (
     this.prefix == other.prefix &&
     this.type == other.type &&
     this.stackSize == other.stackSize
       );
 }
        public ProtectorChestData(DPoint location, ItemData[] content = null)
        {
            this.Location = location;

              if (content != null)
            this.Items = content.Clone() as ItemData[];
              else
            this.Items = new ItemData[Chest.maxItems];
        }
        public int CreateNew(TSPlayer forPlayer, DPoint location, ItemData itemData, bool sendPacket = true)
        {
            int itemIndex = Item.NewItem(
            location.X, location.Y, 0, 0, (int)itemData.Type, itemData.StackSize, true, (int)itemData.Prefix
              );

              if (sendPacket)
            forPlayer.SendData(PacketTypes.ItemDrop, string.Empty, itemIndex);

              return itemIndex;
        }
        public bool Equals(ItemData other)
        {
            if (this.StackSize == 0 && other.StackSize == 0)
            return true;

              return (
            this.Prefix == other.Prefix &&
            this.Type == other.Type &&
            this.StackSize == other.StackSize
              );
        }
        public void RemoveChestData(IChest chest)
        {
            ItemData[] content = new ItemData[Chest.maxItems];
              for (int i = 0; i < Chest.maxItems; i++)
            content[i] = chest.Items[i];

              if (chest.IsWorldChest) {
            int playerUsingChestIndex = Chest.UsingChest(chest.Index);
            if (playerUsingChestIndex != -1)
              Main.player[playerUsingChestIndex].chest = -1;

            Main.chest[chest.Index] = null;
              } else {
            lock (this.WorldMetadata.ProtectorChests)
              this.WorldMetadata.ProtectorChests.Remove(chest.Location);
              }
        }
        public virtual bool HandleChestModifySlot(TSPlayer player, int chestIndex, int slotIndex, ItemData newItem)
        {
            if (this.IsDisposed)
            return false;

              // Get the chest location of the chest the player has last opened.
              IChest chest = this.LastOpenedChest(player);
              if (chest == null)
            return true;

              ProtectionEntry protection = null;
              // Only need the first enumerated entry as we don't need the protections of adjacent blocks.
              foreach (ProtectionEntry enumProtection in this.ProtectionManager.EnumerateProtectionEntries(chest.Location)) {
            protection = enumProtection;
            break;
              }

              bool playerHasAccess = true;
              if (protection != null)
            playerHasAccess = this.ProtectionManager.CheckProtectionAccess(protection, player, false);

              if (!playerHasAccess)
            return true;

              if (protection != null && protection.RefillChestData != null) {
            RefillChestMetadata refillChest = protection.RefillChestData;
            // The player who set up the refill chest or masters shall modify its contents.
            if (
              this.Config.AllowRefillChestContentChanges &&
              (refillChest.Owner == player.User.ID || player.Group.HasPermission(ProtectorPlugin.ProtectionMaster_Permission))
            ) {
              refillChest.RefillItems[slotIndex] = newItem;

              this.ChestManager.TryRefillChest(chest, refillChest);

              if (refillChest.RefillTime == TimeSpan.Zero) {
            player.SendSuccessMessage("The content of this refill chest was updated.");
              } else {
            lock (this.ChestManager.RefillTimers) {
              if (this.ChestManager.RefillTimers.IsTimerRunning(refillChest.RefillTimer))
                this.ChestManager.RefillTimers.RemoveTimer(refillChest.RefillTimer);
            }

            player.SendSuccessMessage("The content of this refill chest was updated and the timer was reset.");
              }

              return false;
            }

            if (refillChest.OneLootPerPlayer || refillChest.RemainingLoots > 0) {
              Contract.Assert(refillChest.Looters != null);
              if (!refillChest.Looters.Contains(player.User.ID)) {
            refillChest.Looters.Add(player.User.ID);

            if (refillChest.RemainingLoots > 0)
              refillChest.RemainingLoots--;
              }
            }

            // As the first item is taken out, we start the refill timer.
            ItemData oldItem = chest.Items[slotIndex];
            if (newItem.Type == ItemType.None || (newItem.Type == oldItem.Type && newItem.StackSize <= oldItem.StackSize)) {
              // TODO: Bad code, refill timers shouldn't be public at all.
              lock (this.ChestManager.RefillTimers)
            this.ChestManager.RefillTimers.StartTimer(refillChest.RefillTimer);
            } else {
              player.SendErrorMessage("You can not put items into this chest.");
              return true;
            }
              } else if (protection != null && protection.BankChestKey != BankChestDataKey.Invalid) {
            BankChestDataKey bankChestKey = protection.BankChestKey;
            this.ServerMetadataHandler.EnqueueUpdateBankChestItem(bankChestKey, slotIndex, newItem);
              }

              chest.Items[slotIndex] = newItem;
              return true;
        }
        public bool TrySwapChestData(TSPlayer player, DPoint anyChestTileLocation, out IChest newChest)
        {
            newChest = null;

              if (TerrariaUtils.Tiles[anyChestTileLocation].type != TileID.Containers && TerrariaUtils.Tiles[anyChestTileLocation].type != TileID.Dressers) {
            player.SendErrorMessage("The selected tile is not a chest or dresser.");
            return false;
              }

              DPoint chestLocation = TerrariaUtils.Tiles.MeasureObject(anyChestTileLocation).OriginTileLocation;
              IChest chest = this.ChestManager.ChestFromLocation(chestLocation, player);
              if (chest == null)
            return false;

              ItemData[] content = new ItemData[Chest.maxItems];
              for (int i = 0; i < Chest.maxItems; i++)
            content[i] = chest.Items[i];

              if (chest.IsWorldChest) {
            lock (this.WorldMetadata.ProtectorChests) {
              bool isChestAvailable = this.WorldMetadata.ProtectorChests.Count < this.Config.MaxProtectorChests;
              if (!isChestAvailable) {
            player?.SendErrorMessage("The maximum of possible Protector chests has been reached.");
            return false;
              }

              int playerUsingChestIndex = Chest.UsingChest(chest.Index);
              if (playerUsingChestIndex != -1)
            Main.player[playerUsingChestIndex].chest = -1;

              Main.chest[chest.Index] = null;
              newChest = new ProtectorChestData(chestLocation, content);

              this.WorldMetadata.ProtectorChests.Add(chestLocation, (ProtectorChestData)newChest);

              //TSPlayer.All.SendData(PacketTypes.ChestName, string.Empty, chest.Index, chestLocation.X, chestLocation.Y);

              // Tell the client to remove the chest with the given index from its own chest array.
              TSPlayer.All.SendData(PacketTypes.TileKill, string.Empty, 1, chestLocation.X, chestLocation.Y, 0, chest.Index);
              TSPlayer.All.SendTileSquare(chestLocation.X, chestLocation.Y, 2);
              player?.SendWarningMessage("This chest is now a Protector chest.");
            }
              } else {
            int availableUnnamedChestIndex = -1;
            int availableEmptyChestIndex = -1;
            for (int i = 0; i < Main.chest.Length; i++) {
              if (i == ChestManager.DummyChestIndex)
            continue;

              Chest tChest = Main.chest[i];
              if (tChest == null) {
            availableEmptyChestIndex = i;
            break;
              } else if (availableUnnamedChestIndex == -1 && string.IsNullOrWhiteSpace(tChest.name)) {
            availableUnnamedChestIndex = i;
              }
            }

            // Prefer unset chests over unnamed chests.
            int availableChestIndex = availableEmptyChestIndex;
            if (availableChestIndex == -1)
              availableChestIndex = availableUnnamedChestIndex;

            bool isChestAvailable = (availableChestIndex != -1);
            if (!isChestAvailable) {
              player?.SendErrorMessage("The maximum of possible world chests has been reached.");
              return false;
            }

            lock (this.WorldMetadata.ProtectorChests)
              this.WorldMetadata.ProtectorChests.Remove(chestLocation);

            Chest availableChest = Main.chest[availableChestIndex];
            bool isExistingButUnnamedChest = (availableChest != null);
            if (isExistingButUnnamedChest) {
              if (!this.TrySwapChestData(null, new DPoint(availableChest.x, availableChest.y), out newChest))
            return false;
            }

            availableChest = Main.chest[availableChestIndex] = new Chest();
            availableChest.x = chestLocation.X;
            availableChest.y = chestLocation.Y;
            availableChest.item = content.Select(i => i.ToItem()).ToArray();

            newChest = new ChestAdapter(availableChestIndex, availableChest);
            player?.SendWarningMessage("This chest is now a world chest.");
              }

              return true;
        }
        public string GetItemRepresentativeString(ItemData itemData)
        {
            string format = "{0}";
              if (itemData.StackSize > 1)
            format = "{0} ({1})";

              return string.Format(format, this.GetItemName(itemData, true), itemData.StackSize);
        }
        public string GetItemName(ItemData itemData, bool includePrefix = false)
        {
            string name = "";
              if ((itemData.Prefix != ItemPrefix.None && includePrefix) || itemData.Type < 0)
            name += "<" + this.GetItemPrefixName(itemData.Prefix) + "> ";

              name += Main.itemName[(int)itemData.Type];
              return name;
        }
        public int GetCoinItemValue(ItemData coinItem)
        {
            Contract.Requires<ArgumentException>(this.IsCoinType(coinItem.Type));

              int baseValue = 1;
              switch (coinItem.Type) {
            case ItemType.SilverCoin:
              baseValue = 100;
              break;
            case ItemType.GoldCoin:
              baseValue = 100 * 100;
              break;
            case ItemType.PlatinumCoin:
              baseValue = 100 * 100 * 100;
              break;
              }

              return baseValue * coinItem.StackSize;
        }
        public Task EnqueueUpdateBankChestItem(BankChestDataKey key, int slotIndex, ItemData newItem)
        {
            Contract.Requires<ObjectDisposedException>(!this.IsDisposed);

              lock (this.workQueueLock) {
            return this.WorkQueue.EnqueueTask(() => {
              this.UpdateBankChestItem(key, slotIndex, newItem);
            });
              }
        }
        private void UpdateBankChestItem(BankChestDataKey key, int slotIndex, ItemData newItem)
        {
            BankChestMetadata bankChest = this.GetBankChestMetadata(key);
              if (bankChest == null)
            throw new ArgumentException("No bank chest with the given key found.", "key");

              bankChest.Items[slotIndex] = newItem;
              this.AddOrUpdateBankChest(key, bankChest);
        }
        private BankChestMetadata GetBankChestMetadata(BankChestDataKey key)
        {
            using (QueryResult reader = this.DbConnection.QueryReader(
            "SELECT Content FROM Protector_BankChests WHERE UserId = @0 AND ChestIndex = @1;",
            key.UserId, key.BankChestIndex
              )) {
            if (!reader.Read())
              return null;

            ItemData[] itemDataFromDB = this.StringToItemMetadata(reader.Get<string>("Content"));
            ItemData[] itemData = itemDataFromDB;
            // Backward compatibility in case chests can now hold more items than before.
            if (itemDataFromDB.Length < Chest.maxItems) {
              itemData = new ItemData[Chest.maxItems];
              for (int i = 0; i < itemDataFromDB.Length; i++)
            itemData[i] = itemDataFromDB[i];
            }

            return new BankChestMetadata { Items = itemData };
              };
        }
        protected ItemData[] StringToItemMetadata(string raw)
        {
            string[] itemsRaw = raw.Split(';');
              ItemData[] items = new ItemData[itemsRaw.Length];
              for (int i = 0; i < itemsRaw.Length; i++) {
            string[] itemDataRaw = itemsRaw[i].Split(',');
            items[i] = new ItemData(
              (ItemPrefix)int.Parse(itemDataRaw[0]),
              (ItemType)int.Parse(itemDataRaw[1]),
              int.Parse(itemDataRaw[2])
            );
              }

              return items;
        }
        public string GetItemName(ItemData itemData, bool includePrefix = false)
        {
            if ((itemData.Prefix != ItemPrefix.None && includePrefix) || itemData.Type < 0) {
            Item dummyItem = new Item();
            dummyItem.netDefaults((int)itemData.Type);
            dummyItem.prefix = (byte)itemData.Prefix;

            return dummyItem.AffixName();
              }

              return Main.itemName[(int)itemData.Type];
        }