public async Task <bool> UpgradeAsync(CancellationToken cancellationToken, bool updateServer, bool validate, bool updateMods, ProgressDelegate progressCallback) { if (updateServer && !Environment.Is64BitOperatingSystem) { var result = MessageBox.Show("The ARK server requires a 64-bit operating system to run. Your operating system is 32-bit and therefore the Ark Server Manager will be unable to start the server, but you may still install it or load and save profiles and settings files for use on other machines.\r\n\r\nDo you wish to continue?", "64-bit OS Required", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.No) { return(false); } } try { await StopAsync(); bool isNewInstallation = this.Status == ServerStatus.Uninstalled; this.Status = ServerStatus.Updating; // Run the SteamCMD to install the server var steamCmdFile = Updater.GetSteamCmdFile(); if (string.IsNullOrWhiteSpace(steamCmdFile) || !File.Exists(steamCmdFile)) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: SteamCMD could not be found. Expected location is {steamCmdFile}"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************"); return(false); } // record the start time of the process, this is used to determine if any files changed in the download process. var startTime = DateTime.Now; var gotNewVersion = false; var downloadSuccessful = false; var success = false; if (updateServer) { // ********************* // Server Update Section // ********************* progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Starting server update."); // Check if this is a new server installation. if (isNewInstallation) { // check if the auto-update facility is enabled and the cache folder defined. if (!this.ProfileSnapshot.SotFServer && Config.Default.AutoUpdate_EnableUpdate && !string.IsNullOrWhiteSpace(Config.Default.AutoUpdate_CacheDir) && Directory.Exists(Config.Default.AutoUpdate_CacheDir)) { // Auto-Update enabled and cache foldler exists. progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Installing server from local cache...may take a while to copy all the files."); // Install the server files from the cache. var installationFolder = this.ProfileSnapshot.InstallDirectory; int count = 0; await Task.Run(() => ServerApp.DirectoryCopy(Config.Default.AutoUpdate_CacheDir, installationFolder, true, Config.Default.AutoUpdate_UseSmartCopy, (p, m, n) => { count++; progressCallback?.Invoke(0, ".", count % DIRECTORIES_PER_LINE == 0); }), cancellationToken); } } progressCallback?.Invoke(0, "\r\n"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Updating server from steam.\r\n"); downloadSuccessful = !Config.Default.SteamCmdRedirectOutput; DataReceivedEventHandler serverOutputHandler = (s, e) => { var dataValue = e.Data ?? string.Empty; progressCallback?.Invoke(0, dataValue); if (!gotNewVersion && dataValue.Contains("downloading,")) { gotNewVersion = true; } if (dataValue.StartsWith("Success!")) { downloadSuccessful = true; } }; var steamCmdInstallServerArgsFormat = this.ProfileSnapshot.SotFServer ? Config.Default.SteamCmdInstallServerArgsFormat_SotF : Config.Default.SteamCmdInstallServerArgsFormat; var steamCmdArgs = String.Format(steamCmdInstallServerArgsFormat, this.ProfileSnapshot.InstallDirectory, validate ? "validate" : string.Empty); success = await ServerUpdater.UpgradeServerAsync(steamCmdFile, steamCmdArgs, this.ProfileSnapshot.InstallDirectory, Config.Default.SteamCmdRedirectOutput?serverOutputHandler : null, cancellationToken); if (success && downloadSuccessful) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished server update."); if (Directory.Exists(this.ProfileSnapshot.InstallDirectory)) { if (!Config.Default.SteamCmdRedirectOutput) { // check if any of the server files have changed. gotNewVersion = ServerApp.HasNewServerVersion(this.ProfileSnapshot.InstallDirectory, startTime); } progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} New server version - {gotNewVersion.ToString().ToUpperInvariant()}."); } progressCallback?.Invoke(0, "\r\n"); } else { success = false; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Failed server update."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************\r\n"); if (Config.Default.SteamCmdRedirectOutput) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} If the server update keeps failing try disabling the '{_globalizer.GetResourceString("GlobalSettings_SteamCmdRedirectOutputLabel")}' option in the settings window.\r\n"); } } } else { success = true; } if (success) { if (updateMods) { // ****************** // Mod Update Section // ****************** // build a list of mods to be processed var modIdList = new List <string>(); if (!string.IsNullOrWhiteSpace(this.ProfileSnapshot.ServerMapModId)) { modIdList.Add(this.ProfileSnapshot.ServerMapModId); } if (!string.IsNullOrWhiteSpace(this.ProfileSnapshot.TotalConversionModId)) { modIdList.Add(this.ProfileSnapshot.TotalConversionModId); } modIdList.AddRange(this.ProfileSnapshot.ServerModIds); modIdList = ModUtils.ValidateModList(modIdList); // get the details of the mods to be processed. var modDetails = SteamUtils.GetSteamModDetails(modIdList); if (modDetails != null) { // create a new list for any failed mod updates var failedMods = new List <string>(modIdList.Count); for (var index = 0; index < modIdList.Count; index++) { var modId = modIdList[index]; var modTitle = modId; var modSuccess = false; gotNewVersion = false; downloadSuccessful = false; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Started processing mod {index + 1} of {modIdList.Count}."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod {modId}."); // check if the steam information was downloaded var modDetail = modDetails.publishedfiledetails?.FirstOrDefault(m => m.publishedfileid.Equals(modId, StringComparison.OrdinalIgnoreCase)); if (modDetail != null) { modTitle = $"{modDetail.title} ({modId})"; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} {modDetail.title ?? string.Empty}.\r\n"); var modCachePath = ModUtils.GetModCachePath(modId, this.ProfileSnapshot.SotFServer); var cacheTimeFile = ModUtils.GetLatestModCacheTimeFile(modId, this.ProfileSnapshot.SotFServer); var modPath = ModUtils.GetModPath(this.ProfileSnapshot.InstallDirectory, modId); var modTimeFile = ModUtils.GetLatestModTimeFile(this.ProfileSnapshot.InstallDirectory, modId); var modCacheLastUpdated = 0; var downloadMod = true; var copyMod = true; if (downloadMod) { // check if the mod needs to be downloaded, or force the download. if (Config.Default.ServerUpdate_ForceUpdateMods) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod download - ASM setting is TRUE."); } else { // check if the mod detail record is valid (private mod). if (modDetail.time_updated <= 0) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod download - mod is private."); } else { modCacheLastUpdated = ModUtils.GetModLatestTime(cacheTimeFile); if (modCacheLastUpdated <= 0) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod download - mod cache is not versioned."); } else { var steamLastUpdated = modDetail.time_updated; if (steamLastUpdated <= modCacheLastUpdated) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Skipping mod download - mod cache has the latest version."); downloadMod = false; } } } } if (downloadMod) { // mod will be downloaded downloadSuccessful = !Config.Default.SteamCmdRedirectOutput; DataReceivedEventHandler modOutputHandler = (s, e) => { var dataValue = e.Data ?? string.Empty; progressCallback?.Invoke(0, dataValue); if (dataValue.StartsWith("Success.")) { downloadSuccessful = true; } }; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Starting mod download.\r\n"); var steamCmdArgs = string.Empty; if (this.ProfileSnapshot.SotFServer) { if (Config.Default.SteamCmd_UseAnonymousCredentials) { steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat_SotF, Config.Default.SteamCmd_AnonymousUsername, modId); } else { steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat_SotF, Config.Default.SteamCmd_Username, modId); } } else { if (Config.Default.SteamCmd_UseAnonymousCredentials) { steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat, Config.Default.SteamCmd_AnonymousUsername, modId); } else { steamCmdArgs = string.Format(Config.Default.SteamCmdInstallModArgsFormat, Config.Default.SteamCmd_Username, modId); } } modSuccess = await ServerUpdater.UpgradeModsAsync(steamCmdFile, steamCmdArgs, Config.Default.SteamCmdRedirectOutput?modOutputHandler : null, cancellationToken); if (modSuccess && downloadSuccessful) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished mod download."); copyMod = true; if (Directory.Exists(modCachePath)) { // check if any of the mod files have changed. gotNewVersion = new DirectoryInfo(modCachePath).GetFiles("*.*", SearchOption.AllDirectories).Any(file => file.LastWriteTime >= startTime); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} New mod version - {gotNewVersion.ToString().ToUpperInvariant()}."); var steamLastUpdated = modDetail.time_updated.ToString(); if (modDetail.time_updated <= 0) { // get the version number from the steamcmd workshop file. steamLastUpdated = ModUtils.GetSteamWorkshopLatestTime(ModUtils.GetSteamWorkshopFile(this.ProfileSnapshot.SotFServer), modId).ToString(); } // update the last updated file with the steam updated time. File.WriteAllText(cacheTimeFile, steamLastUpdated); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod Cache version: {steamLastUpdated}\r\n"); } } else { modSuccess = false; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mod download failed."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***************************\r\n"); if (Config.Default.SteamCmdRedirectOutput) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} If the mod update keeps failing try disabling the '{_globalizer.GetResourceString("GlobalSettings_SteamCmdRedirectOutputLabel")}' option in the settings window.\r\n"); } copyMod = false; } } else { modSuccess = true; } } else { modSuccess = true; } if (copyMod) { // check if the mod needs to be copied, or force the copy. if (Config.Default.ServerUpdate_ForceCopyMods) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod copy - ASM setting is TRUE."); } else { // check the mod version against the cache version. var modLastUpdated = ModUtils.GetModLatestTime(modTimeFile); if (modLastUpdated <= 0) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Forcing mod copy - mod is not versioned."); } else { modCacheLastUpdated = ModUtils.GetModLatestTime(cacheTimeFile); if (modCacheLastUpdated <= modLastUpdated) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Skipping mod copy - mod has the latest version."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod version: {modLastUpdated}"); copyMod = false; } } } if (copyMod) { try { if (Directory.Exists(modCachePath)) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Started mod copy."); int count = 0; await Task.Run(() => ModUtils.CopyMod(modCachePath, modPath, modId, (p, m, n) => { count++; progressCallback?.Invoke(0, ".", count % DIRECTORIES_PER_LINE == 0); }), cancellationToken); progressCallback?.Invoke(0, "\r\n"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished mod copy."); var modLastUpdated = ModUtils.GetModLatestTime(modTimeFile); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Mod version: {modLastUpdated}"); } else { modSuccess = false; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mod cache was not found, mod was not updated."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ****************************************************"); } } catch (Exception ex) { modSuccess = false; progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Failed mod copy.\r\n{ex.Message}"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************"); } } } } else { // no steam information downloaded, display an error, mod might no longer be available progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} *******************************************************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mod cannot be updated, unable to download steam information."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} *******************************************************************"); } if (!modSuccess) { success = false; failedMods.Add($"{index + 1} of {modIdList.Count} - {modTitle}"); } progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished processing mod {modId}.\r\n"); } if (failedMods.Count > 0) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} **************************************************************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: The following mods failed the update, check above for more details."); foreach (var failedMod in failedMods) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} {failedMod}"); } progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} **************************************************************************\r\n"); } } else { success = false; // no steam information downloaded, display an error progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ********************************************************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mods cannot be updated, unable to download steam information."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ********************************************************************\r\n"); } } } else { if (updateServer && updateMods) { progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************************************"); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ERROR: Mods were not processed as server update had errors."); progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} ***********************************************************\r\n"); } } progressCallback?.Invoke(0, $"{Updater.OUTPUT_PREFIX} Finished upgrade process."); return(success); } catch (TaskCanceledException) { return(false); } finally { this.Status = ServerStatus.Stopped; } }
public static string GetLatestModCacheTimeFile(string modId, bool isSotF) => IOUtils.NormalizePath(Path.Combine(ModUtils.GetModCachePath(modId, isSotF), Config.Default.LastUpdatedTimeFile));