using GCMM.Properties; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO.Compression; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Reflection; namespace GCMM { partial class MainForm { 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 GameState.NoPatcher; } if (gcipa.Updatable && !(gcipa.Version == new Version(1, 0, 0, 0) && gcipa.LatestVersion == new Version(4, 0, 0, 0))) { status.Text = "Status: Patcher outdated\nClicking play will update it"; playbtn.Text = pnp; return GameState.OldPatcher; } string nopatch = "Status: Unpatched\nClicking Play patches it"; string gc = GetExe().Replace(".exe", ""); string backups = GamePath(@"\IPA\Backups\" + gc); if (!Directory.Exists(backups)) { status.Text = nopatch; playbtn.Text = pnp; return GameState.Unpatched; } string backup = Directory.EnumerateDirectories(backups).OrderByDescending(name => Directory.GetLastWriteTimeUtc(name)).FirstOrDefault(); if (backup == null) { status.Text = nopatch; playbtn.Text = pnp; return GameState.Unpatched; } if (File.GetLastWriteTime(GamePath($@"\{gc}_Data\Managed\Assembly-CSharp.dll")) > //If the file was updated at least 2 minutes after patching Directory.GetLastWriteTime(backup).AddMinutes(2) || !File.Exists(GamePath($@"\{gc}_Data\Managed\IllusionInjector.dll"))) { status.Text = nopatch; playbtn.Text = pnp; return GameState.Unpatched; } status.Text = "Status: " + (unpatched.Checked ? "Mods disabled" : "Patched"); playbtn.Text = "Play" + (unpatched.Checked ? " unmodded" : ""); return GameState.Patched; } public async Task PatchStartGame() { if (!BeginWork()) return; foreach (ListViewItem item in modlist.SelectedItems) item.Selected = false; var status = CheckIfPatched(); switch (status) { case GameState.NotFound: MessageBox.Show("Gamecraft not found! Set the correct path in Settings."); EndWork(false); return; case GameState.NoPatcher: case GameState.OldPatcher: { if (MessageBox.Show((status == GameState.NoPatcher ? "The patcher (GCIPA) is not found. It's necessary to load the mods." : "There is a patcher update available!" ) + "\n\nIt will be downloaded from https://git.exmods.org/modtainers/GCIPA/releases and ran to patch the game. You can validate the game to restore the original game files or simply disable mods at any time.", "Patcher download needed", MessageBoxButtons.OKCancel) == DialogResult.Cancel) { EndWork(); return; } this.status.Text = "Status: Patching..."; using (WebClient client = GetClient()) { string url = gcipa.DownloadURL; await client.DownloadFileTaskAsync(url, "IPA.zip"); using (var fs = new FileStream("IPA.zip", FileMode.Open)) using (var za = new ZipArchive(fs)) za.ExtractToDirectory(Settings.Default.GamePath, true); //Overwrite files that were left from a previous install of the patcher } } GetInstalledMods(); //Update patcher state, should be fine for this rare event status = CheckIfPatched(); break; } switch (status) { case GameState.NoPatcher: //Make sure it actually worked case GameState.OldPatcher: 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; } } public enum GameState { NotFound, NoPatcher, OldPatcher, Unpatched, Patched } } }