tModLoader v0.11.8.9
A mod to make and play Terraria mods
BackupIO.cs
Go to the documentation of this file.
1using Ionic.Zip;
2using Ionic.Zlib;
3using System;
4using System.IO;
5using System.Linq;
6using System.Text;
7using Terraria.Social;
8using Terraria.Utilities;
9
10namespace Terraria.ModLoader
11{
12 internal static class BackupIO
13 {
14 // at the end of WorldGen.generateWorld:
15 // BackupIO.archiveLock = true;
16 // in WorldGen.do_worldGenCallBack after WorldFile.saveWorld:
17 // BackupIO.archiveLock = false;
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));
23
28 private static void RunArchiving(Action<ZipFile, bool, string> saveAction, bool isCloudSave, string dir, string name, string path) {
29 try {
30 Directory.CreateDirectory(dir);
31 DeleteOldArchives(dir, isCloudSave, name);
32
33 using (var zip = new ZipFile(Path.Combine(dir, TodaysBackup(name, isCloudSave)), Encoding.UTF8)) {
34 // use zip64 extensions if necessary for huge files
35 zip.UseZip64WhenSaving = Zip64Option.AsNecessary;
36 zip.ZipErrorAction = ZipErrorAction.Throw;
37 saveAction(zip, isCloudSave, path);
38 zip.Save();
39 }
40 }
41 catch (Exception e) {
42 Logging.tML.Error("A problem occurred when trying to create a backup file.", e);
43 }
44 }
45
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";
55
56 if (!isCloud && (File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory) {
57 zip.AddFiles(Directory.GetFiles(path), false, Path.GetFileNameWithoutExtension(path));
58 }
59 else {
60 if (isCloud) zip.AddEntry(Path.GetFileName(path), FileUtilities.ReadAllBytes(path, true));
61 else zip.AddFile(path, "");
62 }
63 }
64
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)) {
75 DeleteArchive(path);
76 }
77
78 var archives = new DirectoryInfo(dir).GetFiles($"*{GetArchiveName(name, isCloudSave)}*.zip", SearchOption.TopDirectoryOnly)
79 .OrderBy(f => GetTime(f.Name))
80 .ToArray();
81
82 FileInfo previous = null;
83
84 foreach (var archived in archives) {
85 if (previous == null) {
86 previous = archived;
87 continue;
88 }
89
90 var time = GetTime(archived.Name);
91 var freshness =
92 IsArchiveOlder(time, TimeSpan.FromDays(30))
93 ? 30 : IsArchiveOlder(time, TimeSpan.FromDays(7))
94 ? 7 : 1;
95
96 if ((time - GetTime(previous.Name)).Days < freshness) {
97 DeleteArchive(previous.FullName);
98 }
99 previous = archived;
100 }
101 }
102
103 private static void DeleteArchive(string path) {
104 try {
105 File.Delete(path);
106 }
107 catch (Exception e) {
108 Logging.tML.Error("Problem deleting old archive file", e);
109 }
110 }
111
115 public static class World
116 {
117 public static readonly string WorldDir = Path.Combine(Main.SavePath, "Worlds");
118 public static readonly string WorldBackupDir = Path.Combine(WorldDir, "Backups");
119
120 internal static void ArchiveWorld(string path, bool isCloudSave)
121 => RunArchiving(WriteArchive, isCloudSave, WorldBackupDir, Path.GetFileNameWithoutExtension(path), path);
122
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);
127 }
128 }
129
133 public static class Player
134 {
135 public static readonly string PlayerDir = Path.Combine(Main.SavePath, "Players");
136 public static readonly string PlayerBackupDir = Path.Combine(PlayerDir, "Backups");
137
138 public static void ArchivePlayer(string path, bool isCloudSave)
139 => RunArchiving(WriteArchive, isCloudSave, PlayerBackupDir, Path.GetFileNameWithoutExtension(path), path);
140
144 private static void WriteArchive(ZipFile zip, bool isCloudSave, string path) {
145 // Write .plr and .tplr files
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);
149
150 // Write other files, such as tmap files to the zip
151 if (isCloudSave) WriteCloudFiles(zip, path);
152 else WriteLocalFiles(zip, path);
153 }
154
158 private static void WriteCloudFiles(ZipFile zip, string path) {
159 // Path is still equal to local path
160 var name = Path.GetFileNameWithoutExtension(path);
161 path = Path.ChangeExtension(path, "");
162 path = path.Substring(0, path.Length - 1);
163 // Write map files from plr dir in cloud
164 var cloudFiles = SocialAPI.Cloud.GetFiles().Where(p => p.StartsWith(path, StringComparison.CurrentCultureIgnoreCase)
165 && (p.EndsWith(".map", StringComparison.CurrentCultureIgnoreCase) || p.EndsWith(".tmap", StringComparison.CurrentCultureIgnoreCase)));
166
167 foreach (string cloudPath in cloudFiles)
168 zip.AddEntry($"{name}/{Path.GetFileName(cloudPath)}", FileUtilities.ReadAllBytes(cloudPath, true));
169 }
170
174 private static void WriteLocalFiles(ZipFile zip, string path) {
175 // Write map files from plr dir
176 var plrDir = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path));
177 if (Directory.Exists(plrDir)) zip.AddZipEntry(plrDir);
178 }
179 }
180 }
181}
Responsible for archiving player backups
Definition: BackupIO.cs:134
static void WriteLocalFiles(ZipFile zip, string path)
Write local files, which simply writes the entire player dir
Definition: BackupIO.cs:174
static readonly string PlayerDir
Definition: BackupIO.cs:135
static void WriteArchive(ZipFile zip, bool isCloudSave, string path)
Write the archive. Writes the .plr and .tplr files, then writes the player directory
Definition: BackupIO.cs:144
static void WriteCloudFiles(ZipFile zip, string path)
Write cloud files, which will get the relevant part of the path and write map & tmap files
Definition: BackupIO.cs:158
static void ArchivePlayer(string path, bool isCloudSave)
static readonly string PlayerBackupDir
Definition: BackupIO.cs:136
Responsible for archiving world backups
Definition: BackupIO.cs:116
static void WriteArchive(ZipFile zip, bool isCloudSave, string path)
Definition: BackupIO.cs:123
static readonly string WorldBackupDir
Definition: BackupIO.cs:118
static readonly string WorldDir
Definition: BackupIO.cs:117