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 defaultConfigFileName = "GiantsDefault.config";
private const string playerConfigFileName = "Giants.config"; private const string playerConfigFileName = "Giants.config";
private bool dirty = false;
private IDictionary<string, dynamic> defaultConfig = new Dictionary<string, dynamic>(); private IDictionary<string, dynamic> defaultConfig = new Dictionary<string, dynamic>();
private IDictionary<string, dynamic> userConfig = 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) public bool TryGetObject(string section, string key, object defaultValue, out object value)
{ {
value = defaultValue; value = defaultValue;
@ -87,6 +116,26 @@
return false; 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) private static IDictionary<string, dynamic> ReadConfig(string filePath)
{ {
string fileContents = File.ReadAllText(filePath); string fileContents = File.ReadAllText(filePath);

View File

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

View File

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

View File

@ -13,7 +13,7 @@ namespace Giants.Launcher
private readonly string gamePath = null; private readonly string gamePath = null;
private readonly string appName; private readonly string appName;
private readonly Config config; private readonly Config config;
private readonly string branchName; private readonly string currentBranchName;
private readonly bool enableBranchSelection; private readonly bool enableBranchSelection;
private readonly BranchesClient branchesClient; private readonly BranchesClient branchesClient;
@ -22,7 +22,7 @@ namespace Giants.Launcher
string gamePath, string gamePath,
string appName, string appName,
Config config, Config config,
string branchName, string currentBranchName,
BranchesClient branchesClient) BranchesClient branchesClient)
{ {
this.InitializeComponent(); this.InitializeComponent();
@ -31,7 +31,7 @@ namespace Giants.Launcher
this.gamePath = gamePath; this.gamePath = gamePath;
this.appName = appName; this.appName = appName;
this.config = config; this.config = config;
this.branchName = branchName; this.currentBranchName = currentBranchName;
this.branchesClient = branchesClient; this.branchesClient = branchesClient;
this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection); this.config.TryGetBool(ConfigSections.Update, ConfigKeys.EnableBranchSelection, defaultValue: false, out bool enableBranchSelection);
@ -57,12 +57,21 @@ namespace Giants.Launcher
{ {
if (this.enableBranchSelection) 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.SelectedItem = this.currentBranchName;
cmbBranch.Visible = true;
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) if (this.enableBranchSelection)
{ {
this.cmbBranch.SelectedItem = this.branchName; this.cmbBranch.SelectedItem = this.currentBranchName;
} }
} }
private void PopulateAntialiasing() private void PopulateAntialiasing()
{ {
var antialiasingOptions = new List<KeyValuePair<string, int>>(); var antialiasingOptions = new List<KeyValuePair<string, int>>
antialiasingOptions.Add(new KeyValuePair<string, int>(Resources.OptionNone, 0)); {
new KeyValuePair<string, int>(Resources.OptionNone, 0)
};
var renderer = (RendererInfo)this.cmbRenderer.SelectedItem; var renderer = (RendererInfo)this.cmbRenderer.SelectedItem;
if (renderer != null) if (renderer != null)
@ -268,6 +279,15 @@ namespace Giants.Launcher
GameSettings.Save(); 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(); this.Close();
} }

View File

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

View File

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

View File

@ -39,7 +39,9 @@ namespace Giants.Services
var versions = await this.versionCache.GetItems(); var versions = await this.versionCache.GetItems();
return versions 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(); .FirstOrDefault();
} }

View File

@ -28,26 +28,9 @@ namespace Giants.WebApi.Controllers
} }
[HttpGet] [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) public async Task<DataContract.V1.VersionInfo> GetVersionInfo(string appName, string branchName)
{ {
ArgumentUtility.CheckStringForNullOrEmpty(appName); ArgumentUtility.CheckStringForNullOrEmpty(appName);
ArgumentUtility.CheckStringForNullOrEmpty(branchName);
VersionInfo versionInfo = await this.versioningService.GetVersionInfo(appName, branchName); VersionInfo versionInfo = await this.versioningService.GetVersionInfo(appName, branchName);