summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/release-notes.md4
-rw-r--r--src/SMAPI.Mods.SaveBackup/ModEntry.cs50
2 files changed, 39 insertions, 15 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index dada7726..b49307c6 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -17,6 +17,10 @@
* Added `performance` command to track mod performance metrics. This is an advanced experimental feature. (Thanks to Drachenkätzchen!)
* Added `test_input` command to view button codes in the console.
+* For the Save Backup mod:
+ * Fixed extra files under `Saves` (e.g. manual backups) not being ignored.
+ * Fixed Android issue where game files were backed up.
+
* For modders:
* Asset propagation for player sprites now affects other players' sprites, and updates recolor maps (e.g. sleeves).
* Reworked the order that asset editors/loaders are called between multiple mods to support some framework mods like Content Patcher and Json Assets. Note that the order is undefined and should not be depended on.
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 _);
+ }
}
}