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); }
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; } }
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); } }
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); }
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(); } } }
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(); } }
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; } }