Skip to content
This repository has been archived by the owner on Nov 7, 2023. It is now read-only.

Commit

Permalink
feat(infchests-import): allow to import more than 999 chests and fixe…
Browse files Browse the repository at this point in the history
…d some bugs
  • Loading branch information
CoderCow committed May 2, 2017
1 parent 5763616 commit 9065e90
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 53 deletions.
83 changes: 45 additions & 38 deletions Implementation/PluginCooperationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Data;
using System.Diagnostics.Contracts;
using System.IO;
using DPoint = System.Drawing.Point;

Expand All @@ -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<ArgumentNullException>(pluginTrace != null);
Contract.Requires<ArgumentNullException>(config != null);
Contract.Requires<ArgumentNullException>(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 {
Expand All @@ -61,39 +67,39 @@ 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<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);
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);
Expand All @@ -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++;
}
}
Expand Down
3 changes: 2 additions & 1 deletion Implementation/ProtectorPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
13 changes: 3 additions & 10 deletions Implementation/UserInteractionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,15 @@ To get more information about a command type `/<command> 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.

Expand Down

0 comments on commit 9065e90

Please sign in to comment.