Esempio n. 1
0
        protected override IMetadataFile ReadMetadataFromFile(string filePath)
        {
            WorldMetadata result = WorldMetadata.Read(filePath);

            if (result == null)
            {
                throw new FormatException();
            }

            Version fileVersion = new Version(result.Version);

            // Ensure compatibility with older versions
            if (fileVersion < new Version(1, 2))
            {
                foreach (KeyValuePair <DPoint, ProtectionEntry> protectionPair in result.Protections)
                {
                    DPoint          location   = protectionPair.Key;
                    ProtectionEntry protection = protectionPair.Value;

                    if (protection.BlockType == -1)
                    {
                        ITile tile = TerrariaUtils.Tiles[location];
                        if (tile.active())
                        {
                            protection.BlockType = tile.type;
                        }
                    }
                }
            }

            return(result);
        }
Esempio n. 2
0
        public ProtectionEntry CreateProtection(
            TSPlayer player, DPoint tileLocation, bool checkIfBlockTypeProtectableByConfig = true,
            bool checkTShockBuildAndRegionAccess = true, bool checkLimits = true
            )
        {
            Contract.Requires <ArgumentNullException>(player != null);
            Contract.Requires <ArgumentException>(TerrariaUtils.Tiles[tileLocation] != null, "tileLocation");
            Contract.Requires <ArgumentException>(TerrariaUtils.Tiles[tileLocation].active(), "tileLocation");

            Tile      tile      = TerrariaUtils.Tiles[tileLocation];
            BlockType blockType = (BlockType)tile.type;

            tileLocation = TerrariaUtils.Tiles.MeasureObject(tileLocation).OriginTileLocation;

            if (checkIfBlockTypeProtectableByConfig && !this.Config.ManuallyProtectableTiles[tile.type])
            {
                throw new InvalidBlockTypeException(blockType);
            }

            if (checkTShockBuildAndRegionAccess && TShock.CheckTilePermission(player, tileLocation.X, tileLocation.Y))
            {
                throw new TileProtectedException(tileLocation);
            }

            if (
                checkLimits &&
                !player.Group.HasPermission(ProtectorPlugin.NoProtectionLimits_Permission) &&
                this.WorldMetadata.CountUserProtections(player.UserID) >= this.Config.MaxProtectionsPerPlayerPerWorld
                )
            {
                throw new LimitEnforcementException();
            }

            ProtectionEntry protection;

            lock (this.WorldMetadata.Protections) {
                if (this.WorldMetadata.Protections.TryGetValue(tileLocation, out protection))
                {
                    if (protection.Owner == player.UserID)
                    {
                        throw new AlreadyProtectedException();
                    }

                    throw new TileProtectedException(tileLocation);
                }
            }

            protection = new ProtectionEntry(player.UserID, tileLocation, (BlockType)tile.type);

            lock (this.WorldMetadata.Protections)
                this.WorldMetadata.Protections.Add(tileLocation, protection);

            return(protection);
        }
        public bool CheckProtectionAccess(ProtectionEntry protection, TSPlayer player, bool fullAccessRequired = false)
        {
            bool hasAccess = (player.IsLoggedIn && protection.Owner == player.Account.ID);

            if (!hasAccess && !fullAccessRequired)
            {
                hasAccess = player.Group.HasPermission(ProtectorPlugin.UseEverything_Permission);
                if (!hasAccess)
                {
                    hasAccess = protection.IsSharedWithPlayer(player);
                }
            }

            return(hasAccess);
        }
        public void EnsureProtectionData(
            bool resetBankChestContent, out int invalidProtectionsCount, out int invalidRefillChestCount, out int invalidBankChestCount
            )
        {
            invalidRefillChestCount = 0;
            invalidBankChestCount   = 0;

            lock (this.WorldMetadata.Protections) {
                List <DPoint> invalidProtectionLocations = new List <DPoint>();

                foreach (KeyValuePair <DPoint, ProtectionEntry> protectionPair in this.WorldMetadata.Protections)
                {
                    DPoint          location   = protectionPair.Key;
                    ProtectionEntry protection = protectionPair.Value;
                    ITile           tile       = TerrariaUtils.Tiles[location];

                    if (!tile.active() || tile.type != protection.BlockType)
                    {
                        invalidProtectionLocations.Add(location);
                        continue;
                    }

                    UserAccount owner = TShock.UserAccounts.GetUserAccountByID(protection.Owner);
                    if (owner == null)
                    {
                        invalidProtectionLocations.Add(location);
                        continue;
                    }

                    if (protection.RefillChestData != null && !this.ChestManager.EnsureRefillChest(protection))
                    {
                        invalidRefillChestCount++;
                    }
                    else if (protection.BankChestKey != BankChestDataKey.Invalid && !this.ChestManager.EnsureBankChest(protection, resetBankChestContent))
                    {
                        invalidBankChestCount++;
                    }
                }

                foreach (DPoint invalidProtectionLocation in invalidProtectionLocations)
                {
                    this.WorldMetadata.Protections.Remove(invalidProtectionLocation);
                }

                invalidProtectionsCount = invalidProtectionLocations.Count;
            }
        }
Esempio n. 5
0
        private bool RefillChestTimer_Callback(TimerBase timer)
        {
            RefillChestMetadata refillChest = (RefillChestMetadata)timer.Data;

            lock (this.WorldMetadata.Protections) {
                ProtectionEntry protection = this.WorldMetadata.Protections.Values.SingleOrDefault(p => p.RefillChestData == refillChest);
                if (protection == null)
                {
                    return(false);
                }

                DPoint chestLocation = protection.TileLocation;
                this.TryRefillChest(chestLocation, refillChest);

                // Returning true would mean the Timer would repeat.
                return(false);
            }
        }
Esempio n. 6
0
        public bool EnsureRefillChest(ProtectionEntry protection)
        {
            if (protection.RefillChestData == null)
            {
                return(false);
            }

            if (this.ChestFromLocation(protection.TileLocation) == null)
            {
                protection.RefillChestData = null;
                return(false);
            }

            protection.RefillChestData.RefillTimer.Data     = protection.RefillChestData;
            protection.RefillChestData.RefillTimer.Callback = this.RefillTimerCallbackHandler;
            this.RefillTimers.ContinueTimer(protection.RefillChestData.RefillTimer);
            return(true);
        }
        private bool RefillChestTimer_Callback(TimerBase timer)
        {
            RefillChestMetadata refillChest = (RefillChestMetadata)timer.Data;

            lock (this.WorldMetadata.Protections) {
                ProtectionEntry protection = this.WorldMetadata.Protections.Values.SingleOrDefault(p => p.RefillChestData == refillChest);
                if (protection == null)
                {
                    return(false);
                }

                DPoint chestLocation = protection.TileLocation;
                try {
                    this.TryRefillChest(chestLocation, refillChest);
                } catch (InvalidOperationException) {
                    this.PluginTrace.WriteLineWarning($"Chest at position {chestLocation} doesn't seem to exist anymore. Can't refill it.");
                    return(false);
                }

                // Returning true would mean the Timer would repeat.
                return(false);
            }
        }
        private void ProtectionSharePreValidation(
            TSPlayer player, DPoint tileLocation, bool shareOrUnshare, bool checkPermissions, out ProtectionEntry protection
            )
        {
            ITile tile      = TerrariaUtils.Tiles[tileLocation];
            int   blockType = tile.type;

            if (!ProtectionManager.IsShareableBlockType(blockType))
            {
                throw new InvalidBlockTypeException(blockType);
            }

            if (checkPermissions)
            {
                if (
                    (tile.type == TileID.Containers || tile.type == TileID.Containers2 || tile.type == TileID.Dressers) &&
                    !player.Group.HasPermission(ProtectorPlugin.ChestSharing_Permission)
                    )
                {
                    throw new MissingPermissionException(ProtectorPlugin.ChestSharing_Permission);
                }

                if (
                    TerrariaUtils.Tiles.IsSwitchableObject(tile.type) &&
                    !player.Group.HasPermission(ProtectorPlugin.SwitchSharing_Permission)
                    )
                {
                    throw new MissingPermissionException(ProtectorPlugin.SwitchSharing_Permission);
                }

                if (
                    (
                        tile.type == TileID.Signs ||
                        tile.type == TileID.Tombstones ||
                        tile.type == TileID.Beds ||
                        tile.type == TileID.OpenDoor ||
                        tile.type == TileID.ClosedDoor
                    ) &&
                    !player.Group.HasPermission(ProtectorPlugin.OtherSharing_Permission)
                    )
                {
                    throw new MissingPermissionException(ProtectorPlugin.OtherSharing_Permission);
                }
            }

            tileLocation = TerrariaUtils.Tiles.MeasureObject(tileLocation).OriginTileLocation;
            lock (this.WorldMetadata.Protections)
                if (!this.WorldMetadata.Protections.TryGetValue(tileLocation, out protection))
                {
                    throw new NoProtectionException(tileLocation);
                }

            if (checkPermissions)
            {
                if (
                    protection.BankChestKey != BankChestDataKey.Invalid &&
                    !player.Group.HasPermission(ProtectorPlugin.BankChestShare_Permission)
                    )
                {
                    throw new MissingPermissionException(ProtectorPlugin.BankChestShare_Permission);
                }
            }

            if (protection.Owner != player.Account.ID && !player.Group.HasPermission(ProtectorPlugin.ProtectionMaster_Permission))
            {
                if (!protection.IsSharedWithPlayer(player))
                {
                    throw new TileProtectedException(tileLocation);
                }

                if (shareOrUnshare)
                {
                    if (!this.Config.AllowChainedSharing)
                    {
                        throw new TileProtectedException(tileLocation);
                    }
                }
                else if (!this.Config.AllowChainedShareAltering)
                {
                    throw new TileProtectedException(tileLocation);
                }
            }
        }
        public bool CheckBlockAccess(TSPlayer player, DPoint tileLocation, bool fullAccessRequired, out ProtectionEntry relatedProtection)
        {
            foreach (ProtectionEntry protection in this.EnumerateProtectionEntries(tileLocation))
            {
                relatedProtection = protection;

                if (!this.CheckProtectionAccess(protection, player, fullAccessRequired))
                {
                    relatedProtection = protection;
                    return(false);
                }

                // If full access is not required, then there's no use in checking the adjacent blocks.
                if (!fullAccessRequired)
                {
                    return(true);
                }
            }

            relatedProtection = null;
            return(true);
        }
Esempio n. 10
0
        public void InfiniteChests_ChestDataImport(
            ProtectionManager protectionManager,
            out int importedChests, out int overwrittenChests, out int protectFailures
            )
        {
            string sqliteDatabaseFilePath = Path.Combine(TShock.SavePath, "chests.sqlite");

            if (!File.Exists(sqliteDatabaseFilePath))
            {
                throw new FileNotFoundException("Sqlite database file not found.", sqliteDatabaseFilePath);
            }

            IDbConnection dbConnection = null;

            try {
                switch (TShock.Config.StorageType.ToLower())
                {
                case "mysql":
                    string[] host = TShock.Config.MySqlHost.Split(':');
                    dbConnection = new MySqlConnection(string.Format(
                                                           "Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};",
                                                           host[0],
                                                           host.Length == 1 ? "3306" : host[1],
                                                           TShock.Config.MySqlDbName,
                                                           TShock.Config.MySqlUsername,
                                                           TShock.Config.MySqlPassword
                                                           ));

                    break;

                case "sqlite":
                    dbConnection = new SqliteConnection(
                        string.Format("uri=file://{0},Version=3", sqliteDatabaseFilePath)
                        );

                    break;

                default:
                    throw new NotImplementedException("Unsupported database.");
                }

                importedChests    = 0;
                overwrittenChests = 0;
                protectFailures   = 0;
                using (QueryResult reader = dbConnection.QueryReader(
                           "SELECT X, Y, Account, Flags, Items FROM Chests WHERE WorldID = @0", Main.worldID)
                       ) {
                    while (reader.Read())
                    {
                        int    rawX       = reader.Get <int>("X");
                        int    rawY       = reader.Get <int>("Y");
                        string rawAccount = reader.Get <string>("Account");
                        InfiniteChestsChestFlags rawFlags = (InfiniteChestsChestFlags)reader.Get <int>("Flags");
                        string rawItems = reader.Get <string>("Items");

                        if (!TerrariaUtils.Tiles.IsValidCoord(rawX, rawY))
                        {
                            continue;
                        }

                        DPoint chestLocation = new DPoint(rawX, rawY);
                        if (!TerrariaUtils.Tiles[chestLocation].active() || TerrariaUtils.Tiles[chestLocation].type != (int)BlockType.Chest)
                        {
                            this.PluginTrace.WriteLineWarning(string.Format(
                                                                  "The chest data on the location {0} could not be imported because no corresponding chest does exist in the world.",
                                                                  chestLocation
                                                                  ));
                            continue;
                        }

                        // TSPlayer.All means that the chest must not be protected at all.
                        TSPlayer owner = TSPlayer.All;
                        if (!string.IsNullOrEmpty(rawAccount))
                        {
                            User tUser = TShock.Users.GetUserByName(rawAccount);
                            if (tUser != null)
                            {
                                owner = new TSPlayer(0)
                                {
                                    UserID          = tUser.ID,
                                    UserAccountName = tUser.Name,
                                    Group           = TShock.Groups.GetGroupByName(tUser.Group),
                                };
                            }
                            else
                            {
                                // The original owner of the chest does not exist anymore, so we just protect it for the server player.
                                owner = TSPlayer.Server;
                            }
                        }

                        int chestIndex = Chest.FindChest(rawX, rawY);
                        if (chestIndex == -1)
                        {
                            chestIndex = Chest.CreateChest(rawX, rawY);
                        }
                        else
                        {
                            this.PluginTrace.WriteLineWarning(string.Format("The items of the chest {0} were overwritten.", chestLocation));
                            overwrittenChests++;
                        }

                        Chest    tChest   = Main.chest[chestIndex];
                        int[]    itemArgs = new int[60];
                        string[] itemData = rawItems.Split(',');
                        for (int i = 0; i < 120; i++)
                        {
                            itemArgs[i] = int.Parse(itemData[i]);
                        }

                        for (int i = 0; i < 40; i++)
                        {
                            tChest.item[i] = new Item();
                            tChest.item[i].netDefaults(itemArgs[i * 3]);
                            tChest.item[i].prefix = (byte)itemArgs[i * 3 + 2];
                            tChest.item[i].stack  = itemArgs[i * 3 + 1];
                        }
                        importedChests++;

                        if (owner != TSPlayer.All)
                        {
                            try {
                                ProtectionEntry protection = protectionManager.CreateProtection(owner, chestLocation, true, false, false);
                                protection.IsSharedWithEveryone = (rawFlags & InfiniteChestsChestFlags.PUBLIC) != 0;
                                if ((rawFlags & InfiniteChestsChestFlags.REFILL) != 0)
                                {
                                    protectionManager.SetUpRefillChest(owner, chestLocation, TimeSpan.Zero);
                                }
                            } catch (Exception ex) {
                                this.PluginTrace.WriteLineWarning(
                                    "Failed to create protection or define refill chest at {0}:\n{1}", chestLocation, ex
                                    );
                                protectFailures++;
                            }
                        }
                    }
                }
            } finally {
                if (dbConnection != null)
                {
                    dbConnection.Close();
                }
            }
        }
Esempio n. 11
0
        public bool EnsureBankChest(ProtectionEntry protection, bool resetContent)
        {
            if (protection.BankChestKey == BankChestDataKey.Invalid)
            {
                return(false);
            }

            BankChestMetadata bankChest = this.ServerMetadataHandler.EnqueueGetBankChestMetadata(protection.BankChestKey).Result;

            if (bankChest == null)
            {
                protection.BankChestKey = BankChestDataKey.Invalid;
                return(false);
            }

            IChest chest = this.ChestFromLocation(protection.TileLocation);

            if (chest == null)
            {
                protection.BankChestKey = BankChestDataKey.Invalid;
                return(false);
            }

            User owner = TShock.Users.GetUserByID(protection.Owner);

            if (owner == null)
            {
                this.DestroyChest(chest);

                protection.BankChestKey = BankChestDataKey.Invalid;
                return(false);
            }

            Group ownerGroup = TShock.Groups.GetGroupByName(owner.Group);

            if (ownerGroup != null)
            {
                if (protection.SharedUsers != null && !ownerGroup.HasPermission(ProtectorPlugin.BankChestShare_Permission))
                {
                    protection.SharedUsers.Clear();
                }
                if (protection.SharedGroups != null && !ownerGroup.HasPermission(ProtectorPlugin.BankChestShare_Permission))
                {
                    protection.SharedGroups.Clear();
                }
                if (protection.IsSharedWithEveryone && !ownerGroup.HasPermission(ProtectorPlugin.BankChestShare_Permission))
                {
                    protection.IsSharedWithEveryone = false;
                }
            }

            if (resetContent)
            {
                for (int i = 0; i < Chest.maxItems; i++)
                {
                    chest.SetItem(i, bankChest.Items[i]);
                }
            }

            return(true);
        }
        public void InfiniteChests_ChestDataImport(
            ChestManager chestManager, ProtectionManager protectionManager, out int importedChests, out int protectFailures
            )
        {
            Contract.Assert(this.ChestManager != null);

            importedChests  = 0;
            protectFailures = 0;

            IDbConnection dbConnection = null;

            try {
                switch (TShock.Config.StorageType.ToLower())
                {
                case "mysql":
                    string[] host = TShock.Config.MySqlHost.Split(':');
                    dbConnection = new MySqlConnection(string.Format(
                                                           "Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};",
                                                           host[0],
                                                           host.Length == 1 ? "3306" : host[1],
                                                           TShock.Config.MySqlDbName,
                                                           TShock.Config.MySqlUsername,
                                                           TShock.Config.MySqlPassword
                                                           ));

                    break;

                case "sqlite":
                    string sqliteDatabaseFilePath = Path.Combine(TShock.SavePath, "chests.sqlite");
                    if (!File.Exists(sqliteDatabaseFilePath))
                    {
                        throw new FileNotFoundException("Sqlite database file not found.", sqliteDatabaseFilePath);
                    }

                    dbConnection = new SqliteConnection($"uri=file://{sqliteDatabaseFilePath},Version=3");

                    break;

                default:
                    throw new NotImplementedException("Unsupported database.");
                }

                using (QueryResult reader = dbConnection.QueryReader(
                           "SELECT X, Y, Account, Flags, Items, RefillTime FROM Chests WHERE WorldID = @0", Main.worldID)
                       ) {
                    while (reader.Read())
                    {
                        int    rawX       = reader.Get <int>("X");
                        int    rawY       = reader.Get <int>("Y");
                        string rawAccount = reader.Get <string>("Account");
                        InfiniteChestsChestFlags rawFlags = (InfiniteChestsChestFlags)reader.Get <int>("Flags");
                        string rawItems   = reader.Get <string>("Items");
                        int    refillTime = reader.Get <int>("RefillTime");

                        if (!TerrariaUtils.Tiles.IsValidCoord(rawX, rawY))
                        {
                            continue;
                        }

                        DPoint chestLocation = new DPoint(rawX, rawY);
                        ITile  chestTile     = TerrariaUtils.Tiles[chestLocation];
                        if (!chestTile.active() || (chestTile.type != TileID.Containers && chestTile.type != TileID.Containers2 && chestTile.type != TileID.Dressers))
                        {
                            this.PluginTrace.WriteLineWarning($"Chest data at {chestLocation} could not be imported because no corresponding chest tiles exist in the world.");
                            continue;
                        }

                        // TSPlayer.All = chest will not be protected
                        TSPlayer owner = TSPlayer.All;
                        if (!string.IsNullOrEmpty(rawAccount))
                        {
                            UserAccount tUser = TShock.UserAccounts.GetUserAccountByName(rawAccount);
                            if (tUser != null)
                            {
                                owner              = new TSPlayer(0);
                                owner.Account.ID   = tUser.ID;
                                owner.Account.Name = tUser.Name;
                                owner.Group        = TShock.Groups.GetGroupByName(tUser.Group);
                            }
                            else
                            {
                                // The original owner of the chest does not exist anymore, so we just protect it for the server player.
                                owner = TSPlayer.Server;
                            }
                        }

                        IChest importedChest;
                        try {
                            importedChest = this.ChestManager.ChestFromLocation(chestLocation);
                            if (importedChest == null)
                            {
                                importedChest = this.ChestManager.CreateChestData(chestLocation);
                            }
                        } catch (LimitEnforcementException) {
                            this.PluginTrace.WriteLineWarning($"Chest limit of {Main.chest.Length + this.Config.MaxProtectorChests - 1} has been reached!");
                            break;
                        }

                        string[] itemData = rawItems.Split(',');
                        int[]    itemArgs = new int[itemData.Length];
                        for (int i = 0; i < itemData.Length; i++)
                        {
                            itemArgs[i] = int.Parse(itemData[i]);
                        }

                        for (int i = 0; i < 40; i++)
                        {
                            int type   = itemArgs[i * 3];
                            int stack  = itemArgs[i * 3 + 1];
                            int prefix = (byte)itemArgs[i * 3 + 2];

                            importedChest.Items[i] = new ItemData(prefix, type, stack);
                        }
                        importedChests++;

                        if (owner != TSPlayer.All)
                        {
                            try {
                                ProtectionEntry protection = protectionManager.CreateProtection(owner, chestLocation, false, false, false);
                                protection.IsSharedWithEveryone = (rawFlags & InfiniteChestsChestFlags.PUBLIC) != 0;

                                if ((rawFlags & InfiniteChestsChestFlags.REFILL) != 0)
                                {
                                    chestManager.SetUpRefillChest(owner, chestLocation, TimeSpan.FromSeconds(refillTime));
                                }
                            } catch (Exception ex) {
                                this.PluginTrace.WriteLineWarning($"Failed to create protection or define refill chest at {chestLocation}:\n{ex}");
                                protectFailures++;
                            }
                        }
                    }
                }
            } finally {
                dbConnection?.Close();
            }
        }
Esempio n. 13
0
        public void EnsureProtectionData(
            out int invalidProtectionsCount, out int invalidRefillChestCount, out int invalidBankChestCount
            )
        {
            invalidRefillChestCount = 0;
            invalidBankChestCount   = 0;

            lock (this.WorldMetadata.Protections) {
                List <DPoint> invalidProtectionLocations = new List <DPoint>();

                foreach (KeyValuePair <DPoint, ProtectionEntry> protectionPair in this.WorldMetadata.Protections)
                {
                    DPoint          location   = protectionPair.Key;
                    ProtectionEntry protection = protectionPair.Value;
                    Tile            tile       = TerrariaUtils.Tiles[location];

                    if (!tile.active() || (BlockType)tile.type != protection.BlockType)
                    {
                        invalidProtectionLocations.Add(location);
                        continue;
                    }

                    if (protection.RefillChestData != null)
                    {
                        int tChestIndex = Chest.FindChest(location.X, location.Y);
                        if (!tile.active() || tile.type != (int)BlockType.Chest || tChestIndex == -1)
                        {
                            protection.RefillChestData = null;
                            invalidRefillChestCount++;
                            continue;
                        }

                        protection.RefillChestData.RefillTimer.Data     = protection.RefillChestData;
                        protection.RefillChestData.RefillTimer.Callback = this.RefillTimerCallbackHandler;
                        this.RefillTimers.ContinueTimer(protection.RefillChestData.RefillTimer);
                    }
                    if (protection.BankChestKey != BankChestDataKey.Invalid)
                    {
                        BankChestMetadata bankChest = this.ServerMetadataHandler.EnqueueGetBankChestMetadata(protection.BankChestKey).Result;
                        if (bankChest == null)
                        {
                            protection.BankChestKey = BankChestDataKey.Invalid;
                            invalidBankChestCount++;
                            continue;
                        }

                        int tChestIndex = Chest.FindChest(location.X, location.Y);
                        if (!tile.active() || tile.type != (int)BlockType.Chest || tChestIndex == -1)
                        {
                            protection.BankChestKey = BankChestDataKey.Invalid;
                            invalidBankChestCount++;
                            continue;
                        }

                        Chest tChest = Main.chest[tChestIndex];
                        for (int i = 0; i < Chest.maxItems; i++)
                        {
                            tChest.item[i] = bankChest.Items[i].ToItem();
                        }
                    }
                }

                foreach (DPoint invalidProtectionLocation in invalidProtectionLocations)
                {
                    this.WorldMetadata.Protections.Remove(invalidProtectionLocation);
                }


                invalidProtectionsCount = invalidProtectionLocations.Count;
            }
        }