From 675daf1935c427e0eb2e7d2a4c8f635cb4f06038 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 18 Aug 2020 20:56:19 +0200 Subject: [PATCH] Fix handling of game not found, refresh support --- GCMM/MainForm.Designer.cs | 21 ++++++- GCMM/MainForm.cs | 18 ++++-- GCMM/MainModInstaller.cs | 7 +-- GCMM/MainModList.cs | 22 ++++--- GCMM/MainPatcher.cs | 126 +++++++++++++++++++++++--------------- GCMM/MainUtils.cs | 18 +++++- 6 files changed, 144 insertions(+), 68 deletions(-) diff --git a/GCMM/MainForm.Designer.cs b/GCMM/MainForm.Designer.cs index b7d6187..bec7965 100644 --- a/GCMM/MainForm.Designer.cs +++ b/GCMM/MainForm.Designer.cs @@ -49,6 +49,7 @@ this.findlog = new System.Windows.Forms.Button(); this.unpatched = new System.Windows.Forms.CheckBox(); this.modinfobox = new System.Windows.Forms.RichTextBox(); + this.refreshbtn = new System.Windows.Forms.Button(); this.SuspendLayout(); // // modlist @@ -79,9 +80,9 @@ listViewItem1.Group = listViewGroup1; this.modlist.Items.AddRange(new System.Windows.Forms.ListViewItem[] { listViewItem1}); - this.modlist.Location = new System.Drawing.Point(12, 12); + this.modlist.Location = new System.Drawing.Point(12, 47); this.modlist.Name = "modlist"; - this.modlist.Size = new System.Drawing.Size(491, 468); + this.modlist.Size = new System.Drawing.Size(491, 433); this.modlist.TabIndex = 0; this.modlist.UseCompatibleStateImageBehavior = false; this.modlist.View = System.Windows.Forms.View.Details; @@ -220,12 +221,27 @@ this.modinfobox.TabIndex = 9; this.modinfobox.Text = ""; // + // refreshbtn + // + this.refreshbtn.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Green; + this.refreshbtn.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(40)))), ((int)(((byte)(0))))); + this.refreshbtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.refreshbtn.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); + this.refreshbtn.Location = new System.Drawing.Point(12, 12); + this.refreshbtn.Name = "refreshbtn"; + this.refreshbtn.Size = new System.Drawing.Size(81, 29); + this.refreshbtn.TabIndex = 10; + this.refreshbtn.Text = "Refresh"; + this.refreshbtn.UseVisualStyleBackColor = true; + this.refreshbtn.Click += new System.EventHandler(this.refreshbtn_Click); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Black; this.ClientSize = new System.Drawing.Size(784, 561); + this.Controls.Add(this.refreshbtn); this.Controls.Add(this.modinfobox); this.Controls.Add(this.unpatched); this.Controls.Add(this.findlog); @@ -260,6 +276,7 @@ private System.Windows.Forms.Button findlog; private System.Windows.Forms.CheckBox unpatched; private System.Windows.Forms.RichTextBox modinfobox; + private System.Windows.Forms.Button refreshbtn; } } diff --git a/GCMM/MainForm.cs b/GCMM/MainForm.cs index 791238f..1576908 100644 --- a/GCMM/MainForm.cs +++ b/GCMM/MainForm.cs @@ -72,9 +72,7 @@ You may also want to verify the game's files by right clicking the game in Steam DeleteEmptyPluginsDir(out bool pexists, out bool dexists); if (!pexists && dexists) unpatched.Checked = true; //It will call the event but that won't do anything - CheckIfPatched(); - GetInstalledMods(); - GetAvailableMods(); + refreshbtn_Click(refreshbtn, null); } private async void playbtn_Click(object sender, EventArgs e) @@ -183,12 +181,16 @@ You may also want to verify the game's files by right clicking the game in Steam { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - Process.Start("explorer.exe", $@"/select,{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}Low\Freejam\{GetExe().Replace(".exe", "")}\Player.log"); + if (CheckNoExe(out string exe)) + return; + Process.Start("explorer.exe", $@"/select,{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}Low\Freejam\{exe.Replace(".exe", "")}\Player.log"); } } private void unpatched_CheckedChanged(object sender, EventArgs e) { //Not using the patcher's revert option because sometimes it restores the wrong files - the game can be patched without mods + if (CheckNoExe()) + return; CheckIfPatched(); modlist_SelectedIndexChanged(modlist, null); string plugins = GamePath("\\Plugins"); @@ -231,5 +233,13 @@ You may also want to verify the game's files by right clicking the game in Steam dexists = false; } } + + private void refreshbtn_Click(object sender, EventArgs e) + { + CheckIfPatched(); + var mods = GetInstalledMods(); + GetAvailableMods(); + CheckUninstalledMods(mods); + } } } diff --git a/GCMM/MainModInstaller.cs b/GCMM/MainModInstaller.cs index 9e401df..949c074 100644 --- a/GCMM/MainModInstaller.cs +++ b/GCMM/MainModInstaller.cs @@ -16,11 +16,8 @@ namespace GCMM public async Task InstallMod(ModInfo mod) { if (mod.DownloadURL == null) return; - if (GetExe() == null) - { - MessageBox.Show("Gamecraft not found. Set the correct path in Settings."); + if (CheckNoExe()) return; - } if (mod.Name != "GamecraftModdingAPI") await UpdateAPI(); var tmp = Directory.CreateDirectory("temp"); @@ -140,6 +137,8 @@ namespace GCMM public async Task UpdateAPI() { + if (!mods.ContainsKey("GamecraftModdingAPI")) + return; var gcmapi = mods["GamecraftModdingAPI"]; if (!gcmapi.Installed || gcmapi.Updatable) { diff --git a/GCMM/MainModList.cs b/GCMM/MainModList.cs index aaf931d..4cd7fca 100644 --- a/GCMM/MainModList.cs +++ b/GCMM/MainModList.cs @@ -17,13 +17,14 @@ namespace GCMM partial class MainForm { - public void GetInstalledMods() + public HashSet GetInstalledMods() { bool disabled = false; if (!Directory.Exists(GamePath("\\Plugins"))) if (Directory.Exists(GamePath("\\Plugins_Disabled"))) disabled = true; - else return; + else return new HashSet(); + var installed = new HashSet(); foreach (var modPath in Directory.GetFiles(GamePath(disabled ? @"\Plugins_Disabled" : @"\Plugins"), "*.dll")) { try @@ -31,12 +32,15 @@ namespace GCMM var an = AssemblyName.GetAssemblyName(modPath); if (an.Name == "0Harmony") continue; //Use filename to avoid differences between repository & assembly name casing - AddUpdateModInList(new ModInfo { Name = Path.GetFileNameWithoutExtension(modPath), Version = an.Version, LastUpdated = File.GetLastWriteTime(modPath) }); + var mod = new ModInfo { Name = Path.GetFileNameWithoutExtension(modPath), Version = an.Version, LastUpdated = File.GetLastWriteTime(modPath) }; + AddUpdateModInList(mod); + installed.Add(mod.Name); } catch (BadImageFormatException) { //Not a .NET assembly } } + return installed; } public async void GetAvailableMods() @@ -127,7 +131,7 @@ namespace GCMM item = modlist.Items[mod.Name]; var items = item.SubItems; omod.Author = mod.Author ?? omod.Author; - omod.Version = mod.Version ?? omod.Version; + omod.Version = mod.Version ?? omod.Version; //If the object comes from the dictionary then it's directly modified (uninstall) omod.LatestVersion = mod.LatestVersion ?? omod.LatestVersion; omod.LastUpdated = mod.LastUpdated == default ? omod.LastUpdated : mod.LastUpdated; omod.Description = mod.Description ?? omod.Description; @@ -152,10 +156,14 @@ namespace GCMM item.ForeColor = modlist.ForeColor; } - public void RemoveModFromList(ModInfo mod) + public void CheckUninstalledMods(HashSet installed) { - if (mods.Remove(mod.Name)) - modlist.Items.RemoveByKey(mod.Name); + foreach (string name in mods.Keys.Except(installed)) + { + var mod = mods[name]; + mod.Version = null; + AddUpdateModInList(mod); + } } } } diff --git a/GCMM/MainPatcher.cs b/GCMM/MainPatcher.cs index f8a6b79..af7955c 100644 --- a/GCMM/MainPatcher.cs +++ b/GCMM/MainPatcher.cs @@ -15,14 +15,19 @@ namespace GCMM { partial class MainForm { - public bool? CheckIfPatched() + public GameState CheckIfPatched() { + if (GetExe() == null) + { + status.Text = "Status: Game not found"; + return GameState.NotFound; + } string pnp = "Patch && Play"; if (!File.Exists(GamePath(@"\IPA.exe"))) { status.Text = "Status: Patcher missing\nClicking Play will install it"; playbtn.Text = pnp; - return null; + return GameState.NoPatcher; } string nopatch = "Status: Unpatched\nClicking Play patches it"; string gc = GetExe().Replace(".exe", ""); @@ -31,14 +36,14 @@ namespace GCMM { status.Text = nopatch; playbtn.Text = pnp; - return false; + return GameState.Unpatched; } string backup = Directory.EnumerateDirectories(backups).OrderByDescending(s => s).FirstOrDefault(); if (backup == null) { status.Text = nopatch; playbtn.Text = pnp; - return false; + return GameState.Unpatched; } if (File.GetLastWriteTime(GamePath($@"\{gc}_Data\Managed\Assembly-CSharp.dll")) > //If the file was updated at least 2 minutes after patching @@ -46,11 +51,11 @@ namespace GCMM { status.Text = nopatch; playbtn.Text = pnp; - return false; + return GameState.Unpatched; } status.Text = "Status: " + (unpatched.Checked ? "Mods disabled" : "Patched"); playbtn.Text = "Play" + (unpatched.Checked ? " unmodded" : ""); - return true; + return GameState.Patched; } public async Task PatchStartGame() @@ -58,55 +63,76 @@ namespace GCMM if (!BeginWork()) return; foreach (ListViewItem item in modlist.SelectedItems) item.Selected = false; - if (!CheckIfPatched().HasValue) + var status = CheckIfPatched(); + switch (status) { - if (MessageBox.Show("The patcher (GCIPA) is not found. It's necessary to load the mods. It will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game. You can unpatch to run without mods at any time.", "Patcher download needed", MessageBoxButtons.OKCancel) - == DialogResult.Cancel) - { - EndWork(); + case GameState.NotFound: + MessageBox.Show("Gamecraft not found! Set the correct path in Settings."); + EndWork(false); return; - } - string releases = "/api/v1/repos/modtainers/GCIPA/releases"; - string url; - this.status.Text = "Status: Patching..."; - using (WebClient client = GetClient()) - { - url = JArray.Parse(await client.DownloadStringTaskAsync(releases)).First["assets"].First["browser_download_url"].ToString(); - await client.DownloadFileTaskAsync(url, "IPA.zip"); - ZipFile.ExtractToDirectory("IPA.zip", Settings.Default.GamePath); - } + case GameState.NoPatcher: + { + if (MessageBox.Show("The patcher (GCIPA) is not found. It's necessary to load the mods. It will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game. You can unpatch to run without mods at any time.", "Patcher download needed", MessageBoxButtons.OKCancel) + == DialogResult.Cancel) + { + EndWork(); + return; + } + string releases = "/api/v1/repos/modtainers/GCIPA/releases"; + string url; + this.status.Text = "Status: Patching..."; + using (WebClient client = GetClient()) + { + url = JArray.Parse(await client.DownloadStringTaskAsync(releases)).First["assets"].First["browser_download_url"].ToString(); + await client.DownloadFileTaskAsync(url, "IPA.zip"); + ZipFile.ExtractToDirectory("IPA.zip", Settings.Default.GamePath); + } + } + break; } - bool? status = CheckIfPatched(); - if (!status.HasValue) //Make sure it actually worked + if (status != GameState.NotFound && status != GameState.NoPatcher) + status = CheckIfPatched(); + switch (status) { - EndWork(false); - return; - } - if (!status.Value) - { //TODO: Wine - var psi = new ProcessStartInfo(GamePath(@"\IPA.exe"), GetExe() + " --nowait") - { - UseShellExecute = false, - RedirectStandardError = true, - RedirectStandardOutput = true, - WorkingDirectory = Settings.Default.GamePath, - CreateNoWindow = true - }; - var process = Process.Start(psi); - process.BeginErrorReadLine(); - process.BeginOutputReadLine(); - process.EnableRaisingEvents = true; - modinfobox.Text = ""; - DataReceivedEventHandler onoutput = (sender, e) => - { - Invoke((Action)(() => modinfobox.Text += e.Data + Environment.NewLine)); - }; - process.OutputDataReceived += onoutput; - process.ErrorDataReceived += onoutput; - process.Exited += CheckStartGame; + case GameState.NoPatcher: //Make sure it actually worked + EndWork(false); + return; + case GameState.Unpatched: + { //TODO: Wine + var psi = new ProcessStartInfo(GamePath(@"\IPA.exe"), GetExe() + " --nowait") + { + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + WorkingDirectory = Settings.Default.GamePath, + CreateNoWindow = true + }; + var process = Process.Start(psi); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + process.EnableRaisingEvents = true; + modinfobox.Text = ""; + DataReceivedEventHandler onoutput = (sender, e) => + { + Invoke((Action)(() => modinfobox.Text += e.Data + Environment.NewLine)); + }; + process.OutputDataReceived += onoutput; + process.ErrorDataReceived += onoutput; + process.Exited += CheckStartGame; + } + break; + case GameState.Patched: + CheckStartGame(null, null); + break; } - else - CheckStartGame(null, null); + } + + public enum GameState + { + NotFound, + NoPatcher, + Unpatched, + Patched } } } diff --git a/GCMM/MainUtils.cs b/GCMM/MainUtils.cs index 45b300e..661227a 100644 --- a/GCMM/MainUtils.cs +++ b/GCMM/MainUtils.cs @@ -76,7 +76,7 @@ namespace GCMM status.Text = "Status: Patching failed"; return; } - if ((CheckIfPatched() ?? false) || unpatched.Checked) + if (CheckIfPatched() == GameState.Patched || unpatched.Checked) if (Environment.OSVersion.Platform == PlatformID.Win32NT) Process.Start("steam://run/1078000/"); else @@ -144,5 +144,21 @@ namespace GCMM return "GamecraftPreview.exe"; return null; } + + private bool CheckNoExe() + { + return CheckNoExe(out _); + } + + private bool CheckNoExe(out string path) + { + path = GetExe(); + if (path == null) + { + MessageBox.Show("Gamecraft not found! Set the correct path in Settings."); + return true; + } + return false; + } } }