diff --git a/src/ARKServerManager/App.config b/src/ARKServerManager/App.config index d7a7fbd1..b61d4131 100644 --- a/src/ARKServerManager/App.config +++ b/src/ARKServerManager/App.config @@ -95,7 +95,7 @@ 720 - + ShooterGame\Saved\SavedArks @@ -356,6 +356,9 @@ 12 + + SaveGames + diff --git a/src/ARKServerManager/Config.Designer.cs b/src/ARKServerManager/Config.Designer.cs index ea32bcf9..b9301646 100644 --- a/src/ARKServerManager/Config.Designer.cs +++ b/src/ARKServerManager/Config.Designer.cs @@ -309,9 +309,9 @@ namespace ServerManagerTool { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Configuration.DefaultSettingValueAttribute("ShooterGame\\Saved\\SavedArks")] - public string SavedArksRelativePath { + public string SavedFilesRelativePath { get { - return ((string)(this["SavedArksRelativePath"])); + return ((string)(this["SavedFilesRelativePath"])); } } @@ -3150,5 +3150,14 @@ namespace ServerManagerTool { this["DiscordBotAllServersKeyword"] = value; } } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("SaveGames")] + public string SaveGamesRelativePath { + get { + return ((string)(this["SaveGamesRelativePath"])); + } + } } } diff --git a/src/ARKServerManager/Config.settings b/src/ARKServerManager/Config.settings index 2337fce5..3495f826 100644 --- a/src/ARKServerManager/Config.settings +++ b/src/ARKServerManager/Config.settings @@ -92,7 +92,7 @@ 720 - + ShooterGame\Saved\SavedArks @@ -866,5 +866,8 @@ all + + SaveGames + \ No newline at end of file diff --git a/src/ARKServerManager/Lib/ServerApp.cs b/src/ARKServerManager/Lib/ServerApp.cs index f882d92c..7cc162ca 100644 --- a/src/ARKServerManager/Lib/ServerApp.cs +++ b/src/ARKServerManager/Lib/ServerApp.cs @@ -2008,6 +2008,7 @@ namespace ServerManagerTool.Lib { LogProfileMessage("Back up world files started..."); + var worldFileName = Path.GetFileName(worldFile); var backupFolder = GetServerBackupFolder(_profile); var mapName = ServerProfile.GetProfileMapFileName(_profile.ServerMap, _profile.PGM_Enabled, _profile.PGM_Name); var backupFileName = $"{mapName}_{_startTime:yyyyMMdd_HHmmss}{Config.Default.BackupExtension}"; @@ -2019,36 +2020,6 @@ namespace ServerManagerTool.Lib if (File.Exists(backupFile)) File.Delete(backupFile); - var files = new List - { - worldFile - }; - - // get the player files - var saveFolderInfo = new DirectoryInfo(saveFolder); - var playerFileFilter = $"*{Config.Default.PlayerFileExtension}"; - var playerFiles = saveFolderInfo.GetFiles(playerFileFilter, SearchOption.TopDirectoryOnly); - foreach (var file in playerFiles) - { - files.Add(file.FullName); - } - - // get the tribe files - var tribeFileFilter = $"*{Config.Default.TribeFileExtension}"; - var tribeFiles = saveFolderInfo.GetFiles(tribeFileFilter, SearchOption.TopDirectoryOnly); - foreach (var file in tribeFiles) - { - files.Add(file.FullName); - } - - // get the tribute tribe files - var tributeTribeFileFilter = $"*{Config.Default.TributeTribeFileExtension}"; - var tributeTribeFiles = saveFolderInfo.GetFiles(tributeTribeFileFilter, SearchOption.TopDirectoryOnly); - foreach (var file in tributeTribeFiles) - { - files.Add(file.FullName); - } - var comment = new StringBuilder(); comment.AppendLine($"Windows Platform: {Environment.OSVersion.Platform}"); comment.AppendLine($"Windows Version: {Environment.OSVersion.VersionString}"); @@ -2061,7 +2032,48 @@ namespace ServerManagerTool.Lib comment.AppendLine($"PGM Server: {_profile.PGM_Enabled}"); comment.AppendLine($"Process: {ServerProcess}"); - ZipUtils.ZipFiles(backupFile, files, comment.ToString(), false); + var saveFolderInfo = new DirectoryInfo(saveFolder); + + // backup the world save file + ZipUtils.ZipAFile(backupFile, worldFileName, worldFile, comment.ToString()); + + // backup the player files + var playerFileFilter = $"*{Config.Default.PlayerFileExtension}"; + var playerFiles = saveFolderInfo.GetFiles(playerFileFilter, SearchOption.TopDirectoryOnly); + foreach (var file in playerFiles) + { + ZipUtils.ZipAFile(backupFile, file.Name, file.FullName); + } + + // backup the tribe files + var tribeFileFilter = $"*{Config.Default.TribeFileExtension}"; + var tribeFiles = saveFolderInfo.GetFiles(tribeFileFilter, SearchOption.TopDirectoryOnly); + foreach (var file in tribeFiles) + { + ZipUtils.ZipAFile(backupFile, file.Name, file.FullName); + } + + // backup the tribute tribe files + var tributeTribeFileFilter = $"*{Config.Default.TributeTribeFileExtension}"; + var tributeTribeFiles = saveFolderInfo.GetFiles(tributeTribeFileFilter, SearchOption.TopDirectoryOnly); + foreach (var file in tributeTribeFiles) + { + ZipUtils.ZipAFile(backupFile, file.Name, file.FullName); + } + + // backup the save games files + var saveGamesFolder = GetServerSaveGamesFolder(); + if (Directory.Exists(saveGamesFolder)) + { + var saveGamesFolderInfo = new DirectoryInfo(saveGamesFolder); + + var saveGamesFileFilter = $"*"; + var saveGamesFiles = saveGamesFolderInfo.GetFiles(saveGamesFileFilter, SearchOption.AllDirectories); + foreach (var file in saveGamesFiles) + { + ZipUtils.ZipAFile(backupFile, file.FullName.Replace(saveGamesFolder, Config.Default.SaveGamesRelativePath), file.FullName); + } + } LogProfileMessage($"Backed up world files - {saveFolder}"); LogProfileMessage($"Backup file created - {backupFile}"); @@ -2404,6 +2416,8 @@ namespace ServerManagerTool.Lib private string GetServerSaveFolder() => IOUtils.NormalizePath(ServerProfile.GetProfileSavePath(_profile.InstallDirectory, _profile.AltSaveDirectoryName, _profile.PGM_Enabled, _profile.PGM_Name)); + private string GetServerSaveGamesFolder() => IOUtils.NormalizePath(ServerProfile.GetProfileSaveGamesPath(_profile.InstallDirectory)); + private string GetServerVersionFile() => IOUtils.NormalizePath(Path.Combine(_profile.InstallDirectory, Config.Default.VersionFile)); public static Version GetServerVersion(string versionFile) diff --git a/src/ARKServerManager/Lib/ServerProfile.cs b/src/ARKServerManager/Lib/ServerProfile.cs index b4caab4e..91343ce2 100644 --- a/src/ARKServerManager/Lib/ServerProfile.cs +++ b/src/ARKServerManager/Lib/ServerProfile.cs @@ -4830,6 +4830,7 @@ namespace ServerManagerTool.Lib var mapName = GetProfileMapFileName(this); var worldFileName = $"{mapName}{Config.Default.MapExtension}"; + var saveGamesFolder = GetProfileSaveGamesPath(this); // check if the archive file contains the world save file at minimum if (isArchiveFile) @@ -4854,11 +4855,12 @@ namespace ServerManagerTool.Lib var worldFile = IOUtils.NormalizePath(Path.Combine(saveFolder, worldFileName)); var restoreFileInfo = new FileInfo(restoreFile); - int restoredFileCount; + var restoredFileCount = 0; if (isArchiveFile) { // create a list of files to be deleted + var directories = new List(); var files = new List { worldFile @@ -4892,13 +4894,10 @@ namespace ServerManagerTool.Lib files.Add(file.FullName); } - //// get the player images files - //var playerImageFileFilter = $"*{Config.Default.PlayerImageFileExtension}"; - //var playerImageFiles = saveFolderInfo.GetFiles(playerImageFileFilter, SearchOption.TopDirectoryOnly); - //foreach (var file in playerImageFiles) - //{ - // files.Add(file.FullName); - //} + if (Directory.Exists(saveGamesFolder) && ZipUtils.DoesFolderExist(restoreFile, Config.Default.SaveGamesRelativePath)) + { + directories.Add(saveGamesFolder); + } } // delete the selected files @@ -4914,14 +4913,32 @@ namespace ServerManagerTool.Lib } } + foreach (var directory in directories) + { + try + { + Directory.Delete(directory, true); + } + catch + { + // if unable to delete, do not bother + } + } + // restore the files from the backup if (restoreAll) { - restoredFileCount = ZipUtils.ExtractAllFiles(restoreFile, saveFolder); + restoredFileCount += ZipUtils.ExtractFiles(restoreFile, saveFolder, sourceFolder: "", recurseFolders: false); + + if (ZipUtils.DoesFolderExist(restoreFile, Config.Default.SaveGamesRelativePath)) + { + var rootSaveFolder = Path.GetDirectoryName(saveGamesFolder); + restoredFileCount += ZipUtils.ExtractFiles(restoreFile, rootSaveFolder, Config.Default.SaveGamesRelativePath, recurseFolders: true); + } } else { - restoredFileCount = ZipUtils.ExtractAFile(restoreFile, worldFileName, saveFolder); + restoredFileCount += ZipUtils.ExtractAFile(restoreFile, worldFileName, saveFolder); } } else @@ -6691,6 +6708,16 @@ namespace ServerManagerTool.Lib return ModUtils.GetMapName(serverMap); } + public static string GetProfileSaveGamesPath(ServerProfile profile) + { + return GetProfileSaveGamesPath(profile?.InstallDirectory); + } + + public static string GetProfileSaveGamesPath(string installDirectory) + { + return Path.Combine(installDirectory ?? string.Empty, Config.Default.SavedRelativePath, Config.Default.SaveGamesRelativePath); + } + public static string GetProfileSavePath(ServerProfile profile) { return GetProfileSavePath(profile?.InstallDirectory, profile?.AltSaveDirectoryName, profile?.PGM_Enabled ?? false, profile?.PGM_Name); @@ -6706,8 +6733,8 @@ namespace ServerManagerTool.Lib } if (pgmEnabled) - return Path.Combine(installDirectory ?? string.Empty, Config.Default.SavedArksRelativePath, Config.Default.SavedPGMRelativePath, pgmName ?? string.Empty); - return Path.Combine(installDirectory ?? string.Empty, Config.Default.SavedArksRelativePath); + return Path.Combine(installDirectory ?? string.Empty, Config.Default.SavedFilesRelativePath, Config.Default.SavedPGMRelativePath, pgmName ?? string.Empty); + return Path.Combine(installDirectory ?? string.Empty, Config.Default.SavedFilesRelativePath); } #endregion diff --git a/src/ARKServerManager/VersionFeed.xml b/src/ARKServerManager/VersionFeed.xml index 890820a0..b2ae085d 100644 --- a/src/ARKServerManager/VersionFeed.xml +++ b/src/ARKServerManager/VersionFeed.xml @@ -5,7 +5,31 @@ Ark Server Manager Version Feed This is the Ark Server Manager release version feed. - 2022-04-23T00:00:00Z + 2022-05-02T00:00:00Z + + + urn:uuid:018EF426-73B9-4BF6-9602-77EE2CFD864C + 1.1.424 (1.1.424.1) + 1.1.424.1 + + 2022-05-02T00:00:00Z + +
+

+ CHANGE +
+

    +
  • World Save Backup - added the SaveGames folder to the to the backup zip file.
  • +
  • World Save Restore - now restores the SaveGames folder.
  • +
+

+
+
+ + bletch + bletch1971@hotmail.com + +
urn:uuid:8AD6F2C4-D9BD-41D5-BE91-DA23F31A2FA4 diff --git a/src/ARKServerManager/VersionFeedBeta.xml b/src/ARKServerManager/VersionFeedBeta.xml index 143ce664..40ac0484 100644 --- a/src/ARKServerManager/VersionFeedBeta.xml +++ b/src/ARKServerManager/VersionFeedBeta.xml @@ -5,28 +5,22 @@ Ark Server Manager Version Feed This is the Ark Server Manager beta version feed. - 2022-04-23T00:00:00Z + 2022-05-02T00:00:00Z - urn:uuid:8AD6F2C4-D9BD-41D5-BE91-DA23F31A2FA4 - 1.1.423 (1.1.423.1) - 1.1.423.1 + urn:uuid:018EF426-73B9-4BF6-9602-77EE2CFD864C + 1.1.424 (1.1.424.1) + 1.1.424.1 - 2022-04-23T00:00:00Z + 2022-05-02T00:00:00Z

- BUGFIX -
-

    -
  • Fixed the discord bot Info command, to release the profile once the command has finished running.
  • -
CHANGE
    -
  • Profile Discord Settings - added new checkbox to allow the profile to be included in discord commands using the Cluster Id as the alias.
  • -
  • Realigned the default Player and Creature levels to the wiki.
  • -
  • pt-BR Translation file updated.
  • +
  • World Save Backup - added the SaveGames folder to the to the backup zip file.
  • +
  • World Save Restore - now restores the SaveGames folder.

diff --git a/src/ConanServerManager/App.config b/src/ConanServerManager/App.config index 8d02cc0d..5d711632 100644 --- a/src/ConanServerManager/App.config +++ b/src/ConanServerManager/App.config @@ -87,7 +87,7 @@ ConanSandbox\Mods
- Saved + ConanSandbox\Saved workshopcache_440900.json @@ -272,6 +272,9 @@ 12 + + SaveGames + diff --git a/src/ConanServerManager/Config.Designer.cs b/src/ConanServerManager/Config.Designer.cs index 9e8787ec..4c0f823b 100644 --- a/src/ConanServerManager/Config.Designer.cs +++ b/src/ConanServerManager/Config.Designer.cs @@ -487,7 +487,7 @@ namespace ServerManagerTool { [global::System.Configuration.ApplicationScopedSettingAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("Saved")] + [global::System.Configuration.DefaultSettingValueAttribute("ConanSandbox\\Saved")] public string SavedRelativePath { get { return ((string)(this["SavedRelativePath"])); @@ -2333,5 +2333,14 @@ namespace ServerManagerTool { this["DiscordBotAllServersKeyword"] = value; } } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("SaveGames")] + public string SaveGamesRelativePath { + get { + return ((string)(this["SaveGamesRelativePath"])); + } + } } } diff --git a/src/ConanServerManager/Config.settings b/src/ConanServerManager/Config.settings index 5f303707..dd4ed29d 100644 --- a/src/ConanServerManager/Config.settings +++ b/src/ConanServerManager/Config.settings @@ -135,7 +135,7 @@ False - Saved + ConanSandbox\Saved False @@ -641,5 +641,8 @@ all + + SaveGames + \ No newline at end of file diff --git a/src/ConanServerManager/Lib/ServerApp.cs b/src/ConanServerManager/Lib/ServerApp.cs index ef374b27..fff67b01 100644 --- a/src/ConanServerManager/Lib/ServerApp.cs +++ b/src/ConanServerManager/Lib/ServerApp.cs @@ -1925,8 +1925,8 @@ namespace ServerManagerTool.Lib if (Directory.Exists(saveFolder)) { // make a backup of the current world file. - var worldBackupFile = GetServerWorldBackupFile(); - if (File.Exists(worldBackupFile)) + var worldFile = GetServerWorldBackupFile(); + if (File.Exists(worldFile)) { try { @@ -1944,8 +1944,6 @@ namespace ServerManagerTool.Lib if (File.Exists(backupFile)) File.Delete(backupFile); - var files = new List(); - var comment = new StringBuilder(); comment.AppendLine($"Windows Platform: {Environment.OSVersion.Platform}"); comment.AppendLine($"Windows Version: {Environment.OSVersion.VersionString}"); @@ -1956,9 +1954,24 @@ namespace ServerManagerTool.Lib comment.AppendLine($"Profile Name: {_profile.ProfileName}"); comment.AppendLine($"Process: {ServerProcess}"); - ZipUtils.ZipAFile(backupFile, worldFileName, worldBackupFile, comment.ToString()); - if (files.Count > 0) - ZipUtils.UpdateFiles(backupFile, files, null, false, ""); + var saveFolderInfo = new DirectoryInfo(saveFolder); + + // backup the world save file + ZipUtils.ZipAFile(backupFile, worldFileName, worldFile, comment.ToString()); + + // backup the save games files + var saveGamesFolder = GetServerSaveGamesFolder(); + if (Directory.Exists(saveGamesFolder)) + { + var saveGamesFolderInfo = new DirectoryInfo(saveGamesFolder); + + var saveGamesFileFilter = $"*"; + var saveGamesFiles = saveGamesFolderInfo.GetFiles(saveGamesFileFilter, SearchOption.AllDirectories); + foreach (var file in saveGamesFiles) + { + ZipUtils.ZipAFile(backupFile, file.FullName.Replace(saveGamesFolder, Config.Default.SaveGamesRelativePath), file.FullName); + } + } LogProfileMessage($"Backed up world files - {saveFolder}"); LogProfileMessage($"Backup file created - {backupFile}"); @@ -1986,12 +1999,12 @@ namespace ServerManagerTool.Lib } else { - LogProfileMessage($"Server save file does not exist or could not be found '{worldBackupFile}'."); + LogProfileMessage($"Server save file does not exist or could not be found '{worldFile}'."); LogProfileMessage($"Backup not performed."); emailMessage?.AppendLine(); emailMessage?.AppendLine($"Server save file does not exist or could not be found."); - emailMessage?.AppendLine(worldBackupFile); + emailMessage?.AppendLine(worldFile); emailMessage?.AppendLine(); emailMessage?.AppendLine("Backup not performed."); @@ -2289,6 +2302,8 @@ namespace ServerManagerTool.Lib private string GetServerSaveFolder() => IOUtils.NormalizePath(Path.Combine(_profile.InstallDirectory, Config.Default.SavedFilesRelativePath)); + private string GetServerSaveGamesFolder() => IOUtils.NormalizePath(ServerProfile.GetProfileSaveGamesPath(_profile.InstallDirectory)); + private string GetServerVersionFile() => IOUtils.NormalizePath(Path.Combine(_profile.InstallDirectory, Config.Default.ServerBinaryRelativePath, Config.Default.ServerExeFile)); public static Version GetServerVersion(string versionFile) diff --git a/src/ConanServerManager/Lib/ServerProfile.cs b/src/ConanServerManager/Lib/ServerProfile.cs index a1962da5..b5b3f71d 100644 --- a/src/ConanServerManager/Lib/ServerProfile.cs +++ b/src/ConanServerManager/Lib/ServerProfile.cs @@ -1320,7 +1320,7 @@ namespace ServerManagerTool.Lib return JsonUtils.Serialize(this); } - public int RestoreSaveFiles(string restoreFile, bool isArchiveFile) + public int RestoreSaveFiles(string restoreFile, bool isArchiveFile, bool restoreAll) { if (string.IsNullOrWhiteSpace(restoreFile) || !File.Exists(restoreFile)) { @@ -1336,6 +1336,7 @@ namespace ServerManagerTool.Lib } var worldFileName = ServerMapSaveFileName; + var saveGamesFolder = GetProfileSaveGamesPath(this); // check if the archive file contains the world save file at minimum if (isArchiveFile) @@ -1365,12 +1366,23 @@ namespace ServerManagerTool.Lib if (isArchiveFile) { // create a list of files to be deleted - var files = new List(); - // add the current world save file - files.Add(worldFile); + var directories = new List(); + var files = new List + { + worldFile, + }; + // add the world save support files files.AddRange(Directory.GetFiles(saveFolder, $"{worldFileName}-*")); + if (restoreAll) + { + if (Directory.Exists(saveGamesFolder) && ZipUtils.DoesFolderExist(restoreFile, Config.Default.SaveGamesRelativePath)) + { + directories.Add(saveGamesFolder); + } + } + // delete the selected files foreach (var file in files) { @@ -1384,8 +1396,33 @@ namespace ServerManagerTool.Lib } } - // restore the files from the backup - restoredFileCount = ZipUtils.ExtractAFile(restoreFile, worldFileName, saveFolder); + foreach (var directory in directories) + { + try + { + Directory.Delete(directory, true); + } + catch + { + // if unable to delete, do not bother + } + } + + if (restoreAll) + { + // restore the files from the backup + restoredFileCount += ZipUtils.ExtractFiles(restoreFile, saveFolder, sourceFolder: "", recurseFolders: false); + + if (ZipUtils.DoesFolderExist(restoreFile, Config.Default.SaveGamesRelativePath)) + { + var rootSaveFolder = Path.GetDirectoryName(saveGamesFolder); + restoredFileCount += ZipUtils.ExtractFiles(restoreFile, rootSaveFolder, Config.Default.SaveGamesRelativePath, recurseFolders: true); + } + } + else + { + restoredFileCount += ZipUtils.ExtractAFile(restoreFile, worldFileName, saveFolder); + } } else { @@ -1768,6 +1805,16 @@ namespace ServerManagerTool.Lib return ModUtils.GetMapName(serverMap); } + public static string GetProfileSaveGamesPath(ServerProfile profile) + { + return GetProfileSaveGamesPath(profile?.InstallDirectory); + } + + public static string GetProfileSaveGamesPath(string installDirectory) + { + return Path.Combine(installDirectory ?? string.Empty, Config.Default.SavedRelativePath, Config.Default.SaveGamesRelativePath); + } + public static string GetProfileSavePath(ServerProfile profile) { return GetProfileSavePath(profile?.InstallDirectory); diff --git a/src/ConanServerManager/VersionFeed.xml b/src/ConanServerManager/VersionFeed.xml index abb3813e..9a294781 100644 --- a/src/ConanServerManager/VersionFeed.xml +++ b/src/ConanServerManager/VersionFeed.xml @@ -5,7 +5,31 @@ Conan Server Manager Version Feed This is the Conan Server Manager release version feed. - 2022-04-23T00:00:00Z + 2022-05-02T00:00:00Z + + + urn:uuid:FF2C83B2-6D10-4217-A021-5B5F090FC480 + 1.1.68 (1.1.68.1) + 1.1.68.1 + + 2022-05-02T00:00:00Z + +
+

+ CHANGE +
+

    +
  • World Save Backup - added the SaveGames folder to the to the backup zip file.
  • +
  • World Save Restore - now restores the SaveGames folder.
  • +
+

+
+
+ + bletch + bletch1971@hotmail.com + +
urn:uuid:E482A8A4-88C3-4517-A4DD-B954811F4F13 diff --git a/src/ConanServerManager/VersionFeedBeta.xml b/src/ConanServerManager/VersionFeedBeta.xml index 801b398b..29781573 100644 --- a/src/ConanServerManager/VersionFeedBeta.xml +++ b/src/ConanServerManager/VersionFeedBeta.xml @@ -5,26 +5,22 @@ Conan Server Manager Version Feed This is the Conan Server Manager beta version feed. - 2022-04-23T00:00:00Z + 2022-05-02T00:00:00Z - urn:uuid:E482A8A4-88C3-4517-A4DD-B954811F4F13 - 1.1.67 (1.1.67.1) - 1.1.67.1 + urn:uuid:FF2C83B2-6D10-4217-A021-5B5F090FC480 + 1.1.68 (1.1.68.1) + 1.1.68.1 - 2022-04-23T00:00:00Z + 2022-05-02T00:00:00Z

- BUGFIX + CHANGE

    -
  • Fixed the discord bot Info command, to release the profile once the command has finished running.
  • -
- NEW -
-
    -
  • ru-RU Translation file added.
  • +
  • World Save Backup - added the SaveGames folder to the to the backup zip file.
  • +
  • World Save Restore - now restores the SaveGames folder.

diff --git a/src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml.cs b/src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml.cs index 35e3476f..045d2629 100644 --- a/src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml.cs +++ b/src/ConanServerManager/Windows/WorldSaveRestoreWindow.xaml.cs @@ -220,7 +220,7 @@ namespace ServerManagerTool Application.Current.Dispatcher.Invoke(() => this.Cursor = System.Windows.Input.Cursors.Wait); await Task.Delay(500); - var restoredFileCount = _profile.RestoreSaveFiles(item.File, item.IsArchiveFile); + var restoredFileCount = _profile.RestoreSaveFiles(item.File, item.IsArchiveFile, true); var successMessage = _globalizer.GetResourceString("WorldSaveRestore_RestoreSuccessLabel"); successMessage = successMessage.Replace("{fileCount}", restoredFileCount.ToString()); diff --git a/src/Server-Managers.sln b/src/Server-Managers.sln index 3e19ae51..27809f16 100644 --- a/src/Server-Managers.sln +++ b/src/Server-Managers.sln @@ -46,6 +46,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plugin.Discord.UnitTests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerManager.Discord", "ServerManager.Discord\ServerManager.Discord.csproj", "{C4C8000D-5E45-497C-A218-B95A1567010E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{A7B846EF-9884-44DB-AF8F-3173DF1B3B66}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerManager.Common.UnitTests", "ServerManager.Common.UnitTests\ServerManager.Common.UnitTests.csproj", "{18271A4E-6135-466A-BCF8-80E25446F454}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug - AutoBackup|Any CPU = Debug - AutoBackup|Any CPU @@ -260,6 +264,18 @@ Global {C4C8000D-5E45-497C-A218-B95A1567010E}.Debug|Any CPU.Build.0 = Debug|Any CPU {C4C8000D-5E45-497C-A218-B95A1567010E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C4C8000D-5E45-497C-A218-B95A1567010E}.Release|Any CPU.Build.0 = Release|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - AutoBackup|Any CPU.ActiveCfg = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - AutoBackup|Any CPU.Build.0 = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - AutoShutdown|Any CPU.ActiveCfg = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - AutoShutdown|Any CPU.Build.0 = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - AutoUpdate|Any CPU.ActiveCfg = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - AutoUpdate|Any CPU.Build.0 = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - Beta|Any CPU.ActiveCfg = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug - Beta|Any CPU.Build.0 = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18271A4E-6135-466A-BCF8-80E25446F454}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -274,6 +290,7 @@ Global {4CA9C894-518F-42D7-BBE2-CFDFE7A03F8A} = {44D8A1A2-01FF-4DD3-A201-AD9A26F7798D} {A8BFC452-5BE8-41E7-BD1D-C29B944185CE} = {F8DBCE70-4658-47CB-A508-B3951125F0ED} {1434D87A-E9FC-48B9-BEC9-E5A3003F1F2E} = {F8DBCE70-4658-47CB-A508-B3951125F0ED} + {18271A4E-6135-466A-BCF8-80E25446F454} = {A7B846EF-9884-44DB-AF8F-3173DF1B3B66} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4201246C-6E53-4209-883D-A4F084C19187} diff --git a/src/ServerManager.Common.UnitTests/ServerManager.Common.UnitTests.csproj b/src/ServerManager.Common.UnitTests/ServerManager.Common.UnitTests.csproj new file mode 100644 index 00000000..684fb8fe --- /dev/null +++ b/src/ServerManager.Common.UnitTests/ServerManager.Common.UnitTests.csproj @@ -0,0 +1,23 @@ + + + net462 + false + ServerManager.Common.UnitTests + ServerManager.Common.UnitTests + + + none + false + + + + + + + + + + + + + diff --git a/src/ServerManager.Common.UnitTests/ZipUtilsUnitTest.cs b/src/ServerManager.Common.UnitTests/ZipUtilsUnitTest.cs new file mode 100644 index 00000000..ee8e43f1 --- /dev/null +++ b/src/ServerManager.Common.UnitTests/ZipUtilsUnitTest.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using ServerManagerTool.Common.Utils; + +namespace ServerManager.Common.Tests +{ + [TestClass] + public class ZipUtilsUnitTest + { + [TestMethod] + public void ZipUtils_() + { + // Arrange + var zipFile = FetchZipFile(); + var destinationPath = Path.Combine(@"D:\_smtest", Path.GetFileNameWithoutExtension(zipFile)); + var destinationPath1 = Path.Combine(destinationPath, "SavedArks"); + + // Act + var count = ZipUtils.ExtractFiles(zipFile, destinationPath1, recurseFolders: false); + // Assert + Assert.AreEqual(3, count); + + // Act + var exists = ZipUtils.DoesFolderExist(zipFile, "SaveGames"); + // Assert + Assert.IsTrue(exists); + + // Act + count = ZipUtils.ExtractFiles(zipFile, destinationPath, sourceFolder: "SaveGames", recurseFolders: true); + // Assert + Assert.AreEqual(6, count); + + // Act + exists = ZipUtils.DoesFolderExist(zipFile, "AwesomeTeleporters"); + // Assert + Assert.IsTrue(exists); + + // Act + count = ZipUtils.ExtractFiles(zipFile, destinationPath, sourceFolder: "AwesomeTeleporters", recurseFolders: true); + // Assert + Assert.AreEqual(1, count); + } + + private string FetchZipFile() + { + return @"D:\_smtest\new_theisland_20220501_221004.zip"; + } + } +} diff --git a/src/ServerManager.Common/Utils/ZipUtils.cs b/src/ServerManager.Common/Utils/ZipUtils.cs index df1acf3b..dbbe8515 100644 --- a/src/ServerManager.Common/Utils/ZipUtils.cs +++ b/src/ServerManager.Common/Utils/ZipUtils.cs @@ -21,7 +21,25 @@ namespace ServerManagerTool.Common.Utils using (var zip = ZipFile.Read(zipFile)) { - return zip.Entries.Any(e => Path.GetFileName(e.FileName).Equals(entryName, StringComparison.OrdinalIgnoreCase)); + return zip.Entries.Any(e => !e.IsDirectory && Path.GetFileName(e.FileName).Equals(entryName, StringComparison.OrdinalIgnoreCase)); + } + } + + public static bool DoesFolderExist(string zipFile, string folderName) + { + if (string.IsNullOrWhiteSpace(zipFile)) + throw new ArgumentNullException(nameof(zipFile)); + if (string.IsNullOrWhiteSpace(folderName)) + throw new ArgumentNullException(nameof(folderName)); + + if (!File.Exists(zipFile)) + throw new FileNotFoundException(); + + using (var zip = ZipFile.Read(zipFile)) + { + return zip.Entries.Any(e => e.IsDirectory && e.FileName.EndsWith($"{folderName}/", StringComparison.OrdinalIgnoreCase)) + ? true + : zip.Entries.Any(e => !e.IsDirectory && (e.FileName.StartsWith($"{folderName.ToLower()}/", StringComparison.OrdinalIgnoreCase) || e.FileName.ToLower().Contains($"/{folderName.ToLower()}/"))); } } @@ -41,14 +59,14 @@ namespace ServerManagerTool.Common.Utils using (var zip = ZipFile.Read(zipFile)) { - var selection = zip.Entries.Where(e => Path.GetFileName(e.FileName).Equals(entryName, StringComparison.OrdinalIgnoreCase)); + var selection = zip.Entries.Where(e => Path.GetFileName(e.FileName).Equals(entryName, StringComparison.OrdinalIgnoreCase)).ToList(); foreach (var entry in selection) { entry.Extract(destinationPath, ExtractExistingFileAction.OverwriteSilently); } - return selection.Count(); + return selection.Count; } } @@ -70,6 +88,39 @@ namespace ServerManagerTool.Common.Utils } } + public static int ExtractFiles(string zipFile, string destinationPath, string sourceFolder = "", bool recurseFolders = false) + { + if (string.IsNullOrWhiteSpace(zipFile)) + throw new ArgumentNullException(nameof(zipFile)); + if (string.IsNullOrWhiteSpace(destinationPath)) + throw new ArgumentNullException(nameof(destinationPath)); + + if (!Directory.Exists(destinationPath)) + Directory.CreateDirectory(destinationPath); + + if (sourceFolder is null) + sourceFolder = string.Empty; + if (sourceFolder.EndsWith("/")) + sourceFolder = sourceFolder.TrimEnd('/'); + + using (var zip = ZipFile.Read(zipFile)) + { + var selection = new List(); + + if (recurseFolders) + selection.AddRange(zip.Entries.Where(e => !e.IsDirectory && (e.FileName.StartsWith($"{sourceFolder.ToLower()}/", StringComparison.OrdinalIgnoreCase) || e.FileName.ToLower().Contains($"/{sourceFolder.ToLower()}/")))); + else + selection.AddRange(zip.Entries.Where(e => !e.IsDirectory && Path.GetDirectoryName(e.FileName).Equals(sourceFolder, StringComparison.OrdinalIgnoreCase))); + + foreach (var entry in selection) + { + entry.Extract(destinationPath, ExtractExistingFileAction.OverwriteSilently); + } + + return selection.Count; + } + } + public static void UpdateFiles(string zipFile, IEnumerable filesToZip, string comment = "", bool preserveDirHierarchy = true, string directoryPathInArchive = "") { if (string.IsNullOrWhiteSpace(zipFile))