Remove unpatched checkbox and handle the game's running status

- Disabling mod installs while the game is running
- Automatically detecting whether the game is running and unpatching if needed
This commit is contained in:
Norbi Peti 2022-02-20 22:53:19 +01:00
parent ae89291c55
commit 333e8d6040
4 changed files with 103 additions and 107 deletions

View file

@ -43,7 +43,6 @@
this.playbtn = new System.Windows.Forms.Button(); this.playbtn = new System.Windows.Forms.Button();
this.settingsbtn = new System.Windows.Forms.Button(); this.settingsbtn = new System.Windows.Forms.Button();
this.findlog = new System.Windows.Forms.Button(); this.findlog = new System.Windows.Forms.Button();
this.unpatched = new System.Windows.Forms.CheckBox();
this.modinfobox = new System.Windows.Forms.RichTextBox(); this.modinfobox = new System.Windows.Forms.RichTextBox();
this.refreshbtn = new System.Windows.Forms.Button(); this.refreshbtn = new System.Windows.Forms.Button();
this.SuspendLayout(); this.SuspendLayout();
@ -183,18 +182,6 @@
this.findlog.UseVisualStyleBackColor = true; this.findlog.UseVisualStyleBackColor = true;
this.findlog.Click += new System.EventHandler(this.findlog_Click); this.findlog.Click += new System.EventHandler(this.findlog_Click);
// //
// unpatched
//
this.unpatched.Anchor = ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.unpatched.AutoSize = true;
this.unpatched.Location = new System.Drawing.Point(12, 534);
this.unpatched.Name = "unpatched";
this.unpatched.Size = new System.Drawing.Size(218, 17);
this.unpatched.TabIndex = 8;
this.unpatched.Text = "Disable mods (check if game is crashing)";
this.unpatched.UseVisualStyleBackColor = true;
this.unpatched.CheckedChanged += new System.EventHandler(this.unpatched_CheckedChanged);
//
// modinfobox // modinfobox
// //
this.modinfobox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); this.modinfobox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right)));
@ -230,7 +217,6 @@
this.ClientSize = new System.Drawing.Size(784, 561); this.ClientSize = new System.Drawing.Size(784, 561);
this.Controls.Add(this.refreshbtn); this.Controls.Add(this.refreshbtn);
this.Controls.Add(this.modinfobox); this.Controls.Add(this.modinfobox);
this.Controls.Add(this.unpatched);
this.Controls.Add(this.findlog); this.Controls.Add(this.findlog);
this.Controls.Add(this.settingsbtn); this.Controls.Add(this.settingsbtn);
this.Controls.Add(this.playbtn); this.Controls.Add(this.playbtn);
@ -261,7 +247,6 @@
private System.Windows.Forms.Button settingsbtn; private System.Windows.Forms.Button settingsbtn;
private System.Windows.Forms.ColumnHeader modAuthor; private System.Windows.Forms.ColumnHeader modAuthor;
private System.Windows.Forms.Button findlog; private System.Windows.Forms.Button findlog;
private System.Windows.Forms.CheckBox unpatched;
private System.Windows.Forms.RichTextBox modinfobox; private System.Windows.Forms.RichTextBox modinfobox;
private System.Windows.Forms.Button refreshbtn; private System.Windows.Forms.Button refreshbtn;
} }

View file

@ -75,9 +75,7 @@ You may also want to verify the game's files in the launcher.
status.Text = resources.GetString("Status_Game_not_found"); status.Text = resources.GetString("Status_Game_not_found");
return; return;
} }
DeleteEmptyPluginsDir(out bool pexists, out bool dexists); DeleteEmptyPluginsDir(out _, out _);
if (!pexists && dexists)
unpatched.Checked = true; //It will call the event but that won't do anything
await RefreshEverything(evenMods); await RefreshEverything(evenMods);
} }
@ -156,14 +154,6 @@ You may also want to verify the game's files in the launcher.
installbtn.Text = "Install mod"; installbtn.Text = "Install mod";
break; break;
} }
if (unpatched.Checked)
{ //Don't allow (un)installing mods if mods are disabled
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
modlist.Enabled = false;
}
else
modlist.Enabled = true;
} }
private async void installbtn_Click(object sender, EventArgs e) private async void installbtn_Click(object sender, EventArgs e)
@ -176,7 +166,7 @@ You may also want to verify the game's files in the launcher.
if (item.Group.Name == "installed" && (mod.DownloadURL == null || mod.LatestVersion <= mod.Version)) continue; if (item.Group.Name == "installed" && (mod.DownloadURL == null || mod.LatestVersion <= mod.Version)) continue;
await InstallMod(mod); await InstallMod(mod);
} }
EndWork(); EndWork(CheckIfPatched());
} }
private void uninstallbtn_Click(object sender, EventArgs e) private void uninstallbtn_Click(object sender, EventArgs e)
@ -187,7 +177,7 @@ You may also want to verify the game's files in the launcher.
if (item.Group.Name != "installed") continue; if (item.Group.Name != "installed") continue;
UninstallMod(mods[item.Name]); UninstallMod(mods[item.Name]);
} }
EndWork(); //Update button states EndWork(CheckIfPatched()); //Update button states
} }
private void findlog_Click(object sender, EventArgs e) private void findlog_Click(object sender, EventArgs e)
@ -200,35 +190,6 @@ You may also want to verify the game's files in the launcher.
} }
} }
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");
string disabled = GamePath("\\Plugins_Disabled");
DeleteEmptyPluginsDir(out bool pexists, out bool dexists);
if (unpatched.Checked)
{
if (pexists)
{
if (dexists)
Directory.Delete(disabled, true); //Resolving conflicts would be complicated so delete the other mods - this shouldn't happen normally
Directory.Move(plugins, disabled);
}
}
else
{
if (dexists)
{
if (pexists)
Directory.Delete(plugins, true);
Directory.Move(disabled, plugins);
}
}
}
private void DeleteEmptyPluginsDir(out bool pexists, out bool dexists) private void DeleteEmptyPluginsDir(out bool pexists, out bool dexists)
{ {
string plugins = GamePath("\\Plugins"); string plugins = GamePath("\\Plugins");
@ -254,7 +215,8 @@ You may also want to verify the game's files in the launcher.
private async Task RefreshEverything(bool evenMods) private async Task RefreshEverything(bool evenMods)
{ {
CheckIfPatched(); //Set from placeholder if (CheckIfPatched() == GameState.Patched) //Set from placeholder
HandleGameExit(null, EventArgs.Empty);
lastGameUpdateTime = GetGameVersionAsDate(); lastGameUpdateTime = GetGameVersionAsDate();
var mods = GetInstalledMods(); var mods = GetInstalledMods();
if (evenMods) if (evenMods)

View file

@ -25,6 +25,20 @@ namespace TBMM
playbtn.Text = pnp; playbtn.Text = pnp;
return GameState.NoPatcher; return GameState.NoPatcher;
} }
if (CheckIfGameIsRunning())
{
status.Text = "Status: Game is running";
playbtn.Text = "In-game";
UpdateButton(playbtn, false); //Don't allow (un)installing mods if game is running
UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false);
modlist.Enabled = false;
return GameState.InGame;
}
if (!working) UpdateButton(playbtn, true);
modlist.Enabled = true;
if (gcipa.Updatable && !(gcipa.Version == new Version(1, 0, 0, 0) && gcipa.LatestVersion == new Version(4, 0, 0, 0))) 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"; status.Text = "Status: Patcher outdated\nClicking play will update it";
@ -40,7 +54,7 @@ namespace TBMM
playbtn.Text = pnp; playbtn.Text = pnp;
return GameState.Unpatched; return GameState.Unpatched;
} }
string backup = Directory.EnumerateDirectories(backups).OrderByDescending(name => Directory.GetLastWriteTimeUtc(name)).FirstOrDefault(); string backup = Directory.EnumerateDirectories(backups).OrderByDescending(Directory.GetLastWriteTimeUtc).FirstOrDefault();
if (backup == null) if (backup == null)
{ {
status.Text = nopatch; status.Text = nopatch;
@ -56,8 +70,9 @@ namespace TBMM
playbtn.Text = pnp; playbtn.Text = pnp;
return GameState.Unpatched; return GameState.Unpatched;
} }
status.Text = "Status: " + (unpatched.Checked ? "Mods disabled" : "Patched");
playbtn.Text = "Play" + (unpatched.Checked ? " unmodded" : ""); status.Text = "Status: Patched";
playbtn.Text = "Play";
return GameState.Patched; return GameState.Patched;
} }
@ -82,7 +97,7 @@ namespace TBMM
{ {
case GameState.NotFound: case GameState.NotFound:
MessageBox.Show("Techblox not found! Set the correct path in Settings."); MessageBox.Show("Techblox not found! Set the correct path in Settings.");
EndWork(false); EndWork(status, false);
return retOpenedWindowShouldStay; return retOpenedWindowShouldStay;
case GameState.NoPatcher: case GameState.NoPatcher:
case GameState.OldPatcher: case GameState.OldPatcher:
@ -94,7 +109,7 @@ namespace TBMM
) + "\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.", ) + "\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) "Patcher download needed", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
{ {
EndWork(); EndWork(status);
return retOpenedWindowShouldStay; return retOpenedWindowShouldStay;
} }
this.status.Text = "Status: Patching..."; this.status.Text = "Status: Patching...";
@ -124,7 +139,7 @@ namespace TBMM
{ {
case GameState.NoPatcher: //Make sure it actually worked case GameState.NoPatcher: //Make sure it actually worked
case GameState.OldPatcher: case GameState.OldPatcher:
EndWork(false); EndWork(status, false);
return retOpenedWindowShouldStay; return retOpenedWindowShouldStay;
case GameState.Unpatched: case GameState.Unpatched:
{ //TODO: Wine { //TODO: Wine
@ -177,7 +192,11 @@ namespace TBMM
NoPatcher, NoPatcher,
OldPatcher, OldPatcher,
Unpatched, Unpatched,
Patched Patched,
/// <summary>
/// Doesn't matter if patched, don't do anything if the game is running
/// </summary>
InGame
} }
} }
} }

View file

@ -72,13 +72,13 @@ namespace TBMM
status.Text = "Status: Patching failed"; status.Text = "Status: Patching failed";
return; return;
} }
if (CheckIfPatched() == GameState.Patched || unpatched.Checked)
var patched = CheckIfPatched();
if (patched == GameState.Patched)
{ {
Process process = null; Process process = null;
if (command != null) if (command != null)
{ {
if (sender is Process) //Patched just now
CheckCompatibilityAndDisableMods();
await CheckModUpdatesAsync(); await CheckModUpdatesAsync();
process = Process.Start(command); process = Process.Start(command);
} }
@ -93,9 +93,11 @@ namespace TBMM
throw new NullReferenceException("Game process is null"); throw new NullReferenceException("Game process is null");
process.EnableRaisingEvents = true; process.EnableRaisingEvents = true;
process.Exited += HandleGameExit; process.Exited += HandleGameExit;
_gameProcess = process;
patched = CheckIfPatched(); // Set in-game status
} }
EndWork(false); EndWork(patched, false);
tcs.SetResult(null); tcs.SetResult(null);
}; };
if (InvokeRequired) if (InvokeRequired)
@ -107,9 +109,12 @@ namespace TBMM
private void HandleGameExit(object sender, EventArgs e) private void HandleGameExit(object sender, EventArgs e)
{ {
ExecutePatcher(false).Exited += (o, args) => _gameProcess = null;
if (InvokeMethod(CheckIfPatched) != GameState.Patched)
return;
InvokeMethod(() => ExecutePatcher(false)).Exited += (o, args) =>
{ {
if (CheckIfPatched() == GameState.Patched) if (InvokeMethod(CheckIfPatched) == GameState.Patched)
{ {
MessageBox.Show("Failed to unpatch game, launching through the launcher will fail because of anticheat. " + 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" + "Check the output in the panel on the right.\n\n" +
@ -119,15 +124,33 @@ namespace TBMM
}; };
} }
private void CheckCompatibilityAndDisableMods() private Process _gameProcess;
private bool CheckIfGameIsRunning()
{ {
if (!unpatched.Checked && MessageBox.Show("If the game updated just now, some mods may be incompatible or they may work just fine." + switch (_gameProcess)
" Do you want to try running with mods?" + {
"\n\nClick Yes to start the game with mods (after a small update or if you just installed TBMM)" + case { HasExited: false }:
"\nClick No to disable mods before starting the game (after a major update)" + return true;
"\n\nYou can always enable/disable mods by launching TBMM.", case { HasExited: true }:
"Possible incompatibility warning", MessageBoxButtons.YesNo) == DialogResult.No) MessageBox.Show("Game has exited without handling... Please report.");
unpatched.Checked = true; HandleGameExit(null, EventArgs.Empty);
return false;
default:
_gameProcess = Process.GetProcessesByName(GetExe(withExtension: false)).FirstOrDefault();
if (_gameProcess == null) return false;
if (_gameProcess.HasExited)
{
HandleGameExit(null, EventArgs.Empty);
return false;
}
else
{
_gameProcess.Exited += HandleGameExit;
_gameProcess.EnableRaisingEvents = true;
return true;
}
}
} }
private async Task CheckModUpdatesAsync() private async Task CheckModUpdatesAsync()
@ -154,6 +177,14 @@ namespace TBMM
return client; return client;
} }
public T InvokeMethod<T>(Func<T> func)
{
if (InvokeRequired)
return (T)Invoke(func);
else
return func();
}
private bool working = false; private bool working = false;
/// <summary> /// <summary>
/// Some simple "locking", only allow one operation at a time /// Some simple "locking", only allow one operation at a time
@ -167,18 +198,17 @@ namespace TBMM
UpdateButton(installbtn, false); UpdateButton(installbtn, false);
UpdateButton(uninstallbtn, false); UpdateButton(uninstallbtn, false);
UpdateButton(settingsbtn, false); UpdateButton(settingsbtn, false);
unpatched.Enabled = false;
return true; return true;
} }
public void EndWork(bool desc = true) public void EndWork(GameState state, bool desc = true)
{ {
working = false; working = false;
if (state != GameState.InGame)
UpdateButton(playbtn, true); UpdateButton(playbtn, true);
UpdateButton(settingsbtn, true); UpdateButton(settingsbtn, true);
if (desc) if (desc)
modlist_SelectedIndexChanged(modlist, null); modlist_SelectedIndexChanged(modlist, null);
unpatched.Enabled = true;
} }
/// <summary> /// <summary>
@ -197,7 +227,7 @@ namespace TBMM
if (File.Exists(GamePath("\\Techblox.exe", path))) if (File.Exists(GamePath("\\Techblox.exe", path)))
return "Techblox" + (withExtension ? ".exe" : ""); return "Techblox" + (withExtension ? ".exe" : "");
if (File.Exists(GamePath("\\TechbloxPreview.exe", path))) if (File.Exists(GamePath("\\TechbloxPreview.exe", path)))
return "TechbloxPreview.exe" + (withExtension ? ".exe" : ""); return "TechbloxPreview" + (withExtension ? ".exe" : "");
return null; return null;
} }