173 lines
7.4 KiB
C#
173 lines
7.4 KiB
C#
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<bool?> PatchStartGame(string command = null)
|
|
{
|
|
if (!BeginWork()) return false;
|
|
foreach (ListViewItem item in modlist.SelectedItems)
|
|
item.Selected = false;
|
|
bool? retOpenedWindowShouldStay = null;
|
|
void EnsureShown(bool stay)
|
|
{
|
|
if (!Visible)
|
|
{
|
|
Show();
|
|
retOpenedWindowShouldStay = stay;
|
|
TopMost = true; //It opens in the background otherwise - should be fine since it only shows for a couple seconds
|
|
}
|
|
}
|
|
var status = CheckIfPatched();
|
|
switch (status)
|
|
{
|
|
case GameState.NotFound:
|
|
MessageBox.Show("Gamecraft not found! Set the correct path in Settings.");
|
|
EndWork(false);
|
|
return retOpenedWindowShouldStay;
|
|
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 retOpenedWindowShouldStay;
|
|
}
|
|
this.status.Text = "Status: Patching...";
|
|
EnsureShown(false);
|
|
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
|
|
File.Delete("IPA.zip");
|
|
}
|
|
}
|
|
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 retOpenedWindowShouldStay;
|
|
case GameState.Unpatched:
|
|
{ //TODO: Wine
|
|
EnsureShown(false);
|
|
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;
|
|
var (handler, task) = CheckStartGame(command);
|
|
process.Exited += handler;
|
|
await task;
|
|
}
|
|
break;
|
|
case GameState.Patched:
|
|
{
|
|
//CheckStartGame(command)(null, null);
|
|
var (handler, task) = CheckStartGame(command);
|
|
handler(null, null);
|
|
await task;
|
|
}
|
|
break;
|
|
}
|
|
return retOpenedWindowShouldStay;
|
|
}
|
|
|
|
public enum GameState
|
|
{
|
|
NotFound,
|
|
NoPatcher,
|
|
OldPatcher,
|
|
Unpatched,
|
|
Patched
|
|
}
|
|
}
|
|
}
|