From 5d412a82b621377f562dc379046112e616f06b80 Mon Sep 17 00:00:00 2001 From: Matheus Fraguas <16923826+sonik-br@users.noreply.github.com> Date: Tue, 14 Apr 2026 19:18:41 -0300 Subject: [PATCH] Added option to save the patched exe. Uses translated DDGO Final GameConfig if present. Sets "en-Us" culture on app load. Should prevent errors on non english host OS. --- DDGModernizer/Dashboard.Designer.cs | 16 +++++- DDGModernizer/Dashboard.cs | 81 ++++++++++++++++++++++++----- DDGModernizer/Patcher.cs | 70 +++++++++++++++++-------- DDGModernizer/Program.cs | 2 + 4 files changed, 133 insertions(+), 36 deletions(-) diff --git a/DDGModernizer/Dashboard.Designer.cs b/DDGModernizer/Dashboard.Designer.cs index e2287dc..8dda56d 100644 --- a/DDGModernizer/Dashboard.Designer.cs +++ b/DDGModernizer/Dashboard.Designer.cs @@ -65,6 +65,7 @@ private void InitializeComponent() this.groupBox4 = new System.Windows.Forms.GroupBox(); this.checkBox_Borderless = new System.Windows.Forms.CheckBox(); this.button_GameConfig = new System.Windows.Forms.Button(); + this.button_PatchSave = new System.Windows.Forms.Button(); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.upDown_WinZoom)).BeginInit(); @@ -515,7 +516,7 @@ private void InitializeComponent() // button_GameConfig // this.button_GameConfig.Enabled = false; - this.button_GameConfig.Location = new System.Drawing.Point(13, 371); + this.button_GameConfig.Location = new System.Drawing.Point(13, 345); this.button_GameConfig.Name = "button_GameConfig"; this.button_GameConfig.Size = new System.Drawing.Size(157, 23); this.button_GameConfig.TabIndex = 27; @@ -523,11 +524,23 @@ private void InitializeComponent() this.button_GameConfig.UseVisualStyleBackColor = true; this.button_GameConfig.Click += new System.EventHandler(this.button_GameConfig_Click); // + // button_PatchSave + // + this.button_PatchSave.Enabled = false; + this.button_PatchSave.Location = new System.Drawing.Point(13, 371); + this.button_PatchSave.Name = "button_PatchSave"; + this.button_PatchSave.Size = new System.Drawing.Size(157, 23); + this.button_PatchSave.TabIndex = 28; + this.button_PatchSave.Text = "Patch and Save EXE"; + this.button_PatchSave.UseVisualStyleBackColor = true; + this.button_PatchSave.Click += new System.EventHandler(this.button_PatchSave_Click); + // // Dashboard // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(352, 401); + this.Controls.Add(this.button_PatchSave); this.Controls.Add(this.button_GameConfig); this.Controls.Add(this.groupBox4); this.Controls.Add(this.button_Go); @@ -596,6 +609,7 @@ private void InitializeComponent() private System.Windows.Forms.GroupBox groupBox4; private System.Windows.Forms.CheckBox checkBox_Borderless; private System.Windows.Forms.Button button_GameConfig; + private System.Windows.Forms.Button button_PatchSave; } } diff --git a/DDGModernizer/Dashboard.cs b/DDGModernizer/Dashboard.cs index 7d04ebd..9257269 100644 --- a/DDGModernizer/Dashboard.cs +++ b/DDGModernizer/Dashboard.cs @@ -226,6 +226,8 @@ private void ValidateGoButton() button_Go.Enabled = enabled; + button_PatchSave.Enabled = enabled; + button_GameConfig.Enabled = Directory.Exists(textBox_GameFolder.Text); checkBox_Borderless.Enabled = (currentVersion == DDGVersion.PRO_2 || currentVersion == DDGVersion.FINAL); @@ -235,19 +237,7 @@ private void button_Go_Click(object sender, EventArgs e) { try { - Patcher patcher = new Patcher(currentVersion); - - patcher.SetModuleEnabled(Patcher.MODULE_KEY_ASPECT, checkBox_AspectEnable.Checked); - patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "AspectX", (float)upDown_XAspect.Value); - patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "AspectY", (float)upDown_YAspect.Value); - patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "AspectRatio", (float)upDown_WinX.Value / (float)upDown_WinY.Value); - patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "WinZoom", (float)upDown_WinZoom.Value); - - patcher.SetModuleEnabled(Patcher.MODULE_KEY_DRAW_DISTANCE, checkBox_DrawDistEnable.Checked); - patcher.SetModuleArg(Patcher.MODULE_KEY_DRAW_DISTANCE, "RendPow", (float)upDown_RendPow.Value); - - patcher.SetModuleEnabled(Patcher.MODULE_KEY_BORDERLESS, checkBox_Borderless.Checked); - + Patcher patcher = createAndConfigurePatcher(); patcher.PatchAndRun(textBox_EXEPath.Text, textBox_GameFolder.Text); } catch (Exception exception) @@ -423,7 +413,10 @@ private void button_GameConfig_Click(object sender, EventArgs e) switch (currentVersion) { case DDGVersion.FINAL: - path = Path.Combine(textBox_GameFolder.Text, "dgfncal.exe"); + // Check for translated file, with fall back to original file + path = Path.Combine(textBox_GameFolder.Text, "ddgfncal.exe"); + if (!File.Exists(path)) + path = Path.Combine(textBox_GameFolder.Text, "dgfncal.exe"); break; case DDGVersion.PRO_2: @@ -452,5 +445,65 @@ private void button_GameConfig_Click(object sender, EventArgs e) } #endregion + + #region Patch and Save Button + private void button_PatchSave_Click(object sender, EventArgs e) + { + string filePath = null; + try + { + using (SaveFileDialog openFileDialog = new SaveFileDialog()) + { + openFileDialog.InitialDirectory = Path.GetDirectoryName(textBox_EXEPath.Text); + openFileDialog.FileName = $"{Path.GetFileNameWithoutExtension(textBox_EXEPath.Text)}_patched{Path.GetExtension(textBox_EXEPath.Text)}"; + openFileDialog.Filter = "exe files (*.exe)|*.exe|All files (*.*)|*.*"; + openFileDialog.FilterIndex = 2; + openFileDialog.RestoreDirectory = true; + + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + if (textBox_EXEPath.Text.Equals(openFileDialog.FileName, StringComparison.OrdinalIgnoreCase)) + throw new Exception("Can't save over original executable!"); + filePath = openFileDialog.FileName; + } + } + + if (!string.IsNullOrWhiteSpace(filePath)) + { + Patcher patcher = createAndConfigurePatcher(); + patcher.PatchAndSave(textBox_EXEPath.Text, filePath); + MessageBox.Show("Success!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + catch (Exception exception) + { + // Delete new file in case of error + if (!string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath)) + try { File.Delete(filePath); } catch { } + + MessageBox.Show(exception.Message); + } + } + #endregion + + #region Configure Patcher + Patcher createAndConfigurePatcher() + { + Patcher patcher = new Patcher(currentVersion); + + patcher.SetModuleEnabled(Patcher.MODULE_KEY_ASPECT, checkBox_AspectEnable.Checked); + patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "AspectX", (float)upDown_XAspect.Value); + patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "AspectY", (float)upDown_YAspect.Value); + patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "AspectRatio", (float)upDown_WinX.Value / (float)upDown_WinY.Value); + patcher.SetModuleArg(Patcher.MODULE_KEY_ASPECT, "WinZoom", (float)upDown_WinZoom.Value); + + patcher.SetModuleEnabled(Patcher.MODULE_KEY_DRAW_DISTANCE, checkBox_DrawDistEnable.Checked); + patcher.SetModuleArg(Patcher.MODULE_KEY_DRAW_DISTANCE, "RendPow", (float)upDown_RendPow.Value); + + patcher.SetModuleEnabled(Patcher.MODULE_KEY_BORDERLESS, checkBox_Borderless.Checked); + + return patcher; + } + #endregion } } diff --git a/DDGModernizer/Patcher.cs b/DDGModernizer/Patcher.cs index 6d32dcb..524c176 100644 --- a/DDGModernizer/Patcher.cs +++ b/DDGModernizer/Patcher.cs @@ -349,8 +349,56 @@ public void PatchAndRun(string exePath, string workingDir) File.Copy(exePath, patchExePath); // Go through each module's injections and inject the bytes - FileStream file = File.Open(patchExePath, FileMode.Open, FileAccess.ReadWrite); + using (FileStream file = File.Open(patchExePath, FileMode.Open, FileAccess.ReadWrite)) + { + // Apply patches to new file + applyPatches(file); + } + + // Launch the patched EXE + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = patchExePath, + WorkingDirectory = workingDir + } + }; + + process.Start(); + process.WaitForExit(); + + // Clean up + File.Delete(patchExePath); + Directory.Delete(tempDir); + } + #endregion + + #region Save + public void PatchAndSave(string originalExePath, string newExePath) + { + // Load original file into memory + byte[] fileBytes = File.ReadAllBytes(originalExePath); + using (MemoryStream ms = new MemoryStream(fileBytes)) + { + // Apply patches to memory loaded file + applyPatches(ms); + + // Save modified file + ms.Position = 0; + using (FileStream fileStream = new FileStream(newExePath, FileMode.Create, FileAccess.Write)) + { + ms.CopyTo(fileStream); + } + } + } + #endregion + + #region Apply + void applyPatches(Stream file) + { + // Go through each module's injections and inject the bytes foreach (var module in moduleList) { if (module.enabled == false) @@ -392,27 +440,7 @@ public void PatchAndRun(string exePath, string workingDir) file.Write(preppedBytes, 0, preppedBytes.Length); } } - - file.Close(); - - // Launch the patched EXE - var process = new Process - { - StartInfo = new ProcessStartInfo - { - FileName = patchExePath, - WorkingDirectory = workingDir - } - }; - - process.Start(); - process.WaitForExit(); - - // Clean up - File.Delete(patchExePath); - Directory.Delete(tempDir); } - #endregion } } diff --git a/DDGModernizer/Program.cs b/DDGModernizer/Program.cs index b761fb3..caff2fe 100644 --- a/DDGModernizer/Program.cs +++ b/DDGModernizer/Program.cs @@ -14,6 +14,8 @@ static class Program [STAThread] static void Main() { + // Force en-Us to avoid decimal parsing errors + System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-Us"); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Dashboard());