8using Terraria.Utilities;
12 internal static class BackupIO
18 public static bool archiveLock =
false;
19 private static bool IsArchiveOlder(DateTime time, TimeSpan thresholdAge) => (DateTime.Now - time) > thresholdAge;
20 private static string GetArchiveName(
string name,
bool isCloudSave) => name + (isCloudSave ?
"-cloud" :
"");
21 private static string TodaysBackup(
string name,
bool isCloudSave) => $
"{DateTime.Now:yyyy-MM-dd}-{GetArchiveName(name, isCloudSave)}.zip";
22 private static DateTime GetTime(
string file) => Convert.ToDateTime(file.Substring(0, 10));
28 private static void RunArchiving(Action<ZipFile, bool, string> saveAction,
bool isCloudSave,
string dir,
string name,
string path) {
30 Directory.CreateDirectory(dir);
31 DeleteOldArchives(dir, isCloudSave, name);
33 using (var zip =
new ZipFile(Path.Combine(dir, TodaysBackup(name, isCloudSave)), Encoding.UTF8)) {
35 zip.UseZip64WhenSaving = Zip64Option.AsNecessary;
36 zip.ZipErrorAction = ZipErrorAction.Throw;
37 saveAction(zip, isCloudSave, path);
42 Logging.tML.Error(
"A problem occurred when trying to create a backup file.", e);
51 private static void AddZipEntry(
this ZipFile zip,
string path,
bool isCloud =
false) {
52 zip.CompressionMethod = CompressionMethod.Deflate;
53 zip.CompressionLevel = CompressionLevel.BestCompression;
54 zip.Comment = $
"Archived on ${DateTime.Now} by tModLoader";
56 if (!isCloud && (File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory) {
57 zip.AddFiles(Directory.GetFiles(path),
false, Path.GetFileNameWithoutExtension(path));
60 if (isCloud) zip.AddEntry(Path.GetFileName(path), FileUtilities.ReadAllBytes(path,
true));
61 else zip.AddFile(path,
"");
72 private static void DeleteOldArchives(
string dir,
bool isCloudSave,
string name) {
73 var path = Path.Combine(dir, TodaysBackup(name, isCloudSave));
74 if (File.Exists(path)) {
78 var archives =
new DirectoryInfo(dir).GetFiles($
"*{GetArchiveName(name, isCloudSave)}*.zip", SearchOption.TopDirectoryOnly)
79 .OrderBy(f => GetTime(f.Name))
82 FileInfo previous =
null;
84 foreach (var archived
in archives) {
85 if (previous ==
null) {
90 var time = GetTime(archived.Name);
92 IsArchiveOlder(time, TimeSpan.FromDays(30))
93 ? 30 : IsArchiveOlder(time, TimeSpan.FromDays(7))
96 if ((time - GetTime(previous.Name)).Days < freshness) {
97 DeleteArchive(previous.FullName);
103 private static void DeleteArchive(
string path) {
108 Logging.tML.Error(
"Problem deleting old archive file", e);
117 public static readonly
string WorldDir = Path.Combine(Main.SavePath,
"Worlds");
120 internal static void ArchiveWorld(
string path,
bool isCloudSave)
123 private static void WriteArchive(ZipFile zip,
bool isCloudSave,
string path) {
124 if (FileUtilities.Exists(path, isCloudSave)) zip.AddZipEntry(path, isCloudSave);
125 path = Path.ChangeExtension(path,
".twld");
126 if (FileUtilities.Exists(path, isCloudSave)) zip.AddZipEntry(path, isCloudSave);
135 public static readonly
string PlayerDir = Path.Combine(Main.SavePath,
"Players");
144 private static void WriteArchive(ZipFile zip,
bool isCloudSave,
string path) {
146 if (FileUtilities.Exists(path, isCloudSave)) zip.AddZipEntry(path, isCloudSave);
147 path = Path.ChangeExtension(path,
".tplr");
148 if (FileUtilities.Exists(path, isCloudSave)) zip.AddZipEntry(path, isCloudSave);
160 var name = Path.GetFileNameWithoutExtension(path);
161 path = Path.ChangeExtension(path,
"");
162 path = path.Substring(0, path.Length - 1);
164 var cloudFiles = SocialAPI.Cloud.GetFiles().Where(p => p.StartsWith(path, StringComparison.CurrentCultureIgnoreCase)
165 && (p.EndsWith(
".map", StringComparison.CurrentCultureIgnoreCase) || p.EndsWith(
".tmap", StringComparison.CurrentCultureIgnoreCase)));
167 foreach (
string cloudPath
in cloudFiles)
168 zip.AddEntry($
"{name}/{Path.GetFileName(cloudPath)}", FileUtilities.ReadAllBytes(cloudPath,
true));
176 var plrDir = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
177 if (Directory.Exists(plrDir)) zip.AddZipEntry(plrDir);
Responsible for archiving player backups
static void WriteLocalFiles(ZipFile zip, string path)
Write local files, which simply writes the entire player dir
static readonly string PlayerDir
static void WriteArchive(ZipFile zip, bool isCloudSave, string path)
Write the archive. Writes the .plr and .tplr files, then writes the player directory
static void WriteCloudFiles(ZipFile zip, string path)
Write cloud files, which will get the relevant part of the path and write map & tmap files
static void ArchivePlayer(string path, bool isCloudSave)
static readonly string PlayerBackupDir
Responsible for archiving world backups
static void WriteArchive(ZipFile zip, bool isCloudSave, string path)
static readonly string WorldBackupDir
static readonly string WorldDir