private bool TryGetProtectionInfo(TSPlayer player, DPoint tileLocation, bool sendFailureMessages = true)
        {
            Tile tile = TerrariaUtils.Tiles[tileLocation];
              if (!tile.active())
            return false;

              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(tileLocation)) {
            protection = enumProtection;
            break;
              }

              BlockType blockType = (BlockType)TerrariaUtils.Tiles[tileLocation].type;
              if (protection == null) {
            if (sendFailureMessages)
              player.SendErrorMessage($"This {TerrariaUtils.Tiles.GetBlockTypeName(blockType)} is not protected by Protector at all.");

            return false;
              }

              bool canViewExtendedInfo = (
            player.Group.HasPermission(ProtectorPlugin.ViewAllProtections_Permission) ||
            protection.Owner == player.User.ID ||
            protection.IsSharedWithPlayer(player)
              );

              if (!canViewExtendedInfo) {
            player.SendMessage($"This {TerrariaUtils.Tiles.GetBlockTypeName(blockType)} is protected and not shared with you.", Color.LightGray);

            player.SendWarningMessage("You are not permitted to get more information about this protection.");
            return true;
              }

              string ownerName;
              if (protection.Owner == -1)
            ownerName = "{Server}";
              else
            ownerName = GetUserName(protection.Owner);

              player.SendMessage($"This {TerrariaUtils.Tiles.GetBlockTypeName(blockType)} is protected. The owner is {TShock.Utils.ColorTag(ownerName, Color.Red)}.", Color.LightGray);

              string creationTimeFormat = "unknown";
              if (protection.TimeOfCreation != DateTime.MinValue)
            creationTimeFormat = "{0:MM/dd/yy, h:mm tt} UTC ({1} ago)";

              player.SendMessage(
            string.Format(
              CultureInfo.InvariantCulture, "Protection created On: " + creationTimeFormat, protection.TimeOfCreation,
              (DateTime.UtcNow - protection.TimeOfCreation).ToLongString()
            ),
            Color.LightGray
              );

              if (blockType == BlockType.Chest || blockType == BlockType.Dresser) {
            if (protection.RefillChestData != null) {
              RefillChestMetadata refillChest = protection.RefillChestData;
              if (refillChest.RefillTime != TimeSpan.Zero)
            player.SendMessage($"This is a refill chest with a timer set to {TShock.Utils.ColorTag(refillChest.RefillTime.ToLongString(), Color.Red)}.", Color.LightGray);
              else
            player.SendMessage("This is a refill chest without a timer.", Color.LightGray);

              if (refillChest.OneLootPerPlayer || refillChest.RemainingLoots != -1) {
            StringBuilder messageBuilder = new StringBuilder();
            messageBuilder.Append("It can only be looted ");

            if (refillChest.OneLootPerPlayer)
              messageBuilder.Append("one time by each player");
            if (refillChest.RemainingLoots != -1) {
              if (messageBuilder.Length > 0)
                messageBuilder.Append(" and ");

              messageBuilder.Append(TShock.Utils.ColorTag(refillChest.RemainingLoots.ToString(), Color.Red));
              messageBuilder.Append(" more times in total");
            }
            if (refillChest.Looters != null) {
              messageBuilder.Append(" and was looted ");
              messageBuilder.Append(TShock.Utils.ColorTag(refillChest.Looters.Count.ToString(), Color.Red));
              messageBuilder.Append(" times until now");
            }
            messageBuilder.Append('.');

            player.SendMessage(messageBuilder.ToString(), Color.LightGray);
              }
            } else if (protection.BankChestKey != BankChestDataKey.Invalid) {
              BankChestDataKey bankChestKey = protection.BankChestKey;
              player.SendMessage($"This is a bank chest instance with the number {bankChestKey.BankChestIndex}.", Color.LightGray);
            } else if (protection.TradeChestData != null) {
              Item sellItem = new Item();
              sellItem.netDefaults(protection.TradeChestData.ItemToSellId);
              sellItem.stack = protection.TradeChestData.ItemToSellAmount;
              Item payItem = new Item();
              payItem.netDefaults(protection.TradeChestData.ItemToPayId);
              payItem.stack = protection.TradeChestData.ItemToPayAmount;

              player.SendMessage($"This is a trade chest. It's selling {TShock.Utils.ItemTag(sellItem)} for {TShock.Utils.ItemTag(payItem)}", Color.LightGray);
            }

            IChest chest = this.ChestManager.ChestFromLocation(protection.TileLocation);
            if (chest.IsWorldChest)
              player.SendMessage($"It is stored as part of the world data (id: {TShock.Utils.ColorTag(chest.Index.ToString(), Color.Red)}).", Color.LightGray);
            else
              player.SendMessage($"It is {TShock.Utils.ColorTag("not", Color.Red)} stored as part of the world data.", Color.LightGray);
              }

              if (ProtectionManager.IsShareableBlockType(blockType)) {
            if (protection.IsSharedWithEveryone) {
              player.SendMessage("Protection is shared with everyone.", Color.LightGray);
            } else {
              StringBuilder sharedListBuilder = new StringBuilder();
              if (protection.SharedUsers != null) {
            for (int i = 0; i < protection.SharedUsers.Count; i++) {
              if (i > 0)
                sharedListBuilder.Append(", ");

              TShockAPI.DB.User tsUser = TShock.Users.GetUserByID(protection.SharedUsers[i]);
              if (tsUser != null)
                sharedListBuilder.Append(tsUser.Name);
            }
              }

              if (sharedListBuilder.Length == 0 && protection.SharedGroups == null) {
            player.SendMessage($"Protection is {TShock.Utils.ColorTag("not", Color.Red)} shared with users or groups.", Color.LightGray);
              } else {
            if (sharedListBuilder.Length > 0)
              player.SendMessage($"Shared with users: {TShock.Utils.ColorTag(sharedListBuilder.ToString(), Color.Red)}", Color.LightGray);
            else
              player.SendMessage($"Protection is {TShock.Utils.ColorTag("not", Color.Red)} shared with users.", Color.LightGray);

            if (protection.SharedGroups != null)
              player.SendMessage($"Shared with groups: {TShock.Utils.ColorTag(protection.SharedGroups.ToString(), Color.Red)}", Color.LightGray);
            else
              player.SendMessage($"Protection is {TShock.Utils.ColorTag("not", Color.Red)} shared with groups.", Color.LightGray);
              }
            }
              }

              if (protection.TradeChestData != null && protection.TradeChestData.TransactionJournal.Count > 0) {
            player.SendMessage($"Trade Chest Journal (Last {protection.TradeChestData.TransactionJournal.Count} Transactions)", Color.LightYellow);
            protection.TradeChestData.TransactionJournal.ForEach(entry => {
              string entryText = entry.Item1;
              DateTime entryTime = entry.Item2;
              TimeSpan timeSpan = DateTime.UtcNow - entryTime;

              player.SendMessage($"{entryText} {timeSpan.ToLongString()} ago.", Color.LightGray);
            });
              }

              return true;
        }
        public override bool HandleTileEdit(
            TSPlayer player, TileEditType editType, BlockType blockType, DPoint location, int objectStyle
            )
        {
            if (this.IsDisposed)
            return false;
              if (base.HandleTileEdit(player, editType, blockType, location, objectStyle))
            return true;

              switch (editType) {
            case TileEditType.PlaceTile: {
              Tile tile = TerrariaUtils.Tiles[location];
              if (tile == null)
            Main.tile[location.X, location.Y] = tile = new Tile();

              WorldGen.PlaceTile(location.X, location.Y, (int)blockType, false, true, -1, objectStyle);
              NetMessage.SendData((int)PacketTypes.Tile, -1, player.Index, string.Empty, 1, location.X, location.Y, (int)blockType, objectStyle);

              if (this.Config.AutoProtectedTiles[(int)blockType])
            this.TryCreateAutoProtection(player, location);

              return true;
            }
            case TileEditType.TileKill:
            case TileEditType.TileKillNoItem: {
              // Is the tile really going to be destroyed or just being hit?
              //if (blockType != 0)
              //  break;

              Tile tile = TerrariaUtils.Tiles[location];
              bool isChest = (tile.type == TileID.Containers || tile.type == TileID.Dressers);
              foreach (ProtectionEntry protection in this.ProtectionManager.EnumerateProtectionEntries(location)) {
            // If the protection is invalid, just remove it.
            if (!TerrariaUtils.Tiles.IsValidCoord(protection.TileLocation)) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              continue;
            }

            Tile protectedTile = TerrariaUtils.Tiles[protection.TileLocation];
            // If the protection is invalid, just remove it.
            if (!protectedTile.active() || protectedTile.type != (int)protection.BlockType) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              continue;
            }

            string tileName = TerrariaUtils.Tiles.GetBlockTypeName((BlockType)protectedTile.type);
            if (
              protection.Owner == player.User.ID || (
                this.Config.AutoDeprotectEverythingOnDestruction &&
                player.Group.HasPermission(ProtectorPlugin.ProtectionMaster_Permission)
              )
            ) {
              if (isChest) {
                bool isBankChest = (protection.BankChestKey != BankChestDataKey.Invalid);
                ObjectMeasureData measureData = TerrariaUtils.Tiles.MeasureObject(protection.TileLocation);
                DPoint chestLocation = measureData.OriginTileLocation;
                IChest chest = this.ChestManager.ChestFromLocation(chestLocation);

                if (chest == null)
                  return true;

                if (isBankChest) {
                  this.DestroyBlockOrObject(chestLocation);
                } else {
                  for (int i = 0; i < Chest.maxItems; i++) {
                    if (chest.Items[i].StackSize > 0)
                      return true;
                  }
                }
              }
              this.ProtectionManager.RemoveProtection(player, protection.TileLocation, false);

              if (this.Config.NotifyAutoDeprotections)
                player.SendWarningMessage($"The {tileName} is not protected anymore.");
            } else {
              player.SendErrorMessage($"The {tileName} is protected.");

              if (protection.TradeChestData != null)
                player.SendWarningMessage("If you want to trade with this chest, right click it first.");

              player.SendTileSquare(location);
              return true;
            }
              }

              if (isChest) {
            ObjectMeasureData measureData = TerrariaUtils.Tiles.MeasureObject(location);
            DPoint chestLocation = measureData.OriginTileLocation;
            IChest chest = this.ChestManager.ChestFromLocation(chestLocation);
            if (chest != null) {
              // Don't allow removing of non empty chests.
              for (int i = 0; i < Chest.maxItems; i++) {
                if (chest.Items[i].StackSize > 0)
                  return true;
              }

              this.DestroyBlockOrObject(chestLocation);
              return true;
            }
              }

              break;
            }
            case TileEditType.PlaceWire:
            case TileEditType.PlaceWireBlue:
            case TileEditType.PlaceWireGreen:
            case TileEditType.PlaceWireYellow:
            case TileEditType.PlaceActuator:
            case TileEditType.DestroyWire:
            case TileEditType.DestroyWireBlue:
            case TileEditType.DestroyWireGreen:
            case TileEditType.DestroyWireYellow:
            case TileEditType.DestroyActuator:
              if (this.Config.AllowWiringProtectedBlocks)
            break;

              if (this.CheckProtected(player, location, false)) {
            player.SendTileSquare(location);
            return true;
              }

              break;
            case TileEditType.PokeLogicGate:
            case TileEditType.Actuate:
              if (this.CheckProtected(player, location, false)) {
            player.SendTileSquare(location);
            return true;
              }

              break;
              }

              return false;
        }
        public void EnsureProtectionData(TSPlayer player)
        {
            int invalidProtectionsCount;
              int invalidRefillChestCount;
              int invalidBankChestCount;

              this.ProtectionManager.EnsureProtectionData(
            false, out invalidProtectionsCount, out invalidRefillChestCount, out invalidBankChestCount);

              if (player != TSPlayer.Server) {
            if (invalidProtectionsCount > 0)
              player.SendWarningMessage("{0} invalid protections removed.", invalidProtectionsCount);
            if (invalidRefillChestCount > 0)
              player.SendWarningMessage("{0} invalid refill chests removed.", invalidRefillChestCount);
            if (invalidBankChestCount > 0)
              player.SendWarningMessage("{0} invalid bank chest instances removed.", invalidBankChestCount);

            player.SendInfoMessage("Finished ensuring protection data.");
              }

              if (invalidProtectionsCount > 0)
            this.PluginTrace.WriteLineWarning("{0} invalid protections removed.", invalidProtectionsCount);
              if (invalidRefillChestCount > 0)
            this.PluginTrace.WriteLineWarning("{0} invalid refill chests removed.", invalidRefillChestCount);
              if (invalidBankChestCount > 0)
            this.PluginTrace.WriteLineWarning("{0} invalid bank chest instances removed.", invalidBankChestCount);

              this.PluginTrace.WriteLineInfo("Finished ensuring protection data.");
        }
        private bool TryCreateAutoProtection(TSPlayer forPlayer, DPoint location)
        {
            try {
            this.ProtectionManager.CreateProtection(forPlayer, location, false);

            if (this.Config.NotifyAutoProtections)
              forPlayer.SendSuccessMessage(string.Format("This {0} has been protected.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)TerrariaUtils.Tiles[location].type)));

            return true;
              } catch (PlayerNotLoggedInException) {
            forPlayer.SendWarningMessage(string.Format(
              "This {0} will not be protected because you're not logged in.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)TerrariaUtils.Tiles[location].type)
            ));
              } catch (LimitEnforcementException) {
            forPlayer.SendWarningMessage(string.Format(
              "This {0} will not be protected because you've reached the protection limit.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)TerrariaUtils.Tiles[location].type)
            ));
              } catch (TileProtectedException) {
            this.PluginTrace.WriteLineError("Error: A block was tried to be auto protected where tile placement should not be possible.");
              } catch (AlreadyProtectedException) {
            this.PluginTrace.WriteLineError("Error: A block was tried to be auto protected on the same position of an existing protection.");
              } catch (Exception ex) {
            this.PluginTrace.WriteLineError("Unexpected exception was thrown during auto protection: \n" + ex);
              }

              return false;
        }
        // Called after (probably) all other plugin's tile edit handlers.
        public virtual bool HandlePostTileEdit(
            TSPlayer player, TileEditType editType, BlockType blockType, DPoint location, int objectStyle
            )
        {
            if (this.IsDisposed || editType != TileEditType.PlaceTile)
            return false;
              if (!this.Config.AutoProtectedTiles[(int)blockType])
            return false;

              Task.Factory.StartNew(() => {
            Thread.Sleep(150);

            Tile tile = TerrariaUtils.Tiles[location];
            if (!tile.active())
              return;

            try {
              this.ProtectionManager.CreateProtection(player, location, false);

              if (this.Config.NotifyAutoProtections)
            player.SendSuccessMessage(string.Format("This {0} has been protected.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)tile.type)));
            } catch (PlayerNotLoggedInException) {
              player.SendWarningMessage(string.Format(
            "This {0} will not be protected because you're not logged in.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)tile.type)
              ));
            } catch (LimitEnforcementException) {
              player.SendWarningMessage(string.Format(
            "This {0} will not be protected because you've reached the protection limit.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)tile.type)
              ));
            } catch (TileProtectedException) {
              this.PluginTrace.WriteLineError("Error: A block was tried to be auto protected where tile placement should not be possible.");
            } catch (AlreadyProtectedException) {
              this.PluginTrace.WriteLineError("Error: A block was tried to be auto protected on the same position of an existing protection.");
            } catch (Exception ex) {
              this.PluginTrace.WriteLineError("Unexpected exception was thrown during auto protection setup: \n" + ex);
            }
              }, TaskCreationOptions.PreferFairness);

              return false;
        }
        public override bool HandleTileEdit(
            TSPlayer player, TileEditType editType, BlockType blockType, DPoint location, int objectStyle
            )
        {
            if (this.IsDisposed)
            return false;
              if (base.HandleTileEdit(player, editType, blockType, location, objectStyle))
            return true;

              switch (editType) {
            case TileEditType.TileKill:
            case TileEditType.TileKillNoItem: {
              // Is the tile really going to be destroyed or just being hit?
              //if (blockType != 0)
              //  break;

              foreach (ProtectionEntry protection in this.ProtectionManager.EnumerateProtectionEntries(location)) {
            // If the protection is invalid, just remove it.
            if (!TerrariaUtils.Tiles.IsValidCoord(protection.TileLocation)) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              continue;
            }

            Tile protectedTile = TerrariaUtils.Tiles[protection.TileLocation];
            // If the protection is invalid, just remove it.
            if (
              !protectedTile.active() ||
              protectedTile.type != (int)protection.BlockType
            ) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              continue;
            }

            string tileName = TerrariaUtils.Tiles.GetBlockTypeName((BlockType)protectedTile.type);
            if (
              protection.Owner == player.User.ID || (
                this.Config.AutoDeprotectEverythingOnDestruction &&
                player.Group.HasPermission(ProtectorPlugin.ProtectionMaster_Permission)
              )
            ) {
              bool isChest = (protectedTile.type == TileID.Containers || protectedTile.type == TileID.Dressers);
              if (isChest) {
                ObjectMeasureData measureData = TerrariaUtils.Tiles.MeasureObject(protection.TileLocation);
                DPoint chestLocation = measureData.OriginTileLocation;
                int chestId = Chest.FindChest(chestLocation.X, chestLocation.Y);

                if (chestId != -1) {
                  bool isBankChest = (protection.BankChestKey != BankChestDataKey.Invalid);
                  if (isBankChest) {
                    Chest.DestroyChestDirect(chestLocation.X, chestLocation.Y, chestId);
                    WorldGen.KillTile(location.X, location.Y);
                    TSPlayer.All.SendData(PacketTypes.TileKill, string.Empty, 3, chestLocation.X, chestLocation.Y, 0f, chestId);
                  } else {
                    Chest tChest = Main.chest[chestId];
                    bool isFilled = tChest.item.Any(i => i != null && i.stack > 0);
                    if (isFilled)
                     break; // Do not remove protections of filled chests.
                  }
                }
              }
              this.ProtectionManager.RemoveProtection(player, protection.TileLocation, false);

              if (this.Config.NotifyAutoDeprotections) {
                player.SendWarningMessage(string.Format("The {0} is not protected anymore.", tileName));
              }
            } else {
              player.SendErrorMessage(string.Format("The {0} is protected.", tileName));
              player.SendTileSquare(location);
              return true;
            }
              }

              break;
            }
            case TileEditType.PlaceWire:
            case TileEditType.DestroyWire:
              if (this.Config.AllowWiringProtectedBlocks)
            break;

              if (this.CheckProtected(player, location, false)) {
            player.SendTileSquare(location);
            return true;
              }

              break;
            case TileEditType.PlaceTile: // As of Terraria 1.2.3, this packet should never be sent for chests.
              // Fix: We do not allow chests to be placed on active stone to prevent players from using the chest duplication bugs.
              // Fix2: Don't allow on ice blocks either, you never know.
              /*if (blockType == BlockType.Chest) {
            for (int x = 0; x < 2; x++) {
              DPoint tileBeneathLocation = location.OffsetEx(x, 1);
              if (
                TerrariaUtils.Tiles[tileBeneathLocation].active() && (
                  TerrariaUtils.Tiles[tileBeneathLocation].type == (int)BlockType.ActiveStone ||
                  TerrariaUtils.Tiles[tileBeneathLocation].type == (int)BlockType.IceRodBlock
                )
              ) {
                TSPlayer.All.SendData(PacketTypes.Tile, string.Empty, 0, location.X, location.Y);

                bool dummy;
                ChestStyle chestStyle = TerrariaUtils.Tiles.GetChestStyle(objectStyle, out dummy);
                int itemType = (int)TerrariaUtils.Tiles.GetItemTypeFromChestType(chestStyle);
                Item.NewItem(location.X * TerrariaUtils.TileSize, location.Y * TerrariaUtils.TileSize, 32, 32, itemType);

                player.SendErrorMessage("Chests can not be placed on active stone or ice blocks.");

                return true;
              }
            }
              }*/

              break;
              }

              return false;
        }
        private bool TryGetProtectionInfo(TSPlayer player, DPoint tileLocation, bool sendFailureMessages = true)
        {
            Tile tile = TerrariaUtils.Tiles[tileLocation];
              if (!tile.active())
            return false;

              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(tileLocation)) {
            protection = enumProtection;
            break;
              }

              BlockType blockType = (BlockType)TerrariaUtils.Tiles[tileLocation].type;
              if (protection == null) {
            if (sendFailureMessages) {
              player.SendErrorMessage(string.Format(
            "This {0} is not protected by Protector at all.", TerrariaUtils.Tiles.GetBlockTypeName(blockType)
              ));
            }

            return false;
              }

              bool canViewExtendedInfo = (
            player.Group.HasPermission(ProtectorPlugin.ViewAllProtections_Permission) ||
            protection.Owner == player.User.ID ||
            protection.IsSharedWithPlayer(player)
              );

              if (!canViewExtendedInfo) {
            player.SendMessage(string.Format(
              "This {0} is protected and not shared with you.", TerrariaUtils.Tiles.GetBlockTypeName(blockType)
            ), Color.LightGray);

            player.SendWarningMessage("You are not permitted to get more information about this protection.");
            return true;
              }

              string ownerName;
              if (protection.Owner == -1) {
            ownerName = "{Server}";
              } else {
            TShockAPI.DB.User tsUser = TShock.Users.GetUserByID(protection.Owner);
            if (tsUser != null)
              ownerName = tsUser.Name;
            else
              ownerName = string.Concat("{deleted user id: ", protection.Owner, "}");
              }

              player.SendMessage(string.Format(
            "This {0} is protected. The owner is {1}.", TerrariaUtils.Tiles.GetBlockTypeName(blockType), ownerName
              ), Color.LightGray);

              string creationTimeFormat = "Protection created On: unknown";
              if (protection.TimeOfCreation != DateTime.MinValue)
            creationTimeFormat = "Protection created On: {0:MM/dd/yy, h:mm tt} UTC ({1} ago)";

              player.SendMessage(
            string.Format(
              CultureInfo.InvariantCulture, creationTimeFormat, protection.TimeOfCreation,
              (DateTime.UtcNow - protection.TimeOfCreation).ToLongString()
            ),
            Color.LightGray
              );

              if (blockType == BlockType.Chest || blockType == BlockType.Dresser) {
            if (protection.RefillChestData != null) {
              RefillChestMetadata refillChest = protection.RefillChestData;
              if (refillChest.RefillTime != TimeSpan.Zero)
            player.SendMessage(string.Format("This is a refill chest with a timer set to {0}.", refillChest.RefillTime.ToLongString()), Color.LightGray);
              else
            player.SendMessage("This is a refill chest without a timer.", Color.LightGray);

              if (refillChest.OneLootPerPlayer || refillChest.RemainingLoots != -1) {
            StringBuilder messageBuilder = new StringBuilder();
            if (refillChest.OneLootPerPlayer)
              messageBuilder.Append("one time by each player");
            if (refillChest.RemainingLoots != -1) {
              if (messageBuilder.Length > 0)
                messageBuilder.Append(" and ");

              messageBuilder.Append(refillChest.RemainingLoots);
              messageBuilder.Append(" more times in total");
            }
            if (refillChest.Looters != null) {
              messageBuilder.Append(" and was looted ");
              messageBuilder.Append(refillChest.Looters.Count);
              messageBuilder.Append(" times until now");
            }

            messageBuilder.Insert(0, "It can only be looted ");
            messageBuilder.Append('.');

            player.SendMessage(messageBuilder.ToString(), Color.LightGray);
              }
            } else if (protection.BankChestKey != BankChestDataKey.Invalid) {
              BankChestDataKey bankChestKey = protection.BankChestKey;
              player.SendMessage(
            string.Format("This is a bank chest instance with the number {0}.", bankChestKey.BankChestIndex), Color.LightGray
              );
            }
              }

              if (ProtectionManager.IsShareableBlockType(blockType)) {
            if (protection.IsSharedWithEveryone) {
              player.SendMessage("Protection is shared with everyone.", Color.LightGray);
              return true;
            }

            StringBuilder sharedListBuilder = new StringBuilder();
            if (protection.SharedUsers != null) {
              for (int i = 0; i < protection.SharedUsers.Count; i++) {
            if (i > 0)
              sharedListBuilder.Append(", ");

            TShockAPI.DB.User tsUser = TShock.Users.GetUserByID(protection.SharedUsers[i]);
            if (tsUser != null)
              sharedListBuilder.Append(tsUser.Name);
              }
            }

            if (sharedListBuilder.Length == 0 && protection.SharedGroups == null) {
              player.SendMessage("Protection is not shared with users or groups.", Color.LightGray);
              return true;
            }

            if (sharedListBuilder.Length > 0)
              player.SendMessage("Shared with users: " + sharedListBuilder, Color.LightGray);
            else
              player.SendMessage("Protection is not shared with users.", Color.LightGray);

            if (protection.SharedGroups != null)
              player.SendMessage("Shared with groups: " + protection.SharedGroups.ToString(), Color.LightGray);
            else
              player.SendMessage("Protection is not shared with groups.", Color.LightGray);
              }

              return true;
        }
        public override bool HandleTileEdit(
            TSPlayer player, TileEditType editType, BlockType blockType, DPoint location, int objectStyle
            )
        {
            if (this.IsDisposed)
            return false;
              if (base.HandleTileEdit(player, editType, blockType, location, objectStyle))
            return true;

              switch (editType) {
            case TileEditType.TileKill:
            case TileEditType.TileKillNoItem: {
              // Is the tile really going to be destroyed or just being hit?
              //if (blockType != 0)
              //  break;

              foreach (ProtectionEntry protection in this.ProtectionManager.EnumerateProtectionEntries(location)) {
            // If the protection is invalid, just remove it.
            if (!TerrariaUtils.Tiles.IsValidCoord(protection.TileLocation)) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              continue;
            }

            Tile protectedTile = TerrariaUtils.Tiles[protection.TileLocation];
            // If the protection is invalid, just remove it.
            if (!protectedTile.active() || protectedTile.type != (int)protection.BlockType) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              continue;
            }

            string tileName = TerrariaUtils.Tiles.GetBlockTypeName((BlockType)protectedTile.type);
            if (
              protection.Owner == player.User.ID || (
                this.Config.AutoDeprotectEverythingOnDestruction &&
                player.Group.HasPermission(ProtectorPlugin.ProtectionMaster_Permission)
              )
            ) {
              bool isChest = (protectedTile.type == TileID.Containers || protectedTile.type == TileID.Dressers);
              if (isChest) {
                ObjectMeasureData measureData = TerrariaUtils.Tiles.MeasureObject(protection.TileLocation);
                DPoint chestLocation = measureData.OriginTileLocation;
                int chestId = Chest.FindChest(chestLocation.X, chestLocation.Y);

                if (chestId != -1) {
                  bool isBankChest = (protection.BankChestKey != BankChestDataKey.Invalid);
                  if (isBankChest) {
                    Chest.DestroyChestDirect(chestLocation.X, chestLocation.Y, chestId);
                    WorldGen.KillTile(location.X, location.Y);
                    TSPlayer.All.SendData(PacketTypes.TileKill, string.Empty, 3, chestLocation.X, chestLocation.Y, 0f, chestId);
                  } else {
                    Chest tChest = Main.chest[chestId];
                    bool isFilled = tChest.item.Any(i => i != null && i.stack > 0);
                    if (isFilled)
                      break; // Do not remove protections of filled chests.
                  }
                }
              }
              this.ProtectionManager.RemoveProtection(player, protection.TileLocation, false);

              if (this.Config.NotifyAutoDeprotections)
                player.SendWarningMessage(string.Format("The {0} is not protected anymore.", tileName));
            } else {
              player.SendErrorMessage(string.Format("The {0} is protected.", tileName));
              player.SendTileSquare(location);
              return true;
            }
              }

              break;
            }
            case TileEditType.PlaceWire:
            case TileEditType.DestroyWire:
              if (this.Config.AllowWiringProtectedBlocks)
            break;

              if (this.CheckProtected(player, location, false)) {
            player.SendTileSquare(location);
            return true;
              }

              break;
              }

              return false;
        }
        public override bool HandleTileEdit(
            TSPlayer player, TileEditType editType, BlockType blockType, DPoint location, int objectStyle
            )
        {
            if (this.IsDisposed)
            return false;
              if (base.HandleTileEdit(player, editType, blockType, location, objectStyle))
            return true;

              switch (editType) {
            case TileEditType.TileKill:
            case TileEditType.TileKillNoItem: {
              // Is the tile really going to be destroyed or just being hit?
              if (blockType != 0)
            break;

              // Because Terraria is dumb-assed, TileKill which is usually only sent on a chest being removed, is also sent
              // when the chest is filled but was hit enought times to be removed, thus we have to work around this by checking
              // if there's content in the chest.
              if (TerrariaUtils.Tiles[location].active() && TerrariaUtils.Tiles[location].type == (int)BlockType.Chest) {
            DPoint chestLocation = TerrariaUtils.Tiles.MeasureObject(location).OriginTileLocation;
            int chestIndex = Chest.FindChest(chestLocation.X, chestLocation.Y);
            // Non existing chests are considered empty.
            if (chestIndex != -1) {
              Chest tChest = Main.chest[chestIndex];
              bool isFilled = tChest.item.Any(i => i != null && i.stack > 0);
              if (isFilled) {
                lock (this.WorldMetadata.Protections) {
                  ProtectionEntry protection;
                  if (
                    !this.WorldMetadata.Protections.TryGetValue(chestLocation, out protection) ||
                    protection.BankChestKey == BankChestDataKey.Invalid
                  ) {
                    break;
                  }
                }
              }
            }
              }

              Tile protectedTile = null;
              foreach (ProtectionEntry protection in this.ProtectionManager.EnumerateProtectionEntries(location)) {
            if (!TerrariaUtils.Tiles.IsValidCoord(protection.TileLocation)) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              protectedTile = null;
              continue;
            }
            protectedTile = TerrariaUtils.Tiles[protection.TileLocation];

            // If the protection is invalid, just remove it.
            if (!protectedTile.active() || protectedTile.type != (int)protection.BlockType) {
              this.ProtectionManager.RemoveProtection(TSPlayer.Server, protection.TileLocation, false);
              protectedTile = null;
              continue;
            }

            if (
              protection.Owner == player.UserID || (
                this.Config.AutoDeprotectEverythingOnDestruction &&
                player.Group.HasPermission(ProtectorPlugin.ProtectionMaster_Permission)
              )
            ) {
              this.ProtectionManager.RemoveProtection(player, protection.TileLocation, false);

              if (this.Config.NotifyAutoDeprotections) {
                player.SendWarningMessage(string.Format(
                  "The {0} is not protected anymore.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)protectedTile.type)
                ));
              }

              protectedTile = null;
              continue;
            }
              }

              if (protectedTile != null) {
            player.SendErrorMessage(string.Format(
              "The {0} is protected.", TerrariaUtils.Tiles.GetBlockTypeName((BlockType)protectedTile.type)
            ));

            player.SendTileSquare(location);
            return true;
              }

              break;
            }
            case TileEditType.PlaceWire:
            case TileEditType.DestroyWire:
              if (this.Config.AllowWiringProtectedBlocks)
            break;

              if (this.CheckProtected(player, location, false)) {
            player.SendTileSquare(location);
            return true;
              }

              break;
            case TileEditType.PlaceTile: // As of Terraria 1.2.3, this packet should never be sent for chests.
              // Fix: We do not allow chests to be placed on active stone to prevent players from using the chest duplication bugs.
              // Fix2: Don't allow on ice blocks either, you never know.
              /*if (blockType == BlockType.Chest) {
            for (int x = 0; x < 2; x++) {
              DPoint tileBeneathLocation = location.OffsetEx(x, 1);
              if (
                TerrariaUtils.Tiles[tileBeneathLocation].active() && (
                  TerrariaUtils.Tiles[tileBeneathLocation].type == (int)BlockType.ActiveStone ||
                  TerrariaUtils.Tiles[tileBeneathLocation].type == (int)BlockType.IceRodBlock
                )
              ) {
                TSPlayer.All.SendData(PacketTypes.Tile, string.Empty, 0, location.X, location.Y);

                bool dummy;
                ChestStyle chestStyle = TerrariaUtils.Tiles.GetChestStyle(objectStyle, out dummy);
                int itemType = (int)TerrariaUtils.Tiles.GetItemTypeFromChestType(chestStyle);
                Item.NewItem(location.X * TerrariaUtils.TileSize, location.Y * TerrariaUtils.TileSize, 32, 32, itemType);

                player.SendErrorMessage("Chests can not be placed on active stone or ice blocks.");

                return true;
              }
            }
              }*/

              break;
              }

              return false;
        }
Beispiel #10
0
 private void RollCommand(TSPlayer sender, string[] arr)
 {
     if (arr.Length > 1)
     {
         switch (arr[1].ToLower())
         {
             case "on":
                 rollOnLoot = true;
                 TSPlayer.All.SendMessage(string.Format("{0} set loot rules to roll-off.", sender.Name), Color.SeaGreen);
                 break;
             case "off":
                 rollOnLoot = false;
                 TSPlayer.All.SendMessage(string.Format("{0} set loot rules to free-for-all.", sender.Name), Color.SeaGreen);
                 break;
             case "list":
                 StringBuilder sb = new StringBuilder();
                 sb.Append("Loot list: ");
                 foreach (var item in itemsToRoll)
                 {
                     sb.Append(string.Format("{0} ({1}),", item.AffixName(),item.stack));
                 }
                 sb.Remove(sb.Length - 1, 1);
                 sender.SendMessage(sb.ToString(), Color.GreenYellow);
                 sb = new StringBuilder();
                 var inQueue = winQueue.Where(q => q.PlayerID == sender.Index).ToList();
                 if (inQueue.Count > 0)
                 {
                     sb = new StringBuilder();
                     sb.Append("Items Won Awaiting space: ");
                     foreach (var item in inQueue)
                     {
                         sb.Append(string.Format("{0} ({1}),",item.Item.AffixName(),item.Item.stack));
                     }
                     sb.Remove(sb.Length - 1, 1);
                     sender.SendMessage(sb.ToString(), Color.Teal);
                 }
                 break;
             case "idle":
                 if (arr.Length < 3)
                     sender.SendInfoMessage("Correct use is /roll idle pass|roll.");
                 else
                 {
                     Player player = players.Where(p => p.Index == sender.Index).FirstOrDefault();
                     switch (arr[2].ToLower())
                     {
                         case "pass":
                             player.PassOnIdle = true;
                             sender.SendInfoMessage("You have chosen to automatically pass on loot if you do not respond.");
                             break;
                         case "roll":
                             player.PassOnIdle = false;
                             sender.SendInfoMessage("You have chosen to automatically roll on loot if you do not respond.");
                             break;
                         default:
                             sender.SendErrorMessage("Proper use is /roll idle pass|roll.");
                             break;
                     }
                 }
                 break;
             case "?":
             case "help":
                 sender.SendInfoMessage("/roll on|off - Toggles loot rolling on item drops.");
                 sender.SendInfoMessage("/roll list - Shows list of items to roll on, and any items awaiting for space in your inventory.");
                 sender.SendInfoMessage("/roll idle pass|roll - Set whether to roll or pass if you're idle on loot rolls.");
                 break;
             default:
                 sender.SendInfoMessage("Invalid use. Proper use is /roll on|off|list|help|?");
                 break;
         }
     }
     else
     {
         if (itemsToRoll.Count <= 0)
         {
             sender.SendWarningMessage("No items to roll on. Type /roll ? or /roll help for more info.");
         }
         else
         {
             Player player = players.Where(p => p.Index == sender.Index).FirstOrDefault();
             if (player.Roll == -1)
                 sender.SendWarningMessage("You already passed on this item!");
             else if (player.Roll != 0)
                 sender.SendWarningMessage(string.Format("You already rolled a {0} on this item! Stop rolling!", player.Roll));
             else
             {
                 Random rnd = new Random();
                 player.Roll = (sbyte)rnd.Next(1, 101);
                 TSPlayer.All.SendInfoMessage(string.Format("{0} rolled a {1}.", player.Name, player.Roll));
                 CheckLootRoll();
             }
         }
     }
 }
Beispiel #11
0
 private void PassCommand(TSPlayer sender)
 {
     if (itemsToRoll.Count <= 0)
     {
         sender.SendWarningMessage("No items to roll on.");
     }
     else
     {
         Player player = players.Where(p => p.Index == sender.Index).FirstOrDefault();
         if (player.Roll != 0)
             sender.SendWarningMessage(string.Format("You already rolled a {0} on this item! Stop rolling!", player.Roll));
         else
         {
             player.Roll = -1;
             TSPlayer.All.SendInfoMessage("{0} passes.",player.Name);
             CheckLootRoll();
         }
     }
 }