/// <summary>
        /// UI method for patching the specified file at the given file path
        /// </summary>
        /// <param name="filePath">file path</param>
        private void Patch(string filePath)
        {
            // First check if the selected executable is valid
            // and if the game build is supported
            Dispatcher.Invoke(() => PatcherStatus.Text = "Checking game version...");

            GameBuild gameBuild = null;

            try
            {
                gameBuild = Patcher.GetGameBuild(filePath);
            }
            catch (Exception)
            {
                MessageBox.Show("An error occured while checking the game version.",
                                "Error",
                                MessageBoxButton.OK,
                                MessageBoxImage.Error);

                Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
                return;
            }

            // Unknown game build
            if (gameBuild == null)
            {
                MessageBox.Show("Make sure the selected file is correct and that " +
                                "you are not selecting an already patched game executable, or check for updates.",
                                "Unsupported game version detected",
                                MessageBoxButton.OK,
                                MessageBoxImage.Warning);

                Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
                return;
            }

            // Back up the executable?
            var makeBackup = MessageBox.Show("Do you want to make a backup of the current game executable?",
                                             "Backup",
                                             MessageBoxButton.YesNo,
                                             MessageBoxImage.Question);

            if (makeBackup == MessageBoxResult.Yes)
            {
                var saveFileDialog = new SaveFileDialog()
                {
                    Filter      = "All Files (.*)|*.*",
                    FilterIndex = 1,
                    FileName    = "DOOMEternalx64vk.exe.bak",
                    Title       = "Save DOOM Eternal game executable file backup (.bak)"
                };

                if (saveFileDialog.ShowDialog() == true)
                {
                    try
                    {
                        if (File.Exists(saveFileDialog.FileName))
                        {
                            File.Delete(saveFileDialog.FileName);
                        }

                        File.Copy(filePath, saveFileDialog.FileName);
                    }
                    catch (Exception)
                    {
                        var continueOrCancel = MessageBox.Show("An error occured while backing up the game executable. " +
                                                               "Do you want to continue patching anyways?",
                                                               "Error",
                                                               MessageBoxButton.OKCancel,
                                                               MessageBoxImage.Error);

                        if (continueOrCancel == MessageBoxResult.Cancel)
                        {
                            Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                            Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                            Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
                            return;
                        }
                    }
                }
            }

            // Patch the executable
            Dispatcher.Invoke(() => PatcherStatus.Text = "Patching...");

            try
            {
                var patchingResult = Patcher.ApplyPatches(filePath, gameBuild.Patches);

                // Display patching results
                var succesfulPatches = new StringBuilder();
                var failedPatches    = new StringBuilder();
                var resultsString    = new StringBuilder();
                int successes        = 0;
                int fails            = 0;

                foreach (var patchResult in patchingResult)
                {
                    if (patchResult.Success)
                    {
                        succesfulPatches.Append(patchResult.Patch.Description).Append("\n");
                        successes++;
                        continue;
                    }

                    failedPatches.Append(patchResult.Patch.Description).Append("\n");
                    fails++;
                }

                if (successes > 0)
                {
                    resultsString.Append("The following patches were successfuly applied:\n\n");
                    resultsString.Append(succesfulPatches);
                }

                if (fails > 0)
                {
                    if (successes > 0)
                    {
                        resultsString.Append("\n");
                    }

                    resultsString.Append("The following patches could not be applied:\n\n");
                    resultsString.Append(failedPatches);
                }

                resultsString.Append($"\n{successes} patches out of {gameBuild.Patches.Count} applied.");

                MessageBox.Show(resultsString.ToString(),
                                "Patching results",
                                MessageBoxButton.OK,
                                fails > 0 ? MessageBoxImage.Warning : MessageBoxImage.Information);
            }
            catch (Exception)
            {
                MessageBox.Show($"An error occured while patching the game executable.",
                                "Error",
                                MessageBoxButton.OK,
                                MessageBoxImage.Error);
            }
            finally
            {
                Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
            }
        }
Example #2
0
        /// <summary>
        /// Fired on startup
        /// </summary>
        /// <param name="e">startup event args</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            // Used for command line option parsing
            bool   performUpdate = false;
            string filePath      = string.Empty;

            // Parse command line arguments
            if (e.Args != null & e.Args.Length > 0)
            {
                for (var i = 0; i < e.Args.Length; i++)
                {
                    if (e.Args[i].Equals("--patch", StringComparison.InvariantCultureIgnoreCase) && string.IsNullOrEmpty(filePath))
                    {
                        if (i + 1 < e.Args.Length)
                        {
                            filePath = e.Args[i + 1];
                            continue;
                        }
                    }
                    else if (e.Args[i].Equals("--update", StringComparison.InvariantCultureIgnoreCase) && !performUpdate)
                    {
                        performUpdate = true;
                        continue;
                    }
                }
            }

            // Only show the UI when not using the command-line version
            if (string.IsNullOrEmpty(filePath) && !performUpdate)
            {
                var window = new MainWindow();
                window.ShowDialog();
            }
            else
            {
                // Allocate a console
                AllocConsole();

                // Update first if required
                try
                {
                    if (performUpdate)
                    {
                        Console.WriteLine("Checking for updates...");

                        if (Patcher.AnyUpdateAvailable())
                        {
                            Console.WriteLine("Downloading latest patch definitions...");
                            Patcher.DownloadLatestPatchDefinitions();
                            Console.WriteLine("Done.");
                        }
                        else
                        {
                            Console.WriteLine("No updates available.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"An error occured while checking for updates: {ex}");
                    Application.Current.Shutdown(1);
                    return;
                }

                // Stop here if no path was specified
                if (string.IsNullOrEmpty(filePath))
                {
                    Application.Current.Shutdown(0);
                    return;
                }

                // Load the patch definitions file
                try
                {
                    Console.WriteLine("Loading patch definitions file...");
                    Patcher.LoadPatchDefinitions();
                    Console.WriteLine("Done.");
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"An error occured while loading the patch definitions file: {ex}");
                    Application.Current.Shutdown(1);
                    return;
                }

                // Stop if there are no patches loaded
                if (!Patcher.AnyPatchesLoaded())
                {
                    Console.Out.WriteLine($"Unable to patch: 0 patches loaded");
                    Application.Current.Shutdown(1);
                    return;
                }

                // Check game build
                GameBuild gameBuild = null;

                try
                {
                    Console.WriteLine("Checking game build...");
                    gameBuild = Patcher.GetGameBuild(filePath);

                    if (gameBuild == null)
                    {
                        Console.Out.WriteLine($"Unable to apply patches: unsupported game build detected");
                        Application.Current.Shutdown(1);
                        return;
                    }

                    Console.WriteLine($"{gameBuild.Id} detected.");
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"An error occured while checking the game build: {ex}");
                    Application.Current.Shutdown(1);
                    return;
                }

                // Patch the specified file
                int successes = 0;

                try
                {
                    Console.WriteLine("Applying patches...");

                    foreach (var patchResult in Patcher.ApplyPatches(filePath, gameBuild.Patches))
                    {
                        if (patchResult.Success)
                        {
                            successes++;
                        }

                        Console.WriteLine($"{patchResult.Patch.Description} : {(patchResult.Success ? "Success" : "Failure")}");
                    }

                    Console.WriteLine($"\n{successes} out of {gameBuild.Patches.Count} applied.");
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine($"An error occured while patching the game executable: {ex}");
                    Application.Current.Shutdown(1);
                    return;
                }

                Application.Current.Shutdown(successes == gameBuild.Patches.Count ? 0 : 1);
            }
        }
        /// <summary>
        /// UI method to check for patch definition updates
        /// </summary>
        /// <param name="silent">don't show alerts when no updates availabe</param>
        private void CheckForUpdates(bool silent)
        {
            Dispatcher.Invoke(() => PatchButton.IsEnabled        = false);
            Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = false);
            Dispatcher.Invoke(() => PatcherStatus.Text           = "Checking for updates...");

            // Check if there are available updates
            var updatesNeeded = false;

            try
            {
                updatesNeeded = Patcher.AnyUpdateAvailable();

                if (!updatesNeeded)
                {
                    if (!silent)
                    {
                        MessageBox.Show("You are already have the latest patch definitions.",
                                        "Check for updates",
                                        MessageBoxButton.OK,
                                        MessageBoxImage.Information);
                    }

                    // Load current patch definitions if needed
                    if (!Patcher.AnyPatchesLoaded())
                    {
                        Dispatcher.Invoke(() => PatcherStatus.Text = "Loading patch definitions...");
                        Patcher.LoadPatchDefinitions();
                    }

                    Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                    Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                    Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
                    return;
                }
            }
            catch (Exception)
            {
                MessageBox.Show("An error occured while checking for updates.",
                                "Error",
                                MessageBoxButton.OK,
                                MessageBoxImage.Error);

                // Load current patch definitions anyway
                if (!Patcher.AnyPatchesLoaded())
                {
                    Dispatcher.Invoke(() => PatcherStatus.Text = "Loading patch definitions...");
                    Patcher.LoadPatchDefinitions();
                }

                Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
                return;
            }

            // Download updates if needed
            if (updatesNeeded)
            {
                try
                {
                    Dispatcher.Invoke(() => PatcherStatus.Text = "Downloading updates...");
                    Patcher.DownloadLatestPatchDefinitions();
                    Dispatcher.Invoke(() => PatcherStatus.Text = "Updates downloaded");
                }
                catch (Exception e)
                {
                    MessageBox.Show("An error occured while downloading the updates.",
                                    "Error",
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);

                    // Load current patch definitions anyway
                    if (!Patcher.AnyPatchesLoaded())
                    {
                        Dispatcher.Invoke(() => PatcherStatus.Text = "Loading patch definitions...");
                        Patcher.LoadPatchDefinitions();
                    }

                    Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                    Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                    Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
                    return;
                }
            }

            // Load the updated patch definitions
            try
            {
                Dispatcher.Invoke(() => PatcherStatus.Text = "Loading patch definitions...");
                Patcher.LoadPatchDefinitions();
                MessageBox.Show("Patch definitions have been successfully updated.",
                                "Check for updates",
                                MessageBoxButton.OK,
                                MessageBoxImage.Information);
            }
            catch (Exception)
            {
                MessageBox.Show("An error occured while loading the updated patch definitions.",
                                "Error",
                                MessageBoxButton.OK,
                                MessageBoxImage.Error);
            }
            finally
            {
                Dispatcher.Invoke(() => PatchButton.IsEnabled        = true);
                Dispatcher.Invoke(() => CheckUpdatesButton.IsEnabled = true);
                Dispatcher.Invoke(() => PatcherStatus.Text           = "Ready.");
            }
        }