Force update on branch change in launcher.

This commit is contained in:
Nick Blakely 2022-09-09 19:07:40 -07:00
parent 98a81d3289
commit 9f500e9084
8 changed files with 165 additions and 109 deletions

View File

@ -11,6 +11,7 @@
{
private const string defaultConfigFileName = "GiantsDefault.config";
private const string playerConfigFileName = "Giants.config";
private bool dirty = false;
private IDictionary<string, dynamic> defaultConfig = new Dictionary<string, dynamic>();
private IDictionary<string, dynamic> userConfig = new Dictionary<string, dynamic>();
@ -35,6 +36,34 @@
}
}
public void Write()
{
if (!this.dirty)
{
return;
}
try
{
string userConfigFilePath = this.GetUserConfigPath();
Directory.CreateDirectory(Path.GetDirectoryName(userConfigFilePath));
using (var file = File.OpenWrite(userConfigFilePath))
using (var streamWriter = new StreamWriter(file))
{
string serializedConfig = JsonConvert.SerializeObject(this.userConfig, Formatting.Indented);
streamWriter.Write(serializedConfig);
}
this.dirty = false;
}
catch (Exception e)
{
MessageBox.Show($"Unhandled exception saving updated configuration: {e}");
}
}
public bool TryGetObject(string section, string key, object defaultValue, out object value)
{
value = defaultValue;
@ -87,6 +116,26 @@
return false;
}
public void SetValue(string section, string key, dynamic value)
{
if (!this.userConfig.ContainsKey(section))
{
this.userConfig.Add(section, new Dictionary<string, dynamic>());
}
dynamic sectionObject = this.userConfig[section];
if (sectionObject != null && sectionObject.ContainsKey(key))
{
sectionObject[key] = value;
}
else
{
sectionObject.Add(key, value);
}
this.dirty = true;
}
private static IDictionary<string, dynamic> ReadConfig(string filePath)
{
string fileContents = File.ReadAllText(filePath);

View File

@ -41,8 +41,12 @@ namespace Giants.Launcher
// Set window title
this.SetTitle();
// Read newer file-based game settings
this.config = new Config();
this.updater = new Updater(
updateCompletedCallback: this.LauncherForm_DownloadCompletedCallback,
updateProgressCallback: this.LauncherForm_DownloadProgressCallback);
// Read newer file-based game settings
this.config = new Config();
this.config.Read();
this.config.TryGetString(ConfigSections.Network, ConfigKeys.MasterServerHostName, ConfigDefaults.MasterServerHostNameDefault, out string baseUrl);
@ -72,12 +76,14 @@ namespace Giants.Launcher
private void btnExit_Click(object sender, EventArgs e)
{
this.config.Write();
Application.Exit();
}
private void btnPlay_Click(object sender, EventArgs e)
{
GameSettings.Save();
this.config.Write();
foreach (string c in Environment.GetCommandLineArgs())
{
@ -97,25 +103,44 @@ namespace Giants.Launcher
gameProcess.Start();
Application.Exit();
}
catch(Exception ex)
catch (Exception ex)
{
MessageBox.Show(string.Format("Failed to launch game process at: {0}. {1}", this.gamePath, ex.Message),
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void btnOptions_Click(object sender, EventArgs e)
private async void btnOptions_Click(object sender, EventArgs e)
{
OptionsForm form = new OptionsForm(
OptionsForm form = new OptionsForm(
title: Resources.AppName + " Options",
gamePath: this.gamePath,
appName: ApplicationNames.Giants,
branchName: this.branchName,
currentBranchName: this.branchName,
config: this.config,
branchesClient: this.branchHttpClient);
branchesClient: this.branchHttpClient)
{
StartPosition = FormStartPosition.CenterParent
};
form.StartPosition = FormStartPosition.CenterParent;
form.ShowDialog();
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
if (enableBranchSelection)
{
this.config.TryGetString(ConfigSections.Update, ConfigKeys.BranchName, defaultValue: ConfigDefaults.BranchNameDefault, out string branchName);
if (!this.branchName.Equals(branchName))
{
this.branchName = branchName;
VersionInfo gameVersionInfo = await this.GetVersionInfo(
GetApplicationName(ApplicationType.Game), this.branchName);
this.btnPlay.Enabled = false;
await this.updater.UpdateApplication(ApplicationType.Game, gameVersionInfo);
}
}
}
private async void LauncherForm_Load(object sender, EventArgs e)
@ -142,30 +167,15 @@ namespace Giants.Launcher
GameSettings.Load(this.gamePath);
if (GameSettings.Get<int>("NoAutoUpdate") == 0)
{
Version gameVersion = VersionHelper.GetGameVersion(this.gamePath);
if (gameVersion == null)
{
string message = string.Format(Resources.AppNotFound, Resources.AppName);
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
}
{
Task updateTask = this.CheckForUpdates();
Task discordTask = this.UpdateDiscordStatus();
var appVersions = new Dictionary<ApplicationType, Version>()
{
[ApplicationType.Game] = gameVersion,
[ApplicationType.Launcher] = VersionHelper.GetLauncherVersion()
};
await Task.WhenAll(updateTask, discordTask);
}
}
// Check for updates
Task updateTask = this.CheckForUpdates(appVersions);
Task discordTask = this.CheckDiscordStatus();
await Task.WhenAll(updateTask, discordTask);
}
}
private async Task CheckDiscordStatus()
private async Task UpdateDiscordStatus()
{
try
{
@ -181,21 +191,30 @@ namespace Giants.Launcher
}
}
private async Task CheckForUpdates(Dictionary<ApplicationType, Version> appVersions)
private async Task CheckForUpdates()
{
this.updater = new Updater(
appVersions: appVersions,
updateCompletedCallback: this.LauncherForm_DownloadCompletedCallback,
updateProgressCallback: this.LauncherForm_DownloadProgressCallback);
Task<VersionInfo> gameVersionInfo = this.GetVersionInfo(
GetApplicationName(ApplicationType.Game), this.branchName);
VersionInfo gameVersionInfo = await this.GetVersionInfo(
GetApplicationName(ApplicationType.Game));
Task<VersionInfo> launcherVersionInfo = this.GetVersionInfo(
GetApplicationName(ApplicationType.Launcher), this.branchName);
if (this.updater.IsUpdateRequired(ApplicationType.Game, gameVersionInfo))
Version localGameVersion = VersionHelper.GetGameVersion(this.gamePath);
Version localLauncherVersion = VersionHelper.GetLauncherVersion();
await Task.WhenAll(gameVersionInfo, launcherVersionInfo);
if (this.updater.IsUpdateRequired(ApplicationType.Game, gameVersionInfo.Result, localGameVersion))
{
this.btnPlay.Enabled = false;
await this.updater.UpdateApplication(ApplicationType.Game, gameVersionInfo);
await this.updater.UpdateApplication(ApplicationType.Game, gameVersionInfo.Result);
}
if (this.updater.IsUpdateRequired(ApplicationType.Launcher, launcherVersionInfo.Result, localLauncherVersion))
{
this.btnPlay.Enabled = false;
await this.updater.UpdateApplication(ApplicationType.Launcher, launcherVersionInfo.Result);
}
}
private static string GetApplicationName(ApplicationType applicationType)
@ -204,17 +223,19 @@ namespace Giants.Launcher
{
case ApplicationType.Game:
return ApplicationNames.Giants;
case ApplicationType.Launcher:
return ApplicationNames.GiantsLauncher;
}
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException();
}
private async Task<VersionInfo> GetVersionInfo(string appName)
private async Task<VersionInfo> GetVersionInfo(string appName, string branchName)
{
VersionInfo versionInfo;
try
{
versionInfo = await this.versionHttpClient.GetVersionInfoAsync(appName, this.branchName);
versionInfo = await this.versionHttpClient.GetVersionInfoAsync(appName, branchName);
return versionInfo;
}
catch (ApiException ex)
@ -229,26 +250,6 @@ namespace Giants.Launcher
}
}
private async Task<VersionInfo> GetBranches(string appName)
{
VersionInfo versionInfo;
try
{
versionInfo = await this.versionHttpClient.GetVersionInfoAsync(appName, this.branchName);
return versionInfo;
}
catch (ApiException ex)
{
MessageBox.Show($"Exception retrieving branch information: {ex.StatusCode}");
return null;
}
catch (Exception ex)
{
MessageBox.Show($"Exception retrieving branch information: {ex.Message}");
return null;
}
}
private void LauncherForm_MouseDown(object sender, MouseEventArgs e)
{
// Force window to be draggable even though we have no menu bar
@ -314,6 +315,14 @@ namespace Giants.Launcher
updaterProcess.Start();
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
if (enableBranchSelection)
{
this.config.SetValue(ConfigSections.Update, ConfigKeys.BranchName, this.branchName);
}
this.config.Write();
Application.Exit();
return;
}
@ -350,15 +359,6 @@ namespace Giants.Launcher
private void SetTitle()
{
string title = Resources.AppName;
#if DEBUG
title += " DEBUG";
#endif
#if BETA
title += " BETA";
#endif
this.Text = title;
}
}

View File

@ -239,6 +239,7 @@
//
// cmbBranch
//
this.cmbBranch.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbBranch.FormattingEnabled = true;
this.cmbBranch.Location = new System.Drawing.Point(27, 17);
this.cmbBranch.Name = "cmbBranch";

View File

@ -13,7 +13,7 @@ namespace Giants.Launcher
private readonly string gamePath = null;
private readonly string appName;
private readonly Config config;
private readonly string branchName;
private readonly string currentBranchName;
private readonly bool enableBranchSelection;
private readonly BranchesClient branchesClient;
@ -22,7 +22,7 @@ namespace Giants.Launcher
string gamePath,
string appName,
Config config,
string branchName,
string currentBranchName,
BranchesClient branchesClient)
{
this.InitializeComponent();
@ -31,7 +31,7 @@ namespace Giants.Launcher
this.gamePath = gamePath;
this.appName = appName;
this.config = config;
this.branchName = branchName;
this.currentBranchName = currentBranchName;
this.branchesClient = branchesClient;
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
@ -57,12 +57,21 @@ namespace Giants.Launcher
{
if (this.enableBranchSelection)
{
var branches = await this.branchesClient.GetBranchesAsync(this.appName);
try
{
var branches = await this.branchesClient.GetBranchesAsync(this.appName);
cmbBranch.Items.AddRange(branches.ToArray());
cmbBranch.Items.AddRange(branches.ToArray());
BranchGroupBox.Visible = true;
cmbBranch.Visible = true;
cmbBranch.SelectedItem = this.currentBranchName;
BranchGroupBox.Visible = true;
cmbBranch.Visible = true;
}
catch (Exception e)
{
MessageBox.Show($"Unhandled exception retrieving branch information from the server: {e.Message}");
}
}
}
@ -110,14 +119,16 @@ namespace Giants.Launcher
if (this.enableBranchSelection)
{
this.cmbBranch.SelectedItem = this.branchName;
this.cmbBranch.SelectedItem = this.currentBranchName;
}
}
private void PopulateAntialiasing()
{
var antialiasingOptions = new List<KeyValuePair<string, int>>();
antialiasingOptions.Add(new KeyValuePair<string, int>(Resources.OptionNone, 0));
var antialiasingOptions = new List<KeyValuePair<string, int>>
{
new KeyValuePair<string, int>(Resources.OptionNone, 0)
};
var renderer = (RendererInfo)this.cmbRenderer.SelectedItem;
if (renderer != null)
@ -268,6 +279,15 @@ namespace Giants.Launcher
GameSettings.Save();
if (this.enableBranchSelection)
{
string newBranch = this.cmbBranch.SelectedItem?.ToString();
if (!string.IsNullOrEmpty(newBranch) && !newBranch.Equals(this.currentBranchName, StringComparison.OrdinalIgnoreCase))
{
this.config.SetValue(ConfigSections.Update, ConfigKeys.BranchName, newBranch);
}
}
this.Close();
}

View File

@ -1,38 +1,35 @@
using System;
using System.Collections.Generic;
using Giants.WebApi.Clients;
using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using Giants.WebApi.Clients;
namespace Giants.Launcher
{
public class Updater
{
private readonly IDictionary<ApplicationType, Version> appVersions;
private readonly AsyncCompletedEventHandler updateCompletedCallback;
private readonly DownloadProgressChangedEventHandler updateProgressCallback;
public Updater(
IDictionary<ApplicationType, Version> appVersions,
AsyncCompletedEventHandler updateCompletedCallback,
DownloadProgressChangedEventHandler updateProgressCallback)
{
this.appVersions = appVersions;
this.updateCompletedCallback = updateCompletedCallback;
this.updateProgressCallback = updateProgressCallback;
}
public bool IsUpdateRequired(ApplicationType applicationType, VersionInfo versionInfo)
public bool IsUpdateRequired(ApplicationType applicationType, VersionInfo remoteVersionInfo, Version localVersion)
{
if (versionInfo != null && this.ToVersion(versionInfo.Version) > this.appVersions[applicationType])
if (remoteVersionInfo?.InstallerUri != null
&& this.ToVersion(remoteVersionInfo.Version) > localVersion)
{
// Display update prompt
string updateMsg = applicationType == ApplicationType.Game ?
string.Format(Resources.UpdateAvailableText, this.ToVersion(versionInfo.Version).ToString()) :
string.Format(Resources.LauncherUpdateAvailableText, this.ToVersion(versionInfo.Version).ToString());
string.Format(Resources.UpdateAvailableText, this.ToVersion(remoteVersionInfo.Version).ToString()) :
string.Format(Resources.LauncherUpdateAvailableText, this.ToVersion(remoteVersionInfo.Version).ToString());
if (MessageBox.Show(updateMsg, Resources.UpdateAvailableTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
{

View File

@ -15,6 +15,10 @@
}
catch (Exception)
{
string message = string.Format(Resources.AppNotFound, Resources.AppName);
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
return null;
}
}

View File

@ -39,7 +39,9 @@ namespace Giants.Services
var versions = await this.versionCache.GetItems();
return versions
.Where(x => x.AppName.Equals(appName, StringComparison.Ordinal) && x.BranchName.Equals(branchName, StringComparison.OrdinalIgnoreCase))
.Where(x => x.AppName.Equals(appName, StringComparison.Ordinal)
&& !string.IsNullOrEmpty(x.BranchName)
&& x.BranchName.Equals(branchName, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
}

View File

@ -28,26 +28,9 @@ namespace Giants.WebApi.Controllers
}
[HttpGet]
public async Task<DataContract.V1.VersionInfo> GetVersionInfo(string appName)
{
ArgumentUtility.CheckStringForNullOrEmpty(appName);
VersionInfo versionInfo = await this.versioningService.GetVersionInfo(appName, BranchConstants.DefaultBranchName);
if (versionInfo == null)
{
throw new ArgumentException($"No version information for {appName} found.", appName);
}
return this.mapper.Map<DataContract.V1.VersionInfo>(versionInfo);
}
[HttpGet]
[MapToApiVersion("1.1")]
public async Task<DataContract.V1.VersionInfo> GetVersionInfo(string appName, string branchName)
{
ArgumentUtility.CheckStringForNullOrEmpty(appName);
ArgumentUtility.CheckStringForNullOrEmpty(branchName);
VersionInfo versionInfo = await this.versioningService.GetVersionInfo(appName, branchName);