From 9065e906985429d5ab2d5e281e48ce6fe6e9d0e0 Mon Sep 17 00:00:00 2001 From: CoderCow Date: Tue, 2 May 2017 13:40:46 +0200 Subject: [PATCH] feat(infchests-import): allow to import more than 999 chests and fixed some bugs --- Implementation/PluginCooperationHandler.cs | 83 ++++++++++++---------- Implementation/ProtectorPlugin.cs | 3 +- Implementation/UserInteractionHandler.cs | 13 +--- README.md | 12 ++-- 4 files changed, 58 insertions(+), 53 deletions(-) diff --git a/Implementation/PluginCooperationHandler.cs b/Implementation/PluginCooperationHandler.cs index 6284527..4c62613 100644 --- a/Implementation/PluginCooperationHandler.cs +++ b/Implementation/PluginCooperationHandler.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using System.Diagnostics.Contracts; using System.IO; using DPoint = System.Drawing.Point; @@ -15,35 +16,40 @@ namespace Terraria.Plugins.CoderCow.Protector { public class PluginCooperationHandler { - #region [Nested: InfiniteChestsChestFlags Enum] [Flags] private enum InfiniteChestsChestFlags { PUBLIC = 1, REGION = 2, - REFILL = 4 + REFILL = 4, + BANK = 8 } - #endregion private const string SeconomySomeTypeQualifiedName = "Wolfje.Plugins.SEconomy.SEconomy, Wolfje.Plugins.SEconomy"; public PluginTrace PluginTrace { get; } + public Configuration Config { get; private set; } + public ChestManager ChestManager { get; private set; } public bool IsSeconomyAvailable { get; private set; } - public PluginCooperationHandler(PluginTrace pluginTrace) { + public PluginCooperationHandler(PluginTrace pluginTrace, Configuration config, ChestManager chestManager) { + Contract.Requires(pluginTrace != null); + Contract.Requires(config != null); + Contract.Requires(chestManager != null); + this.PluginTrace = pluginTrace; + this.Config = config; + this.ChestManager = chestManager; this.IsSeconomyAvailable = (Type.GetType(SeconomySomeTypeQualifiedName, false) != null); } #region Infinite Chests public void InfiniteChests_ChestDataImport( - ChestManager chestManager, ProtectionManager protectionManager, - out int importedChests, out int overwrittenChests, out int protectFailures + ChestManager chestManager, ProtectionManager protectionManager, out int importedChests, out int protectFailures ) { - string sqliteDatabaseFilePath = Path.Combine(TShock.SavePath, "chests.sqlite"); - if (!File.Exists(sqliteDatabaseFilePath)) - throw new FileNotFoundException("Sqlite database file not found.", sqliteDatabaseFilePath); + importedChests = 0; + protectFailures = 0; IDbConnection dbConnection = null; try { @@ -61,20 +67,19 @@ public void InfiniteChests_ChestDataImport( break; case "sqlite": - dbConnection = new SqliteConnection( - string.Format("uri=file://{0},Version=3", sqliteDatabaseFilePath) - ); + 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."); } - importedChests = 0; - overwrittenChests = 0; - protectFailures = 0; using (QueryResult reader = dbConnection.QueryReader( - "SELECT X, Y, Account, Flags, Items FROM Chests WHERE WorldID = @0", Main.worldID) + "SELECT X, Y, Account, Flags, Items, RefillTime FROM Chests WHERE WorldID = @0", Main.worldID) ) { while (reader.Read()) { int rawX = reader.Get("X"); @@ -82,18 +87,19 @@ public void InfiniteChests_ChestDataImport( string rawAccount = reader.Get("Account"); InfiniteChestsChestFlags rawFlags = (InfiniteChestsChestFlags)reader.Get("Flags"); string rawItems = reader.Get("Items"); + int refillTime = reader.Get("RefillTime"); if (!TerrariaUtils.Tiles.IsValidCoord(rawX, rawY)) continue; DPoint chestLocation = new DPoint(rawX, rawY); Tile chestTile = TerrariaUtils.Tiles[chestLocation]; - if (!chestTile.active() || chestTile.type != TileID.Containers || chestTile.type != TileID.Containers2) { - this.PluginTrace.WriteLineWarning($"The chest data on the location {chestLocation} could not be imported because no corresponding chest does exist in the world."); + 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 means that the chest must not be protected at all. + // TSPlayer.All = chest will not be protected TSPlayer owner = TSPlayer.All; if (!string.IsNullOrEmpty(rawAccount)) { User tUser = TShock.Users.GetUserByName(rawAccount); @@ -108,38 +114,39 @@ public void InfiniteChests_ChestDataImport( } } - 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++; + 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; } - - Chest tChest = Main.chest[chestIndex]; - int[] itemArgs = new int[60]; + string[] itemData = rawItems.Split(','); - for (int i = 0; i < 120; i++) + 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++) { - 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]; + 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, true, false, false); + 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.Zero); + chestManager.SetUpRefillChest(owner, chestLocation, TimeSpan.FromSeconds(refillTime)); } catch (Exception ex) { - this.PluginTrace.WriteLineWarning( - "Failed to create protection or define refill chest at {0}:\n{1}", chestLocation, ex - ); + this.PluginTrace.WriteLineWarning($"Failed to create protection or define refill chest at {chestLocation}:\n{ex}"); protectFailures++; } } diff --git a/Implementation/ProtectorPlugin.cs b/Implementation/ProtectorPlugin.cs index 7edc0a4..dfa71f1 100644 --- a/Implementation/ProtectorPlugin.cs +++ b/Implementation/ProtectorPlugin.cs @@ -100,12 +100,13 @@ private void Game_PostInitialize(EventArgs e) { if (!this.InitWorldMetdataHandler()) return; - this.PluginCooperationHandler = new PluginCooperationHandler(this.Trace); this.ChestManager = new ChestManager( this.Trace, this.Config, this.ServerMetadataHandler, this.WorldMetadata, this.PluginCooperationHandler); this.ProtectionManager = new ProtectionManager( this.Trace, this.Config, this.ChestManager, this.ServerMetadataHandler, this.WorldMetadata); + this.PluginCooperationHandler = new PluginCooperationHandler(this.Trace, this.Config, this.ChestManager); + this.InitUserInteractionHandler(); this.UserInteractionHandler.EnsureProtectionData(TSPlayer.Server); diff --git a/Implementation/UserInteractionHandler.cs b/Implementation/UserInteractionHandler.cs index ee17238..8c37bb8 100644 --- a/Implementation/UserInteractionHandler.cs +++ b/Implementation/UserInteractionHandler.cs @@ -584,24 +584,17 @@ select pt.TileLocation this.PluginTrace.WriteLineInfo("Importing InfiniteChests data..."); int importedChests; - int overwrittenChests; int protectFailures; try { this.PluginCooperationHandler.InfiniteChests_ChestDataImport( - this.ChestManager, this.ProtectionManager, out importedChests, out overwrittenChests, out protectFailures + this.ChestManager, this.ProtectionManager, out importedChests, out protectFailures ); } catch (FileNotFoundException ex) { - args.Player.SendErrorMessage(string.Format("The \"{0}\" database file was not found.", ex.FileName)); + args.Player.SendErrorMessage($"The \"{ex.FileName}\" database file was not found."); return true; } - args.Player.SendSuccessMessage(string.Format( - "Imported {0} chests. {1} chests were overwritten. Failed to protect {2} chests.", - importedChests, overwrittenChests, protectFailures - )); - args.Player.SendInfoMessage("If refill chests were imported they will have their timer removed and refill instantly now."); - args.Player.SendInfoMessage("You might want to change that by using the /refillchest command."); - args.Player.SendInfoMessage("Note that Protector can not take over the chest handling as long as Infinite Chests is installed."); + args.Player.SendSuccessMessage($"Imported {importedChests} chests. Failed to protect {protectFailures} chests."); return true; } diff --git a/README.md b/README.md index b26395e..5b9b7e8 100644 --- a/README.md +++ b/README.md @@ -101,11 +101,15 @@ To get more information about a command type `/ help` ingame. This plugin can import chest and sign data from the Infinite Chests and Infinite Signs plugins. Make SURE you create world backups before using this functionality -as those changes can otherwise not be revoked. +as those changes can otherwise not be revoked. +Note that the import features aren't very well tested, especially not with more +recent versions of the plugins. + +It's also limited to regular- and refill chests. Bank chests will not be imported. +Also, region chest protection and chest passwords are not supported by Protector. +If your infinite chests database holds more than 999 chests, all exceeding chests +**should** become protector chests. -Protector might be operated together with Infinite Chests / Infinite Signs if -protection of chests, signs and tombstones are not meant to be handled by Protector -at all. Do NOT try to use any chest features of Protector together with Infinite Chests as this will cause mixed item data in the world file and the chest database.