diff --git a/TBMM/MainForm.cs b/TBMM/MainForm.cs index f30b33a..00338e1 100644 --- a/TBMM/MainForm.cs +++ b/TBMM/MainForm.cs @@ -128,7 +128,9 @@ You may also want to verify the game's files in the launcher. { if (mod.Updatable) addText("New version available! " + mod.UpdateDetails, Color.Aqua); - if (mod.LastUpdated != default && mod.LastUpdated < lastGameUpdateTime) + if (mod.Broken) + addText("Outdated mod! It has been confirmed that the mod is broken on the current version of the game.", Color.Red); + else if (mod.LastUpdated != default && mod.LastUpdated < lastGameUpdateTime) addText("Outdated mod! It may not work properly on the current version of the game.", Color.DarkOrange); if (mod.Description != null) modinfobox.AppendText(mod.Description.Replace("\n", Environment.NewLine)); diff --git a/TBMM/MainModList.cs b/TBMM/MainModList.cs index 9f98e3c..de8a88f 100644 --- a/TBMM/MainModList.cs +++ b/TBMM/MainModList.cs @@ -66,11 +66,22 @@ namespace TBMM { var sp = line.Split('\t'); if (sp.Length < 2) continue; + DateTime updated = default; + bool broken = false; + if (sp.Length > 2) + { + if (DateTime.TryParse(sp[2].Trim(), out var updatedAt)) + updated = updatedAt; + else if (sp[2].Trim().ToLower() == "broken") + broken = true; + } + var mod = new ModInfo { Author = sp[0].Trim(), Name = sp[1].Trim(), - LastUpdated = sp.Length > 2 ? DateTime.Parse(sp[2].Trim()) : default + LastUpdated = updated, + Broken = broken }; if (await FetchModInfo(mod, preview, true)) //If it's actually a mod AddUpdateModInList(mod); @@ -191,6 +202,8 @@ namespace TBMM } if (mod.LatestVersion != null && mod.Version != null && mod.Version < mod.LatestVersion) item.ForeColor = Color.Blue; + else if(mod.Broken) + item.ForeColor = Color.Red; else if (mod.LastUpdated != default && mod.LastUpdated < lastGameUpdateTime) item.ForeColor = Color.OrangeRed; else diff --git a/TBMM/MainPatcher.cs b/TBMM/MainPatcher.cs index 7fa9ea0..21d6f7a 100644 --- a/TBMM/MainPatcher.cs +++ b/TBMM/MainPatcher.cs @@ -18,7 +18,7 @@ namespace TBMM status.Text = "Status: Game not found"; return GameState.NotFound; } - string pnp = "Patch && Play"; + string pnp = "Play modded"; if (!File.Exists(GamePath(@"\IPA.exe"))) { status.Text = "Status: Patcher missing\nClicking Play will install it"; @@ -31,8 +31,8 @@ namespace TBMM playbtn.Text = pnp; return GameState.OldPatcher; } - string nopatch = "Status: Unpatched\nClicking Play patches it"; - string gc = GetExe().Replace(".exe", ""); + string nopatch = "Status: Unpatched"; + string gc = GetExe(withExtension: false); string backups = GamePath(@"\IPA\Backups\" + gc); if (!Directory.Exists(backups)) { @@ -129,26 +129,8 @@ namespace TBMM case GameState.Unpatched: { //TODO: Wine EnsureShown(false); - var psi = new ProcessStartInfo(GamePath(@"\IPA.exe"), GetExe() + " --nowait") - { - UseShellExecute = false, - RedirectStandardError = true, - RedirectStandardOutput = true, - WorkingDirectory = Configuration.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; var (handler, task) = CheckStartGame(command); + var process = ExecutePatcher(true); process.Exited += handler; await task; } @@ -165,6 +147,30 @@ namespace TBMM return retOpenedWindowShouldStay; } + private Process ExecutePatcher(bool patch) + { + var psi = new ProcessStartInfo(GamePath(@"\IPA.exe"), $"{GetExe()} --nowait {(patch ? "" : "--revert")}") + { + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + WorkingDirectory = Configuration.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; + return process; + } + public enum GameState { NotFound, diff --git a/TBMM/MainUtils.cs b/TBMM/MainUtils.cs index d1a9f0e..61b17a7 100644 --- a/TBMM/MainUtils.cs +++ b/TBMM/MainUtils.cs @@ -73,18 +73,28 @@ namespace TBMM return; } if (CheckIfPatched() == GameState.Patched || unpatched.Checked) + { + Process process = null; if (command != null) { if (sender is Process) //Patched just now CheckCompatibilityAndDisableMods(); await CheckModUpdatesAsync(); - Process.Start(command); + process = Process.Start(command); } else if (Environment.OSVersion.Platform == PlatformID.Win32NT) - Process.Start(new ProcessStartInfo(GamePath("\\" + GetExe())) + { + process = Process.Start(new ProcessStartInfo(GamePath("\\" + GetExe())) { WorkingDirectory = GamePath("\\") //Mods are only loaded if the working directory is correct }); + } + if (process is null) + throw new NullReferenceException("Game process is null"); + process.EnableRaisingEvents = true; + process.Exited += HandleGameExit; + } + EndWork(false); tcs.SetResult(null); }; @@ -95,6 +105,20 @@ namespace TBMM }, tcs.Task); } + private void HandleGameExit(object sender, EventArgs e) + { + ExecutePatcher(false).Exited += (o, args) => + { + if (CheckIfPatched() == GameState.Patched) + { + MessageBox.Show("Failed to unpatch game, launching through the launcher will fail because of anticheat. " + + "Check the output in the panel on the right.\n\n" + + "Please try starting the game again by clicking Play.", "Patcher error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + }; + } + private void CheckCompatibilityAndDisableMods() { if (!unpatched.Checked && MessageBox.Show("If the game updated just now, some mods may be incompatible or they may work just fine." + @@ -168,12 +192,12 @@ namespace TBMM return ((gamepath ?? Configuration.GamePath) + path).Replace('\\', Path.DirectorySeparatorChar); } - public string GetExe(string path = null) + public string GetExe(string path = null, bool withExtension = true) { if (File.Exists(GamePath("\\Techblox.exe", path))) - return "Techblox.exe"; + return "Techblox" + (withExtension ? ".exe" : ""); if (File.Exists(GamePath("\\TechbloxPreview.exe", path))) - return "TechbloxPreview.exe"; + return "TechbloxPreview.exe" + (withExtension ? ".exe" : ""); return null; } @@ -196,7 +220,7 @@ namespace TBMM public DateTime GetGameVersionAsDate() { if (Configuration.GamePath == null) return default; - using var fs = File.OpenRead(GamePath("\\TechbloxPreview_Data\\globalgamemanagers")); + using var fs = File.OpenRead(GamePath($"\\{GetExe(withExtension: false)}_Data\\globalgamemanagers")); using var sr = new StreamReader(fs); char[] data = new char[512]; while(!sr.EndOfStream) diff --git a/TBMM/ModInfo.cs b/TBMM/ModInfo.cs index d1d8625..273b03c 100644 --- a/TBMM/ModInfo.cs +++ b/TBMM/ModInfo.cs @@ -31,5 +31,6 @@ namespace TBMM public HashSet ModFiles { get; set; } public string UpdateDetails { get; set; } public bool Updatable => Version != null && LatestVersion != null && Version < LatestVersion; + public bool Broken { get; set; } } }