2020-08-10 06:58:51 +02:00
|
|
|
|
using System;
|
2020-08-11 20:24:04 +02:00
|
|
|
|
using System.Collections.Generic;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Media;
|
|
|
|
|
using System.Net;
|
2020-08-11 10:29:45 +02:00
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Threading.Tasks;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
using System.Windows.Forms;
|
2020-08-11 10:29:45 +02:00
|
|
|
|
using Giants.WebApi.Clients;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
using Microsoft.Win32;
|
|
|
|
|
|
|
|
|
|
namespace Giants.Launcher
|
|
|
|
|
{
|
|
|
|
|
public partial class LauncherForm : Form
|
|
|
|
|
{
|
|
|
|
|
// Constant settings
|
2020-08-16 11:52:58 +02:00
|
|
|
|
private const string GamePath = "GiantsMain.exe";
|
|
|
|
|
private const string RegistryKey = @"HKEY_CURRENT_USER\Software\PlanetMoon\Giants";
|
|
|
|
|
private const string RegistryValue = "DestDir";
|
|
|
|
|
|
|
|
|
|
private readonly HttpClient httpClient;
|
|
|
|
|
private readonly VersionClient versionHttpClient;
|
2020-08-16 12:08:49 +02:00
|
|
|
|
private readonly CommunityClient communityHttpClient;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-09-14 09:11:32 +02:00
|
|
|
|
private string commandLine;
|
2020-08-11 10:29:45 +02:00
|
|
|
|
private string gamePath = null;
|
|
|
|
|
private Updater updater;
|
2020-09-14 09:11:32 +02:00
|
|
|
|
private Config config;
|
2020-08-16 12:08:49 +02:00
|
|
|
|
private string communityAppUri;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
public LauncherForm()
|
|
|
|
|
{
|
2020-08-11 10:55:57 +02:00
|
|
|
|
this.InitializeComponent();
|
2020-08-16 12:08:49 +02:00
|
|
|
|
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
|
|
|
|
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-08-11 10:29:45 +02:00
|
|
|
|
// Set window title
|
2020-12-13 02:41:01 +01:00
|
|
|
|
this.SetTitle();
|
2020-08-16 11:52:58 +02:00
|
|
|
|
|
2020-09-14 09:11:32 +02:00
|
|
|
|
// Read newer file-based game settings
|
|
|
|
|
this.config = new Config();
|
|
|
|
|
this.config.Read();
|
|
|
|
|
|
|
|
|
|
string baseUrl = this.config.GetString(ConfigSections.Network, ConfigKeys.MasterServerHostName);
|
|
|
|
|
|
2020-09-11 07:50:39 +02:00
|
|
|
|
this.httpClient = new HttpClient(
|
|
|
|
|
new HttpClientHandler()
|
|
|
|
|
{
|
|
|
|
|
UseProxy = false
|
|
|
|
|
});
|
|
|
|
|
this.versionHttpClient = new VersionClient(this.httpClient)
|
|
|
|
|
{
|
2020-09-14 09:11:32 +02:00
|
|
|
|
BaseUrl = baseUrl
|
|
|
|
|
};
|
2020-09-11 07:50:39 +02:00
|
|
|
|
this.communityHttpClient = new CommunityClient(this.httpClient)
|
|
|
|
|
{
|
2020-09-14 09:11:32 +02:00
|
|
|
|
BaseUrl = baseUrl
|
|
|
|
|
};
|
2020-09-11 07:50:39 +02:00
|
|
|
|
}
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
private void btnExit_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Application.Exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnPlay_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
GameSettings.Save();
|
|
|
|
|
|
|
|
|
|
foreach (string c in Environment.GetCommandLineArgs())
|
2020-08-11 10:29:45 +02:00
|
|
|
|
{
|
|
|
|
|
this.commandLine = this.commandLine + c + " ";
|
|
|
|
|
}
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-08-11 10:29:45 +02:00
|
|
|
|
string commandLine = string.Format("{0} -launcher", this.commandLine.Trim());
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Process gameProcess = new Process();
|
|
|
|
|
|
|
|
|
|
gameProcess.StartInfo.Arguments = commandLine;
|
2020-08-11 10:29:45 +02:00
|
|
|
|
gameProcess.StartInfo.FileName = this.gamePath;
|
|
|
|
|
gameProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(this.gamePath);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
gameProcess.Start();
|
|
|
|
|
Application.Exit();
|
|
|
|
|
}
|
|
|
|
|
catch(Exception ex)
|
|
|
|
|
{
|
2020-08-11 10:29:45 +02:00
|
|
|
|
MessageBox.Show(string.Format("Failed to launch game process at: {0}. {1}", this.gamePath, ex.Message),
|
2020-08-10 06:58:51 +02:00
|
|
|
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void btnOptions_Click(object sender, EventArgs e)
|
|
|
|
|
{
|
2020-12-13 02:41:01 +01:00
|
|
|
|
OptionsForm form = new OptionsForm(Resources.AppName + " Options", this.gamePath);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-08-17 00:48:51 +02:00
|
|
|
|
form.StartPosition = FormStartPosition.CenterParent;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
form.ShowDialog();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-11 10:29:45 +02:00
|
|
|
|
private async void LauncherForm_Load(object sender, EventArgs e)
|
2020-08-10 06:58:51 +02:00
|
|
|
|
{
|
|
|
|
|
// Find the game executable, first looking for it relative to our current directory and then
|
|
|
|
|
// using the registry path if that fails.
|
2020-08-16 11:52:58 +02:00
|
|
|
|
this.gamePath = Path.GetDirectoryName(Application.ExecutablePath) + "\\" + GamePath;
|
2020-08-11 10:29:45 +02:00
|
|
|
|
if (!File.Exists(this.gamePath))
|
2020-08-10 06:58:51 +02:00
|
|
|
|
{
|
2020-08-16 11:52:58 +02:00
|
|
|
|
this.gamePath = (string)Registry.GetValue(RegistryKey, RegistryValue, null);
|
2020-08-11 10:29:45 +02:00
|
|
|
|
if (this.gamePath != null)
|
2020-08-16 11:52:58 +02:00
|
|
|
|
this.gamePath = Path.Combine(this.gamePath, GamePath);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-08-11 10:29:45 +02:00
|
|
|
|
if (this.gamePath == null || !File.Exists(this.gamePath))
|
2020-08-10 06:58:51 +02:00
|
|
|
|
{
|
2020-12-13 02:41:01 +01:00
|
|
|
|
string message = string.Format(Resources.AppNotFound, Resources.AppName);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
Application.Exit();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read game settings from registry
|
2020-08-11 10:29:45 +02:00
|
|
|
|
GameSettings.Load(this.gamePath);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-08-13 08:02:36 +02:00
|
|
|
|
if (GameSettings.Get<int>("NoAutoUpdate") == 0)
|
2020-08-16 11:52:58 +02:00
|
|
|
|
{
|
|
|
|
|
Version gameVersion = VersionHelper.GetGameVersion(this.gamePath);
|
|
|
|
|
if (gameVersion == null)
|
|
|
|
|
{
|
2020-12-13 02:41:01 +01:00
|
|
|
|
string message = string.Format(Resources.AppNotFound, Resources.AppName);
|
2020-08-16 11:52:58 +02:00
|
|
|
|
MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
Application.Exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var appVersions = new Dictionary<ApplicationType, Version>()
|
|
|
|
|
{
|
|
|
|
|
[ApplicationType.Game] = gameVersion,
|
|
|
|
|
[ApplicationType.Launcher] = VersionHelper.GetLauncherVersion()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Check for updates
|
|
|
|
|
Task updateTask = this.CheckForUpdates(appVersions);
|
|
|
|
|
Task discordTask = this.CheckDiscordStatus();
|
|
|
|
|
|
|
|
|
|
await Task.WhenAll(updateTask, discordTask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task CheckDiscordStatus()
|
|
|
|
|
{
|
|
|
|
|
try
|
2020-08-10 06:58:51 +02:00
|
|
|
|
{
|
2020-08-16 12:08:49 +02:00
|
|
|
|
var status = await this.communityHttpClient.GetDiscordStatusAsync();
|
2020-08-16 11:52:58 +02:00
|
|
|
|
|
2020-08-16 12:08:49 +02:00
|
|
|
|
this.communityAppUri = status.CommunityAppUri;
|
|
|
|
|
this.CommunityLabel.Text = string.Format(Resources.CommunityLabel, status.CommunityAppName);
|
|
|
|
|
this.CommunityLabel.Visible = true;
|
2020-08-16 11:52:58 +02:00
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
// Ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-11 20:24:04 +02:00
|
|
|
|
|
2020-08-16 11:52:58 +02:00
|
|
|
|
private async Task CheckForUpdates(Dictionary<ApplicationType, Version> appVersions)
|
|
|
|
|
{
|
|
|
|
|
this.updater = new Updater(
|
|
|
|
|
appVersions: appVersions,
|
|
|
|
|
updateCompletedCallback: this.LauncherForm_DownloadCompletedCallback,
|
|
|
|
|
updateProgressCallback: this.LauncherForm_DownloadProgressCallback);
|
2020-08-11 10:29:45 +02:00
|
|
|
|
|
2020-11-04 04:49:04 +01:00
|
|
|
|
Task<VersionInfo> gameVersionInfo = this.GetVersionInfo(
|
|
|
|
|
GetApplicationName(ApplicationType.Game));
|
|
|
|
|
Task<VersionInfo> launcherVersionInfo = this.GetVersionInfo(
|
|
|
|
|
GetApplicationName(ApplicationType.Launcher));
|
2020-08-11 10:29:45 +02:00
|
|
|
|
|
2020-08-16 11:52:58 +02:00
|
|
|
|
await Task.WhenAll(gameVersionInfo, launcherVersionInfo);
|
2020-08-11 10:29:45 +02:00
|
|
|
|
|
2020-10-18 08:44:41 +02:00
|
|
|
|
if (this.updater.IsUpdateRequired(ApplicationType.Game, gameVersionInfo.Result))
|
|
|
|
|
{
|
|
|
|
|
this.btnPlay.Enabled = false;
|
|
|
|
|
await this.updater.UpdateApplication(ApplicationType.Game, gameVersionInfo.Result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.updater.IsUpdateRequired(ApplicationType.Launcher, launcherVersionInfo.Result))
|
|
|
|
|
{
|
|
|
|
|
this.btnPlay.Enabled = false;
|
|
|
|
|
await this.updater.UpdateApplication(ApplicationType.Launcher, launcherVersionInfo.Result);
|
|
|
|
|
}
|
2020-08-10 06:58:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-04 04:49:04 +01:00
|
|
|
|
private static string GetApplicationName(ApplicationType applicationType)
|
|
|
|
|
{
|
|
|
|
|
switch (applicationType)
|
|
|
|
|
{
|
|
|
|
|
case ApplicationType.Game:
|
|
|
|
|
#if BETA
|
|
|
|
|
return ApplicationNames.GiantsBeta;
|
|
|
|
|
#else
|
|
|
|
|
return ApplicationNames.Giants;
|
|
|
|
|
#endif
|
|
|
|
|
case ApplicationType.Launcher:
|
|
|
|
|
#if BETA
|
|
|
|
|
return ApplicationNames.GiantsLauncherBeta;
|
|
|
|
|
#else
|
|
|
|
|
return ApplicationNames.GiantsLauncher;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 11:52:58 +02:00
|
|
|
|
private async Task<VersionInfo> GetVersionInfo(string appName)
|
2020-08-11 10:29:45 +02:00
|
|
|
|
{
|
|
|
|
|
VersionInfo versionInfo;
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-08-16 11:52:58 +02:00
|
|
|
|
versionInfo = await this.versionHttpClient.GetVersionInfoAsync(appName);
|
2020-08-11 10:29:45 +02:00
|
|
|
|
return versionInfo;
|
|
|
|
|
}
|
|
|
|
|
catch (ApiException ex)
|
|
|
|
|
{
|
|
|
|
|
#if DEBUG
|
|
|
|
|
MessageBox.Show($"Exception retrieving version information: {ex.StatusCode}");
|
|
|
|
|
#endif
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
#if DEBUG
|
|
|
|
|
MessageBox.Show($"Exception retrieving version information: {ex.Message}");
|
|
|
|
|
#endif
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-10 06:58:51 +02:00
|
|
|
|
private void LauncherForm_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
// Force window to be draggable even though we have no menu bar
|
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
|
|
|
{
|
|
|
|
|
NativeMethods.ReleaseCapture();
|
2020-08-10 09:22:33 +02:00
|
|
|
|
NativeMethods.SendMessage(this.Handle, NativeMethods.WM_NCLBUTTONDOWN, NativeMethods.HT_CAPTION, 0);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LauncherForm_Shown(object sender, EventArgs e)
|
|
|
|
|
{
|
2020-08-10 09:22:33 +02:00
|
|
|
|
this.btnOptions.Visible = true;
|
|
|
|
|
this.btnPlay.Visible = true;
|
|
|
|
|
this.btnExit.Visible = true;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
// Play intro sound
|
|
|
|
|
SoundPlayer player = new SoundPlayer(Resources.LauncherStart);
|
|
|
|
|
player.Play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LauncherForm_DownloadCompletedCallback(object sender, AsyncCompletedEventArgs e)
|
|
|
|
|
{
|
2020-10-18 08:44:41 +02:00
|
|
|
|
this.btnPlay.Enabled = true;
|
|
|
|
|
|
2020-08-10 06:58:51 +02:00
|
|
|
|
if (e.Cancelled)
|
2020-08-11 10:29:45 +02:00
|
|
|
|
{
|
2020-08-10 06:58:51 +02:00
|
|
|
|
return;
|
2020-08-11 10:29:45 +02:00
|
|
|
|
}
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
2020-08-10 09:22:33 +02:00
|
|
|
|
this.updateProgressBar.Value = 0;
|
|
|
|
|
this.updateProgressBar.Visible = false;
|
|
|
|
|
this.txtProgress.Visible = false;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
if (e.Error != null)
|
|
|
|
|
{
|
|
|
|
|
string errorMsg = string.Format(Resources.UpdateDownloadFailedText, e.Error.Message);
|
|
|
|
|
MessageBox.Show(errorMsg, Resources.UpdateDownloadFailedTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Show "Download Complete" message, warn that we're closing
|
|
|
|
|
MessageBox.Show(Resources.LauncherClosingText, Resources.LauncherClosingTitle);
|
|
|
|
|
|
|
|
|
|
UpdateInfo updateInfo = (UpdateInfo)e.UserState;
|
|
|
|
|
|
|
|
|
|
// Start the installer process
|
|
|
|
|
Process updaterProcess = new Process();
|
2020-08-11 10:29:45 +02:00
|
|
|
|
updaterProcess.StartInfo.FileName = updateInfo.FilePath;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
updaterProcess.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
|
|
|
|
|
|
2020-08-11 10:29:45 +02:00
|
|
|
|
if (updateInfo.ApplicationType == ApplicationType.Game)
|
2020-08-10 06:58:51 +02:00
|
|
|
|
{
|
|
|
|
|
// Default installation directory to current directory
|
|
|
|
|
updaterProcess.StartInfo.Arguments = string.Format("/D {0}", Path.GetDirectoryName(Application.ExecutablePath));
|
|
|
|
|
}
|
2020-08-11 10:29:45 +02:00
|
|
|
|
else if (updateInfo.ApplicationType == ApplicationType.Launcher)
|
2020-08-10 06:58:51 +02:00
|
|
|
|
{
|
|
|
|
|
// Default installation directory to current directory and launch a silent install
|
|
|
|
|
updaterProcess.StartInfo.Arguments = string.Format("/S /D {0}", Path.GetDirectoryName(Application.ExecutablePath));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updaterProcess.Start();
|
|
|
|
|
|
|
|
|
|
Application.Exit();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LauncherForm_DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
|
|
|
|
|
{
|
2020-08-10 09:22:33 +02:00
|
|
|
|
this.updateProgressBar.Visible = true;
|
|
|
|
|
this.updateProgressBar.Value = e.ProgressPercentage;
|
2020-08-10 06:58:51 +02:00
|
|
|
|
|
|
|
|
|
UpdateInfo info = (UpdateInfo)e.UserState;
|
|
|
|
|
|
2020-08-10 09:22:33 +02:00
|
|
|
|
this.txtProgress.Visible = true;
|
2020-08-13 08:37:45 +02:00
|
|
|
|
this.txtProgress.Text = string.Format(Resources.DownloadProgress, e.ProgressPercentage, info.FileSize / 1024 / 1024);
|
2020-08-10 06:58:51 +02:00
|
|
|
|
}
|
2020-08-16 11:52:58 +02:00
|
|
|
|
|
|
|
|
|
private void DiscordLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
|
|
|
{
|
2020-08-16 12:08:49 +02:00
|
|
|
|
if (string.IsNullOrEmpty(this.communityAppUri))
|
2020-08-16 11:52:58 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 12:08:49 +02:00
|
|
|
|
var uri = new Uri(this.communityAppUri);
|
2020-08-16 11:52:58 +02:00
|
|
|
|
if (uri.Scheme != "https")
|
|
|
|
|
{
|
|
|
|
|
// For security, reject any non-HTTPS or local file system URIs
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-16 12:08:49 +02:00
|
|
|
|
Process.Start(this.communityAppUri);
|
2020-12-13 02:41:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetTitle()
|
|
|
|
|
{
|
|
|
|
|
string title = Resources.AppName;
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
title += " DEBUG";
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if BETA
|
|
|
|
|
title += " BETA";
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
this.Text = title;
|
2020-08-16 11:52:58 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-10 06:58:51 +02:00
|
|
|
|
}
|