using AyalaLauncherBeta2016.Config; using AyalaLauncherBeta2016.Patcher; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace AyalaLauncherBeta2016 { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { private string patcherDirectory; public BackgroundWorker patchUpdaterWorker; private AutoResetEvent patchDownloadEvent; private Exception patchDownloadingException; public BackgroundWorker launcherUpdaterWorker; private AutoResetEvent launcherDownloadEvent; private Exception launcherDownloadingException; public bool ServerAccessible; public bool ServerMaintenance; public MainWindow(bool ServerAccessible) { this.ServerAccessible = ServerAccessible; InitializeComponent(); } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { SetVersions(); SetupUpdaters(); launcherUpdaterWorker.RunWorkerAsync(); } private void SetVersions() { string newGameVersion = Versioning.FriendlyCurrentGameVersion(); GameVersionLabel.Content = newGameVersion; LauncherVersionLabel.Content = Versioning.FriendlyLauncherVersion; } private void SetupUpdaters() { PlayButton.IsEnabled = false; patcherDirectory = Settings.LauncherDataFolder; launcherDownloadEvent = new AutoResetEvent(false); launcherUpdaterWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; launcherUpdaterWorker.DoWork += new DoWorkEventHandler(LauncherUpdate); launcherUpdaterWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(LauncherUpdateComplete); patchDownloadEvent = new AutoResetEvent(false); patchUpdaterWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; patchUpdaterWorker.DoWork += new DoWorkEventHandler(GameUpdate); patchUpdaterWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(GameUpdateComplete); } private void LauncherUpdate(object sender, DoWorkEventArgs e) { SetProgressBar(0); BackgroundWorker worker = (BackgroundWorker)sender; Version currentVersion = Versioning.LauncherVersion; Version latestVersion; SetTextStatus(App.resourceManager.GetString("lc_checking_new_version")); if (worker.CancellationPending) { e.Cancel = true; return; } try { String versionURI = $"{Settings.LauncherPatchesURL}{Settings.LauncherVersionFN}"; using (WebClientAuth wc = new WebClientAuth()) { latestVersion = Version.Parse(wc.DownloadString(versionURI)); } } catch (FormatException ex) { e.Cancel = true; MBError(String.Format("Server has invalid response for url `{0}` . {1}", $"{Settings.LauncherPatchesURL}{Settings.LauncherVersionFN}", ex.Message)); return; } catch (WebException ex) { if (ex.Message.Contains("timed out")) { MBError("Unable to retrieve latest version, request timed out."); } HttpWebResponse response = (HttpWebResponse)ex.Response; if (response == null) { MBError("Unable to retrieve latest version, no response."); } else { MBError(String.Format( "{0} \nResponse: {1} {2}", "Unable to retrieve latest version.", (int)response.StatusCode, response.StatusDescription )); } e.Cancel = true; return; } catch (KeyNotFoundException ex) { e.Cancel = true; MBError(ex.Message); MBError(ex.StackTrace); return; } if (worker.CancellationPending) { e.Cancel = true; return; } int versionDifference = currentVersion.CompareTo(latestVersion); if (versionDifference.Equals(-1)) { SetTextStatus(App.resourceManager.GetString("start_downloading")); WebClientAuth webClient = new WebClientAuth(); webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(LauncherWebClient_DownloadProgressChanged); webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(LauncherWebClient_DownloadFileCompleted); string tempLauncherFilename = Path.GetTempFileName(); Debug.WriteLine(tempLauncherFilename); string launcher_filename = "AyalaLauncher.exe"; string launcher_uri = Settings.LauncherPatchesURL + launcher_filename; launcherDownloadEvent.Reset(); try { webClient.DownloadFileAsync(new Uri(launcher_uri), tempLauncherFilename, launcher_filename); } catch (Exception ex) { e.Cancel = true; MBError(ex.Message + "\n" + ex.StackTrace); return; } launcherDownloadEvent.WaitOne(); if (launcherDownloadingException != null) { WebException webex = (WebException)launcherDownloadingException; HttpWebResponse response = (HttpWebResponse)webex.Response; e.Cancel = true; MBError(String.Format( "{0}\nMessage: {1}\nRequest: {2}\nResponse: {3}", App.resourceManager.GetString("cant_get_patch"), webex.Message, (response != null ? response.ResponseUri.ToString() : "null"), (response != null ? response.StatusDescription : "null") )); return; } try { LauncherUpdater.RenameRunningLauncher(); LauncherUpdater.CopyNewLauncher(tempLauncherFilename); } catch (Exception ex) { MBError(String.Format(App.resourceManager.GetString("unknown_exception"), ex.Message, ex.StackTrace)); e.Cancel = true; return; } finally { LauncherUpdater.RestartToNewLauncher(); } File.Delete(tempLauncherFilename); } } private void LauncherUpdateComplete(object sender, RunWorkerCompletedEventArgs e) { if (!e.Cancelled) { PlayButton.IsEnabled = true; SetTextStatus(App.resourceManager.GetString("update_done")); SetProgressBar(100); patchUpdaterWorker.RunWorkerAsync(); return; } SetTextStatus(App.resourceManager.GetString("update_error")); SetProgressBar(0); } private void LauncherWebClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { if (e.Error != null) launcherDownloadingException = e.Error; else launcherDownloadingException = null; launcherDownloadEvent.Set(); } private void LauncherWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { SetTextStatus(string.Format(App.resourceManager.GetString("downloading"), "New Launcher", Updater.HumanReadableSizeFormat(e.BytesReceived), Updater.HumanReadableSizeFormat(e.TotalBytesToReceive), e.ProgressPercentage.ToString())); SetProgressBar(e.ProgressPercentage); } private void GameUpdateComplete(object sender, RunWorkerCompletedEventArgs e) { if (!e.Cancelled) { PlayButton.IsEnabled = true; SetTextStatus(App.resourceManager.GetString("update_done")); SetProgressBar(100); return; } SetTextStatus(App.resourceManager.GetString("update_error")); SetProgressBar(0); } private void UpdateVersionAfterPatch(int verNumber) { Versioning.SetNewVersionAfterPatch(verNumber); if (!Dispatcher.CheckAccess()) { Dispatcher.Invoke(() => GameVersionLabel.Content = Versioning.FriendlyCurrentGameVersion()); } else GameVersionLabel.Content = Versioning.FriendlyCurrentGameVersion(); } private void SetTextStatus(string text) { Dispatcher.Invoke(() => { UpdaterStatusLabel.Content = text; }); } private void SetProgressBar(int percent) { Dispatcher.BeginInvoke((Action)(() => { UpdaterProgressBar.Value = percent; })); } private void MBError(string errorMsg) { Dispatcher.Invoke(() => { MessageBox.Show(this, errorMsg, "Error", MessageBoxButton.OK, MessageBoxImage.Error); }); } private void MBError(string errorMsg, string title) { Dispatcher.Invoke(() => { MessageBox.Show(this, errorMsg, title, MessageBoxButton.OK, MessageBoxImage.Error); }); } private bool MBErrorYesNo(string errorMsg) { return Dispatcher.Invoke(() => { var mbResult = MessageBox.Show(this, errorMsg, "Error", MessageBoxButton.YesNo, MessageBoxImage.Error); return mbResult.Equals(MessageBoxResult.Yes) ? true : false; }); } private void GameUpdate(object sender, DoWorkEventArgs e) { SetProgressBar(0); SetTextStatus(App.resourceManager.GetString("checking_version")); BackgroundWorker worker = (BackgroundWorker)sender; int currentVersion = 0; int lastVersion = 0; try { currentVersion = Versioning.CurrentGameVersion; } catch { e.Cancel = true; MBError(App.resourceManager.GetString("cant_get_current_version")); return; } SetTextStatus(App.resourceManager.GetString("checking_new_version")); if (worker.CancellationPending) { e.Cancel = true; return; } try { String versionURI = $"{Settings.GamePatchesURL}{Settings.GameVersionFN}"; using (WebClientAuth wc = new WebClientAuth()) { lastVersion = int.Parse(wc.DownloadString(versionURI)); } } catch (FormatException) { e.Cancel = true; MBError(string.Format("For url `{0}` server has invalid response. Integer is expected.", $"{Settings.GamePatchesURL}{Settings.GameVersionFN}")); return; } catch (WebException ex) { e.Cancel = true; HttpWebResponse response = (HttpWebResponse)ex.Response; MBError($"{App.resourceManager.GetString("cant_get_new_version")} \nResponse: {(int)response.StatusCode} {response.StatusDescription}"); return; } catch (KeyNotFoundException ex) { e.Cancel = true; MBError(ex.Message); MBError(ex.StackTrace); return; } if (worker.CancellationPending) { e.Cancel = true; return; } for (int i = currentVersion; i < lastVersion; i++) { SetTextStatus(App.resourceManager.GetString("start_downloading")); WebClientAuth webClient = new WebClientAuth(); webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(GameWebClient_DownloadProgressChanged); webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(GameWebClient_DownloadFileCompleted); string tempPatchFilename = Path.GetTempFileName(); string patch_filename = string.Format("{0}_{1}.patch", i, i + 1); string patch_uri = Settings.GamePatchesURL + patch_filename; patchDownloadEvent.Reset(); try { webClient.DownloadFileAsync(new Uri(patch_uri), tempPatchFilename, patch_filename); } catch (UriFormatException) { e.Cancel = true; MBError("Configuration.patches_directory is incorrect. Nothing can be downloaded from `" + patch_uri + "`. Url expected."); return; } patchDownloadEvent.WaitOne(); if (patchDownloadingException != null) { WebException webex = (WebException)patchDownloadingException; HttpWebResponse response = (HttpWebResponse)webex.Response; e.Cancel = true; MBError(App.resourceManager.GetString("cant_get_patch") + "\nMessage: " + webex.Message + "\nRequest: " + (response != null ? response.ResponseUri.ToString() : "null") + "\nResponse: " + (response != null ? response.StatusDescription : "null")); return; } try { Updater.ApplyPatch(tempPatchFilename, new Action(delegate (string text, int percent) { SetTextStatus(text); SetProgressBar(percent); })); } catch (PatcherException ex) { MBError($"Error patching game:\n{ex.Message}", "Patcher error"); e.Cancel = true; return; } catch (Exception ex) { MBError(string.Format(App.resourceManager.GetString("unknown_exception"), ex.Message, ex.StackTrace)); e.Cancel = true; return; } UpdateVersionAfterPatch(i + 1); File.Delete(tempPatchFilename); } } private void GameWebClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { if (e.Error != null) patchDownloadingException = e.Error; else patchDownloadingException = null; patchDownloadEvent.Set(); } private void GameWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { SetTextStatus(string.Format(App.resourceManager.GetString("downloading"), e.UserState.ToString(), Updater.HumanReadableSizeFormat(e.BytesReceived), Updater.HumanReadableSizeFormat(e.TotalBytesToReceive), e.ProgressPercentage.ToString())); SetProgressBar(e.ProgressPercentage); } private void PlayButton_Click(object sender, RoutedEventArgs e) { PlayButton.IsEnabled = false; if (StartClient(out string mbText)) { Environment.Exit(1); } else { MessageBox.Show(Application.Current.MainWindow, mbText, "Error"); PlayButton.IsEnabled = true; } } private bool StartClient(out string errorMessage) { var clientExe = Settings.ClientName; var serverIP = Settings.ServerIP; errorMessage = null; try { Process.Start(clientExe, $"-osk_server {serverIP}"); return true; } catch (FileNotFoundException) { errorMessage = $"Can't find game executable: {clientExe}\n Please reinstall game."; return false; } catch (Exception ex) { errorMessage = $"Client start error: {ex.Message}"; return false; } } private void Window_MouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) DragMove(); } private void ExitButton_Click(object sender, RoutedEventArgs e) { Application.Current.Shutdown(); } private void UpdaterProgressBar_Loaded(object sender, RoutedEventArgs e) { var progressBar = sender as ProgressBar; if (progressBar == null) return; progressBar.Foreground = new SolidColorBrush(Colors.Pink); } } }