diff --git a/GameLauncher.csproj b/GameLauncher.csproj
index b187788..e69d6a5 100644
--- a/GameLauncher.csproj
+++ b/GameLauncher.csproj
@@ -27,7 +27,7 @@
Form
-
+
Form
diff --git a/Management.cs b/Management.cs
index bb1f143..abb2493 100644
--- a/Management.cs
+++ b/Management.cs
@@ -23,7 +23,7 @@ internal static class Management
public static readonly Version Version = Assembly.GetEntryAssembly()!.GetName().Version!;
public static readonly string VersionString = Version.ToString(3);
- public static readonly string ExecutablePath = Assembly.GetEntryAssembly()!.Location;
+ public static readonly string ExecutablePath = Environment.ProcessPath!;
public static Config Config;
public static bool IGDBViable => !string.IsNullOrEmpty(Config.IGDBId) && !string.IsNullOrEmpty(Config.IGDBSecret);
public static event Action ThemeChange;
diff --git a/Models/LocalGame.cs b/Models/LocalGame.cs
index 02dd45f..dcb9893 100644
--- a/Models/LocalGame.cs
+++ b/Models/LocalGame.cs
@@ -39,6 +39,7 @@ public string GamePath
private string launchPath;
public string? CoverPath => this.coverPath;
+ public string GameMetadataPath => this.gameMetadataPath;
public bool HasCover => this.CoverPath != null && File.Exists(this.CoverPath);
public LocalGame(string filePath)
@@ -151,18 +152,9 @@ public void LoadOrDownloadResources()
if (game == null)
{
MessageBox.Show("Game not found on IGDB", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
- IGDBSearchResultsForm form = new(Path.GetFileName(this.GamePath));
- DialogResult result = form.ShowDialog();
-
- if (result == DialogResult.OK && form.SelectedGame != null)
- {
- string newPath = $"{this.GamePath.TrimEnd('\\', '/')} [{form.SelectedGame.Id}]";
- Directory.Move(this.GamePath, newPath);
- this.GamePath = newPath;
-
+ if (MetadataOverrideForm.OverrideMetadata(this))
game = Management.IGDBObj.Search(Path.GetFileName(this.GamePath))
.FirstOrDefault();
- }
else
return;
}
diff --git a/Program.cs b/Program.cs
index e713335..6096aa2 100644
--- a/Program.cs
+++ b/Program.cs
@@ -53,7 +53,7 @@ static void Main()
//splashForm.Invoke(splashForm.Close);
- Application.Run(new Form1());
+ Application.Run(new MainForm());
}
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
diff --git a/README.md b/README.md
index 22dd930..51f39f5 100644
--- a/README.md
+++ b/README.md
@@ -11,16 +11,11 @@
## To-do
- [ ] Improve game automatic detection for launch.dat
- [ ] Play time counter
-- [ ] Make uninstall work
- [ ] Save file management and quick swapping
-- [ ] Add auto-updating
- [ ] Possibly add game source providing
-- [ ] Fix dir names feature
- [ ] Note unrecognized games
- [ ] Add splash screen
-- [ ] Custom metadata override
-
-
+- [ ] Fix dark mode
## Versions
@@ -28,8 +23,7 @@
- [ ] Added auto-updating
- [ ] Added custom metadata override
-- [ ] Fixed dark theme
-- [ ] Added game name cleanup
+- [ ] Added game name matching
### Beta 1.4.8
diff --git a/UI/Controls/GamePanelControl.cs b/UI/Controls/GamePanelControl.cs
index f6d4dc6..2a873ea 100644
--- a/UI/Controls/GamePanelControl.cs
+++ b/UI/Controls/GamePanelControl.cs
@@ -18,9 +18,9 @@ namespace GameLauncher
public partial class GamePanelControl : UserControl, ITick
{
public LocalGame Game;
- private Form1 originForm;
+ private MainForm originForm;
private bool stillLoading = true;
- public GamePanelControl(Form1 originForm, LocalGame game)
+ public GamePanelControl(MainForm originForm, LocalGame game)
{
this.originForm = originForm;
this.Game = game;
diff --git a/UI/Forms/IGDBSearchResultsForm.Designer.cs b/UI/Forms/IGDBSearchResultsForm.Designer.cs
deleted file mode 100644
index 2b28325..0000000
--- a/UI/Forms/IGDBSearchResultsForm.Designer.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-namespace GameLauncher.UI.Forms
-{
- partial class IGDBSearchResultsForm
- {
- ///
- /// Required designer variable.
- ///
- private System.ComponentModel.IContainer components = null;
-
- ///
- /// Clean up any resources being used.
- ///
- /// true if managed resources should be disposed; otherwise, false.
- protected override void Dispose(bool disposing)
- {
- if (disposing && (components != null))
- {
- components.Dispose();
- }
- base.Dispose(disposing);
- }
-
- #region Windows Form Designer generated code
-
- ///
- /// Required method for Designer support - do not modify
- /// the contents of this method with the code editor.
- ///
- private void InitializeComponent()
- {
- ResultBox = new ListBox();
- SearchBox = new TextBox();
- label1 = new Label();
- SelectButton = new Button();
- SearchButton = new Button();
- this.SuspendLayout();
- //
- // ResultBox
- //
- ResultBox.FormattingEnabled = true;
- ResultBox.ItemHeight = 32;
- ResultBox.Location = new Point(22, 85);
- ResultBox.Margin = new Padding(6, 6, 6, 6);
- ResultBox.Name = "ResultBox";
- ResultBox.Size = new Size(615, 228);
- ResultBox.TabIndex = 0;
- //
- // SearchBox
- //
- SearchBox.Location = new Point(154, 18);
- SearchBox.Margin = new Padding(6, 6, 6, 6);
- SearchBox.Name = "SearchBox";
- SearchBox.Size = new Size(335, 39);
- SearchBox.TabIndex = 1;
- SearchBox.KeyDown += this.SearchBox_KeyDown;
- //
- // label1
- //
- label1.AutoSize = true;
- label1.Location = new Point(15, 21);
- label1.Margin = new Padding(6, 0, 6, 0);
- label1.Name = "label1";
- label1.Size = new Size(131, 32);
- label1.TabIndex = 2;
- label1.Text = "Term or ID:";
- //
- // SelectButton
- //
- SelectButton.Location = new Point(501, 331);
- SelectButton.Margin = new Padding(6, 6, 6, 6);
- SelectButton.Name = "SelectButton";
- SelectButton.Size = new Size(139, 49);
- SelectButton.TabIndex = 3;
- SelectButton.Text = "Select";
- SelectButton.UseVisualStyleBackColor = true;
- SelectButton.Click += this.SelectButton_Click;
- //
- // SearchButton
- //
- SearchButton.Location = new Point(501, 13);
- SearchButton.Margin = new Padding(6, 6, 6, 6);
- SearchButton.Name = "SearchButton";
- SearchButton.Size = new Size(139, 49);
- SearchButton.TabIndex = 4;
- SearchButton.Text = "Search";
- SearchButton.UseVisualStyleBackColor = true;
- SearchButton.Click += this.SearchButton_Click;
- //
- // IGDBSearchResultsForm
- //
- this.AutoScaleDimensions = new SizeF(13F, 32F);
- this.AutoScaleMode = AutoScaleMode.Font;
- this.ClientSize = new Size(652, 395);
- this.Controls.Add(SearchButton);
- this.Controls.Add(SelectButton);
- this.Controls.Add(label1);
- this.Controls.Add(SearchBox);
- this.Controls.Add(ResultBox);
- this.FormBorderStyle = FormBorderStyle.FixedDialog;
- this.Margin = new Padding(6, 6, 6, 6);
- this.MaximizeBox = false;
- this.MinimizeBox = false;
- this.Name = "IGDBSearchResultsForm";
- this.Text = "IGDB Search Results";
- this.Load += this.IGDBSearchResultsForm_Load;
- this.ResumeLayout(false);
- this.PerformLayout();
- }
-
- #endregion
-
- private ListBox ResultBox;
- private TextBox SearchBox;
- private Label label1;
- private Button SelectButton;
- private Button SearchButton;
- }
-}
\ No newline at end of file
diff --git a/UI/Forms/IGDBSearchResultsForm.cs b/UI/Forms/IGDBSearchResultsForm.cs
deleted file mode 100644
index 7319d44..0000000
--- a/UI/Forms/IGDBSearchResultsForm.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using IGDB.Models;
-
-namespace GameLauncher.UI.Forms
-{
- public partial class IGDBSearchResultsForm : Form
- {
- public Game? SelectedGame => this._results?.ElementAtOrDefault(this.ResultBox.SelectedIndex);
- private string _initialResult;
- private Game[]? _results;
- public IGDBSearchResultsForm(string initialResult)
- {
- this._initialResult = initialResult;
- this.DialogResult = DialogResult.Cancel;
- InitializeComponent();
- }
-
- private void IGDBSearchResultsForm_Load(object sender, EventArgs e)
- {
- this.SearchBox.Text = this._initialResult;
- this.PerformSearch();
- }
-
- private void SearchButton_Click(object? sender, EventArgs e)
- {
- PerformSearch();
- }
-
- private void PerformSearch()
- {
- this.SearchButton.Enabled = false;
- this.SelectButton.Enabled = false;
- string query = this.SearchBox.Text;
- if (query.All(char.IsNumber))
- query = $"[{query}]";
-
- Management.IGDBObj.SearchAsync(query, results =>
- {
- this._results = results;
-
- this.Invoke(() =>
- {
- this.ResultBox.BeginUpdate();
- this.ResultBox.Items.Clear();
-
- // ReSharper disable once CoVariantArrayConversion
- this.ResultBox.Items.AddRange(results.Select(x => x.Name).ToArray());
-
- this.ResultBox.EndUpdate();
-
- this.SearchButton.Enabled = true;
- this.SelectButton.Enabled = true;
- });
- }, 25);
- }
-
- private void SelectButton_Click(object? sender, EventArgs e)
- {
- this.DialogResult = DialogResult.OK;
- this.Close();
- }
-
- private void SearchBox_KeyDown(object sender, KeyEventArgs e)
- {
- if (e.KeyCode == Keys.Enter)
- PerformSearch();
- }
- }
-}
diff --git a/UI/Forms/Form1.Designer.cs b/UI/Forms/MainForm.Designer.cs
similarity index 98%
rename from UI/Forms/Form1.Designer.cs
rename to UI/Forms/MainForm.Designer.cs
index c54dda3..cf9e928 100644
--- a/UI/Forms/Form1.Designer.cs
+++ b/UI/Forms/MainForm.Designer.cs
@@ -1,6 +1,6 @@
namespace GameLauncher
{
- partial class Form1
+ partial class MainForm
{
///
/// Required designer variable.
@@ -29,7 +29,7 @@ protected override void Dispose(bool disposing)
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
- System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
flowLayoutPanel1 = new FlowLayoutPanel();
contextMenuStrip1 = new ContextMenuStrip(this.components);
addManuallyToolStripMenuItem = new ToolStripMenuItem();
@@ -109,7 +109,7 @@ private void InitializeComponent()
this.Controls.Add(flowLayoutPanel1);
this.Controls.Add(LoadingProgressBar);
this.Icon = (Icon)resources.GetObject("$this.Icon");
- this.Name = "Form1";
+ this.Name = "MainForm";
this.Text = "Game Launcher";
this.FormClosed += this.Form1_FormClosed;
this.Load += this.Form1_Load;
diff --git a/UI/Forms/Form1.cs b/UI/Forms/MainForm.cs
similarity index 88%
rename from UI/Forms/Form1.cs
rename to UI/Forms/MainForm.cs
index 9f8a370..38e677b 100644
--- a/UI/Forms/Form1.cs
+++ b/UI/Forms/MainForm.cs
@@ -8,14 +8,14 @@
namespace GameLauncher
{
- public partial class Form1 : Form
+ public partial class MainForm : Form
{
private static LocalGame[]? Games;
private static Thread? ProcessMonitorThread;
private static Thread? RichPresenceThread;
- public Form1()
+ public MainForm()
{
this.InitializeComponent();
}
@@ -183,9 +183,19 @@ public void CheckForUpdates(Action callback)
Version newVer = GitHub.GetLatestVersion();
if (newVer > Management.Version)
{
- DialogResult result = MessageBox.Show($"New version available: {newVer}", "Update", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
- if (result == DialogResult.Yes)
- GitHub.UpdateToVersion(newVer);
+ DialogResult result = MessageBox.Show($"New version is available: {newVer}\nWould you like to update?", "Update", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
+ try
+ {
+ if (result == DialogResult.Yes)
+ GitHub.UpdateToVersion(newVer);
+ }
+ catch (Exception ex)
+ {
+ string backupFile = Path.Combine(Path.GetDirectoryName(Management.ExecutablePath), "GameLauncher.exe.bak");
+ if (File.Exists(backupFile))
+ File.Move(backupFile, Management.ExecutablePath);
+ MessageBox.Show($"Failed to update: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
callback();
}
else
diff --git a/UI/Forms/Form1.resx b/UI/Forms/MainForm.resx
similarity index 100%
rename from UI/Forms/Form1.resx
rename to UI/Forms/MainForm.resx
diff --git a/UI/Forms/MetadataOverrideForm.Designer.cs b/UI/Forms/MetadataOverrideForm.Designer.cs
new file mode 100644
index 0000000..ee37eb3
--- /dev/null
+++ b/UI/Forms/MetadataOverrideForm.Designer.cs
@@ -0,0 +1,262 @@
+namespace GameLauncher.UI.Forms
+{
+ partial class MetadataOverrideForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ ResultBox = new ListBox();
+ SearchBox = new TextBox();
+ label1 = new Label();
+ SelectButton = new Button();
+ SearchButton = new Button();
+ CustomMetadataButton = new Button();
+ CustomOverridePanel = new Panel();
+ ThumnailPathLabel = new Label();
+ GenresBox = new TextBox();
+ label5 = new Label();
+ label4 = new Label();
+ label3 = new Label();
+ label2 = new Label();
+ ChooseThumbnailButton = new Button();
+ DescriptionBox = new RichTextBox();
+ NameBox = new TextBox();
+ UpdateDirNameBox = new CheckBox();
+ CustomOverridePanel.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // ResultBox
+ //
+ ResultBox.FormattingEnabled = true;
+ ResultBox.ItemHeight = 32;
+ ResultBox.Location = new Point(22, 85);
+ ResultBox.Margin = new Padding(6);
+ ResultBox.Name = "ResultBox";
+ ResultBox.Size = new Size(615, 228);
+ ResultBox.TabIndex = 0;
+ //
+ // SearchBox
+ //
+ SearchBox.Location = new Point(154, 18);
+ SearchBox.Margin = new Padding(6);
+ SearchBox.Name = "SearchBox";
+ SearchBox.Size = new Size(335, 39);
+ SearchBox.TabIndex = 1;
+ SearchBox.KeyDown += this.SearchBox_KeyDown;
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Location = new Point(15, 21);
+ label1.Margin = new Padding(6, 0, 6, 0);
+ label1.Name = "label1";
+ label1.Size = new Size(131, 32);
+ label1.TabIndex = 2;
+ label1.Text = "Term or ID:";
+ //
+ // SelectButton
+ //
+ SelectButton.Location = new Point(501, 331);
+ SelectButton.Margin = new Padding(6);
+ SelectButton.Name = "SelectButton";
+ SelectButton.Size = new Size(139, 49);
+ SelectButton.TabIndex = 3;
+ SelectButton.Text = "Select";
+ SelectButton.UseVisualStyleBackColor = true;
+ SelectButton.Click += this.SelectButton_Click;
+ //
+ // SearchButton
+ //
+ SearchButton.Location = new Point(501, 13);
+ SearchButton.Margin = new Padding(6);
+ SearchButton.Name = "SearchButton";
+ SearchButton.Size = new Size(139, 49);
+ SearchButton.TabIndex = 4;
+ SearchButton.Text = "Search";
+ SearchButton.UseVisualStyleBackColor = true;
+ SearchButton.Click += this.SearchButton_Click;
+ //
+ // CustomMetadataButton
+ //
+ CustomMetadataButton.Location = new Point(339, 332);
+ CustomMetadataButton.Name = "CustomMetadataButton";
+ CustomMetadataButton.Size = new Size(150, 46);
+ CustomMetadataButton.TabIndex = 5;
+ CustomMetadataButton.Text = "Custom";
+ CustomMetadataButton.UseVisualStyleBackColor = true;
+ CustomMetadataButton.Click += this.CustomMetadataButton_Click;
+ //
+ // CustomOverridePanel
+ //
+ CustomOverridePanel.Controls.Add(ThumnailPathLabel);
+ CustomOverridePanel.Controls.Add(GenresBox);
+ CustomOverridePanel.Controls.Add(label5);
+ CustomOverridePanel.Controls.Add(label4);
+ CustomOverridePanel.Controls.Add(label3);
+ CustomOverridePanel.Controls.Add(label2);
+ CustomOverridePanel.Controls.Add(ChooseThumbnailButton);
+ CustomOverridePanel.Controls.Add(DescriptionBox);
+ CustomOverridePanel.Controls.Add(NameBox);
+ CustomOverridePanel.Location = new Point(22, 12);
+ CustomOverridePanel.Name = "CustomOverridePanel";
+ CustomOverridePanel.Size = new Size(615, 301);
+ CustomOverridePanel.TabIndex = 6;
+ CustomOverridePanel.Visible = false;
+ //
+ // ThumnailPathLabel
+ //
+ ThumnailPathLabel.Font = new Font("Segoe UI", 5F, FontStyle.Regular, GraphicsUnit.Point);
+ ThumnailPathLabel.Location = new Point(322, 252);
+ ThumnailPathLabel.Name = "ThumnailPathLabel";
+ ThumnailPathLabel.Size = new Size(276, 32);
+ ThumnailPathLabel.TabIndex = 8;
+ ThumnailPathLabel.TextAlign = ContentAlignment.MiddleLeft;
+ //
+ // GenresBox
+ //
+ GenresBox.Location = new Point(166, 189);
+ GenresBox.Name = "GenresBox";
+ GenresBox.Size = new Size(432, 39);
+ GenresBox.TabIndex = 7;
+ //
+ // label5
+ //
+ label5.AutoSize = true;
+ label5.Location = new Point(20, 251);
+ label5.Name = "label5";
+ label5.Size = new Size(133, 32);
+ label5.TabIndex = 6;
+ label5.Text = "Thumbnail:";
+ //
+ // label4
+ //
+ label4.AutoSize = true;
+ label4.Location = new Point(20, 192);
+ label4.Name = "label4";
+ label4.Size = new Size(93, 32);
+ label4.TabIndex = 5;
+ label4.Text = "Genres:";
+ //
+ // label3
+ //
+ label3.AutoSize = true;
+ label3.Location = new Point(20, 76);
+ label3.Name = "label3";
+ label3.Size = new Size(140, 32);
+ label3.TabIndex = 4;
+ label3.Text = "Description:";
+ //
+ // label2
+ //
+ label2.AutoSize = true;
+ label2.Location = new Point(20, 20);
+ label2.Name = "label2";
+ label2.Size = new Size(90, 32);
+ label2.TabIndex = 3;
+ label2.Text = "Name: ";
+ //
+ // ChooseThumbnailButton
+ //
+ ChooseThumbnailButton.Location = new Point(166, 245);
+ ChooseThumbnailButton.Name = "ChooseThumbnailButton";
+ ChooseThumbnailButton.Size = new Size(150, 46);
+ ChooseThumbnailButton.TabIndex = 2;
+ ChooseThumbnailButton.Text = "Select";
+ ChooseThumbnailButton.UseVisualStyleBackColor = true;
+ //
+ // DescriptionBox
+ //
+ DescriptionBox.BorderStyle = BorderStyle.FixedSingle;
+ DescriptionBox.Location = new Point(166, 73);
+ DescriptionBox.Name = "DescriptionBox";
+ DescriptionBox.Size = new Size(432, 104);
+ DescriptionBox.TabIndex = 1;
+ DescriptionBox.Text = "";
+ //
+ // NameBox
+ //
+ NameBox.Location = new Point(166, 18);
+ NameBox.Name = "NameBox";
+ NameBox.Size = new Size(432, 39);
+ NameBox.TabIndex = 0;
+ //
+ // UpdateDirNameBox
+ //
+ UpdateDirNameBox.AutoSize = true;
+ UpdateDirNameBox.Location = new Point(23, 338);
+ UpdateDirNameBox.Name = "UpdateDirNameBox";
+ UpdateDirNameBox.Size = new Size(291, 36);
+ UpdateDirNameBox.TabIndex = 7;
+ UpdateDirNameBox.Text = "Update directory name";
+ UpdateDirNameBox.UseVisualStyleBackColor = true;
+ //
+ // MetadataOverrideForm
+ //
+ this.AutoScaleDimensions = new SizeF(13F, 32F);
+ this.AutoScaleMode = AutoScaleMode.Font;
+ this.ClientSize = new Size(652, 395);
+ this.Controls.Add(UpdateDirNameBox);
+ this.Controls.Add(CustomOverridePanel);
+ this.Controls.Add(CustomMetadataButton);
+ this.Controls.Add(SearchButton);
+ this.Controls.Add(SelectButton);
+ this.Controls.Add(label1);
+ this.Controls.Add(SearchBox);
+ this.Controls.Add(ResultBox);
+ this.FormBorderStyle = FormBorderStyle.FixedDialog;
+ this.Margin = new Padding(6);
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "MetadataOverrideForm";
+ this.Text = "Metadata Override";
+ this.Load += this.IGDBSearchResultsForm_Load;
+ CustomOverridePanel.ResumeLayout(false);
+ CustomOverridePanel.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+ }
+
+ #endregion
+
+ private ListBox ResultBox;
+ private TextBox SearchBox;
+ private Label label1;
+ private Button SelectButton;
+ private Button SearchButton;
+ private Button CustomMetadataButton;
+ private Panel CustomOverridePanel;
+ private Label label4;
+ private Label label3;
+ private Label label2;
+ private Button ChooseThumbnailButton;
+ private RichTextBox DescriptionBox;
+ private TextBox NameBox;
+ private TextBox GenresBox;
+ private Label label5;
+ private Label ThumnailPathLabel;
+ private CheckBox UpdateDirNameBox;
+ }
+}
\ No newline at end of file
diff --git a/UI/Forms/MetadataOverrideForm.cs b/UI/Forms/MetadataOverrideForm.cs
new file mode 100644
index 0000000..23b37a6
--- /dev/null
+++ b/UI/Forms/MetadataOverrideForm.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using GameLauncher.Connections;
+using GameLauncher.Utils;
+using IGDB.Models;
+
+namespace GameLauncher.UI.Forms
+{
+ public partial class MetadataOverrideForm : Form
+ {
+ public Game? SelectedGame => this._results?.ElementAtOrDefault(this.ResultBox.SelectedIndex);
+ private string _initialResult;
+ private Game[]? _results;
+ private bool inCustomMode => CustomOverridePanel.Visible;
+ public MetadataOverrideForm(string initialResult, LocalGame? oldGame = null)
+ {
+ this._initialResult = initialResult;
+
+ InitializeComponent();
+
+ this.NameBox.Text = initialResult;
+ this.DialogResult = DialogResult.Cancel;
+
+ if (oldGame != null)
+ {
+ this.NameBox.Text = oldGame.Name ?? initialResult;
+ this.DescriptionBox.Text = oldGame.Summary ?? "";
+ this.GenresBox.Text = oldGame.Genres ?? "";
+ this.ThumnailPathLabel.Text = oldGame.CoverUrl ?? "No cover";
+ }
+ }
+
+ private void IGDBSearchResultsForm_Load(object sender, EventArgs e)
+ {
+ this.SearchBox.Text = this._initialResult;
+ this.PerformSearch();
+ }
+
+ private void SearchButton_Click(object? sender, EventArgs e)
+ {
+ PerformSearch();
+ }
+
+ private void PerformSearch()
+ {
+ this.SearchButton.Enabled = false;
+ this.SelectButton.Enabled = false;
+ string query = this.SearchBox.Text;
+ if (query.All(char.IsNumber))
+ query = $"[{query}]";
+
+ Management.IGDBObj.SearchAsync(query, results =>
+ {
+ this._results = results;
+
+ this.Invoke(() =>
+ {
+ this.ResultBox.BeginUpdate();
+ this.ResultBox.Items.Clear();
+
+ // ReSharper disable once CoVariantArrayConversion
+ this.ResultBox.Items.AddRange(results.Select(x => x.Name).ToArray());
+
+ this.ResultBox.EndUpdate();
+
+ this.SearchButton.Enabled = true;
+ this.SelectButton.Enabled = true;
+ });
+ }, 25);
+ }
+
+ private void SelectButton_Click(object? sender, EventArgs e)
+ {
+ this.DialogResult = DialogResult.OK;
+ this.Close();
+ }
+
+ private void SearchBox_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Enter)
+ PerformSearch();
+ }
+
+ private void CustomMetadataButton_Click(object sender, EventArgs e)
+ {
+ CustomOverridePanel.Visible = !CustomOverridePanel.Visible;
+ CustomMetadataButton.Text = inCustomMode ? "IGDB Search" : "Custom";
+ }
+
+ public static bool OverrideMetadata(LocalGame game)
+ {
+ MetadataOverrideForm form = new(game.Name, game);
+ DialogResult result = form.ShowDialog();
+
+ if (result != DialogResult.OK) return false;
+
+ if (form.inCustomMode)
+ {
+ // Download image as cover.
+
+ WebClient client = new();
+ byte[] imageBytes = client.DownloadData(form.ThumnailPathLabel.Text);
+ File.WriteAllBytes(game.CoverPath, imageBytes);
+
+ game.GameMetaData = new()
+ {
+ { "name", form.NameBox.Text },
+ { "genres", form.GenresBox.Text },
+ { "summary", form.DescriptionBox.Text },
+ { "cover_url", form.ThumnailPathLabel.Text }
+ };
+
+ DatFile.Save(game.GameMetadataPath, game.GameMetaData);
+
+ if (form.UpdateDirNameBox.Checked)
+ {
+ // change folder name to match the game name.
+ string dir = Path.GetDirectoryName(game.GamePath)!;
+
+ string newGamePath = Path.Join(dir, game.Name.CleanFileName());
+ Directory.Move(game.GamePath, newGamePath);
+ game.GamePath = newGamePath;
+ }
+ }
+ else
+ {
+ Game? selectedGame = form.SelectedGame;
+ if (selectedGame == null) return false;
+
+ string dir = Path.GetDirectoryName(game.GamePath)!;
+ string name = Path.GetFileName(game.GamePath);
+ if (form.UpdateDirNameBox.Checked)
+ name = selectedGame.Name;
+
+ name = Regex.Replace(name, @"\[(\d+)\]", "");
+ name = $"{name.TrimEnd()} [{selectedGame.Id}]";
+
+ string newPath = Path.Join(dir, name.CleanFileName());
+ Directory.Move(game.GamePath, newPath);
+ game.GamePath = newPath;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/UI/Forms/IGDBSearchResultsForm.resx b/UI/Forms/MetadataOverrideForm.resx
similarity index 100%
rename from UI/Forms/IGDBSearchResultsForm.resx
rename to UI/Forms/MetadataOverrideForm.resx
diff --git a/UI/Pages/GameDetailsPage.cs b/UI/Pages/GameDetailsPage.cs
index f22d756..3ccdaea 100644
--- a/UI/Pages/GameDetailsPage.cs
+++ b/UI/Pages/GameDetailsPage.cs
@@ -16,7 +16,7 @@ namespace GameLauncher
{
public partial class GameDetailsControl : UserControl, ITick
{
- public Form1? MainForm;
+ public MainForm? MainForm;
private LocalGame game;
public GameDetailsControl(LocalGame game)
{
@@ -34,7 +34,7 @@ private void ExpandButton_Click(object sender, EventArgs e)
private void GameDetailsControl_Load(object sender, EventArgs e)
{
- this.MainForm = (this.ParentForm as Form1)!;
+ this.MainForm = (this.ParentForm as MainForm)!;
this.UpdateUIFromMetadata();
@@ -126,20 +126,8 @@ private void uninstallToolStripMenuItem_Click(object sender, EventArgs e)
private void overrideMetadataToolStripMenuItem_Click(object sender, EventArgs e)
{
- IGDBSearchResultsForm form = new(Path.GetFileName(this.game.GamePath));
- DialogResult result = form.ShowDialog();
-
- if (result == DialogResult.OK && form.SelectedGame != null)
+ if (MetadataOverrideForm.OverrideMetadata(this.game))
{
- string dir = Path.GetDirectoryName(this.game.GamePath);
- string name = Path.GetFileName(this.game.GamePath);
- name = Regex.Replace(name, @"\[(\d+)\]", "");
- name = $"{name.TrimEnd()} [{form.SelectedGame.Id}]";
-
- string newPath = Path.Join(dir, name);
- Directory.Move(this.game.GamePath, newPath);
- this.game.GamePath = newPath;
-
this.RefreshMetadata();
this.UpdateUIFromMetadata();
}
diff --git a/UI/Pages/SettingsPage.cs b/UI/Pages/SettingsPage.cs
index a634e33..5d31ba8 100644
--- a/UI/Pages/SettingsPage.cs
+++ b/UI/Pages/SettingsPage.cs
@@ -13,7 +13,7 @@ namespace GameLauncher
{
public partial class SettingsPage : UserControl
{
- public Form1? MainForm;
+ public MainForm? MainForm;
public SettingsPage()
{
this.InitializeComponent();
@@ -21,7 +21,7 @@ public SettingsPage()
private void SettingsPage_Load(object sender, EventArgs e)
{
- this.MainForm = (this.ParentForm as Form1)!;
+ this.MainForm = (this.ParentForm as MainForm)!;
Dictionary settings = new();
settings.Add("Add custom game", new Action(this.MainForm.AddGameManually));
diff --git a/Utils/Extensions.cs b/Utils/Extensions.cs
index 19f4f10..d37049f 100644
--- a/Utils/Extensions.cs
+++ b/Utils/Extensions.cs
@@ -105,5 +105,10 @@ public static Color GetColor(this LauncherTheme theme, LauncherThemeKey key)
}
};;
}
+
+ public static string CleanFileName(this string fileName)
+ {
+ return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
+ }
}
}