diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/SMAPI.Mods.SaveBackup/ModEntry.cs | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/src/SMAPI.Mods.SaveBackup/ModEntry.cs b/src/SMAPI.Mods.SaveBackup/ModEntry.cs index 3b47759b..b1d368a1 100644 --- a/src/SMAPI.Mods.SaveBackup/ModEntry.cs +++ b/src/SMAPI.Mods.SaveBackup/ModEntry.cs @@ -68,22 +68,21 @@ namespace StardewModdingAPI.Mods.SaveBackup if (targetFile.Exists || fallbackDir.Exists) return; - // back up saves - this.Monitor.Log($"Backing up saves to {targetFile.FullName}...", LogLevel.Trace); - if (!this.TryCompress(Constants.SavesPath, targetFile, out Exception compressError)) + // copy saves to fallback directory (ignore non-save files/folders) + this.Monitor.Log($"Backing up saves to {fallbackDir.FullName}...", LogLevel.Trace); + DirectoryInfo savesDir = new DirectoryInfo(Constants.SavesPath); + this.RecursiveCopy(savesDir, fallbackDir, copyRoot: false, entry => this.MatchSaveFolders(savesDir, entry)); + + // compress backup if possible + this.Monitor.Log("Compressing backup if possible...", LogLevel.Trace); + if (!this.TryCompress(fallbackDir.FullName, targetFile, out Exception compressError)) { - // log error (expected on Android due to missing compression DLLs) - if (Constants.TargetPlatform == GamePlatform.Android) - this.Monitor.VerboseLog($"Compression isn't supported on Android:\n{compressError}"); - else - { - this.Monitor.Log("Couldn't zip the save backup, creating uncompressed backup instead.", LogLevel.Debug); - this.Monitor.Log(compressError.ToString(), LogLevel.Trace); - } - - // fallback to uncompressed - this.RecursiveCopy(new DirectoryInfo(Constants.SavesPath), fallbackDir, copyRoot: false); + if (Constants.TargetPlatform != GamePlatform.Android) // expected to fail on Android + this.Monitor.Log($"Couldn't compress backup, leaving it uncompressed.\n{compressError}", LogLevel.Trace); } + else + fallbackDir.Delete(recursive: true); + this.Monitor.Log("Backup done!", LogLevel.Trace); } catch (Exception ex) @@ -198,12 +197,16 @@ namespace StardewModdingAPI.Mods.SaveBackup /// <param name="source">The file or folder to copy.</param> /// <param name="targetFolder">The folder to copy into.</param> /// <param name="copyRoot">Whether to copy the root folder itself, or <c>false</c> to only copy its contents.</param> + /// <param name="filter">A filter which matches the files or directories to copy, or <c>null</c> to copy everything.</param> /// <remarks>Derived from the SMAPI installer code.</remarks> - private void RecursiveCopy(FileSystemInfo source, DirectoryInfo targetFolder, bool copyRoot = true) + private void RecursiveCopy(FileSystemInfo source, DirectoryInfo targetFolder, bool copyRoot = true, Func<FileSystemInfo, bool> filter = null) { if (!targetFolder.Exists) targetFolder.Create(); + if (filter?.Invoke(source) == false) + return; + switch (source) { case FileInfo sourceFile: @@ -220,5 +223,22 @@ namespace StardewModdingAPI.Mods.SaveBackup throw new NotSupportedException($"Unknown filesystem info type '{source.GetType().FullName}'."); } } + + /// <summary>A copy filter which matches save folders.</summary> + /// <param name="savesFolder">The folder containing save folders.</param> + /// <param name="entry">The current entry to check under <paramref name="savesFolder"/>.</param> + private bool MatchSaveFolders(DirectoryInfo savesFolder, FileSystemInfo entry) + { + // only need to filter top-level entries + string parentPath = (entry as FileInfo)?.DirectoryName ?? (entry as DirectoryInfo)?.Parent?.FullName; + if (parentPath != savesFolder.FullName) + return true; + + + // match folders with Name_ID format + return + entry is DirectoryInfo + && ulong.TryParse(entry.Name.Split('_').Last(), out _); + } } } |