2020-06-16 17:22:29 +00:00
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 ;
2020-08-23 21:38:10 +00:00
using System.Reflection ;
2020-06-16 17:22:29 +00:00
namespace GCMM
{
partial class MainForm
{
2020-08-18 18:56:19 +00:00
public GameState CheckIfPatched ( )
2020-06-16 17:22:29 +00:00
{
2020-08-18 18:56:19 +00:00
if ( GetExe ( ) = = null )
{
status . Text = "Status: Game not found" ;
return GameState . NotFound ;
}
2020-08-18 14:02:57 +00:00
string pnp = "Patch && Play" ;
2020-07-03 00:00:08 +00:00
if ( ! File . Exists ( GamePath ( @"\IPA.exe" ) ) )
2020-06-16 17:22:29 +00:00
{
status . Text = "Status: Patcher missing\nClicking Play will install it" ;
2020-07-18 20:25:52 +00:00
playbtn . Text = pnp ;
2020-08-18 18:56:19 +00:00
return GameState . NoPatcher ;
2020-06-16 17:22:29 +00:00
}
2020-10-03 11:32:53 +00:00
if ( gcipa . Updatable & & ! ( gcipa . Version = = new Version ( 1 , 0 , 0 , 0 ) & & gcipa . LatestVersion = = new Version ( 4 , 0 , 0 , 0 ) ) )
2020-08-23 21:38:10 +00:00
{
status . Text = "Status: Patcher outdated\nClicking play will update it" ;
playbtn . Text = pnp ;
return GameState . OldPatcher ;
2020-10-03 11:32:53 +00:00
}
2020-08-18 14:02:57 +00:00
string nopatch = "Status: Unpatched\nClicking Play patches it" ;
2020-07-18 20:25:52 +00:00
string gc = GetExe ( ) . Replace ( ".exe" , "" ) ;
string backups = GamePath ( @"\IPA\Backups\" + gc ) ;
2020-07-03 00:00:08 +00:00
if ( ! Directory . Exists ( backups ) )
2020-06-16 17:22:29 +00:00
{
status . Text = nopatch ;
2020-07-18 20:25:52 +00:00
playbtn . Text = pnp ;
2020-08-18 18:56:19 +00:00
return GameState . Unpatched ;
2020-06-16 17:22:29 +00:00
}
2020-08-18 22:32:39 +00:00
string backup = Directory . EnumerateDirectories ( backups ) . OrderByDescending ( name = > Directory . GetLastWriteTimeUtc ( name ) ) . FirstOrDefault ( ) ;
2020-06-16 17:22:29 +00:00
if ( backup = = null )
{
status . Text = nopatch ;
2020-07-18 20:25:52 +00:00
playbtn . Text = pnp ;
2020-08-18 18:56:19 +00:00
return GameState . Unpatched ;
2020-06-16 17:22:29 +00:00
}
2020-07-18 20:25:52 +00:00
if ( File . GetLastWriteTime ( GamePath ( $@"\{gc}_Data\Managed\Assembly-CSharp.dll" ) )
2020-06-16 17:22:29 +00:00
> //If the file was updated at least 2 minutes after patching
2020-10-03 11:32:53 +00:00
Directory . GetLastWriteTime ( backup ) . AddMinutes ( 2 )
| | ! File . Exists ( GamePath ( $@"\{gc}_Data\Managed\IllusionInjector.dll" ) ) )
2020-06-16 17:22:29 +00:00
{
status . Text = nopatch ;
2020-07-18 20:25:52 +00:00
playbtn . Text = pnp ;
2020-08-18 18:56:19 +00:00
return GameState . Unpatched ;
2020-06-16 17:22:29 +00:00
}
2020-08-18 14:02:57 +00:00
status . Text = "Status: " + ( unpatched . Checked ? "Mods disabled" : "Patched" ) ;
playbtn . Text = "Play" + ( unpatched . Checked ? " unmodded" : "" ) ;
2020-08-18 18:56:19 +00:00
return GameState . Patched ;
2020-06-16 17:22:29 +00:00
}
2020-06-18 16:28:07 +00:00
public async Task PatchStartGame ( )
2020-06-16 17:22:29 +00:00
{
2020-06-18 16:28:07 +00:00
if ( ! BeginWork ( ) ) return ;
foreach ( ListViewItem item in modlist . SelectedItems )
item . Selected = false ;
2020-08-18 18:56:19 +00:00
var status = CheckIfPatched ( ) ;
switch ( status )
2020-06-16 17:22:29 +00:00
{
2020-08-18 18:56:19 +00:00
case GameState . NotFound :
MessageBox . Show ( "Gamecraft not found! Set the correct path in Settings." ) ;
EndWork ( false ) ;
2020-06-16 17:22:29 +00:00
return ;
2020-08-18 18:56:19 +00:00
case GameState . NoPatcher :
2020-08-23 21:38:10 +00:00
case GameState . OldPatcher :
2020-08-18 18:56:19 +00:00
{
2020-08-23 21:38:10 +00:00
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 )
2020-08-18 18:56:19 +00:00
{
EndWork ( ) ;
return ;
}
this . status . Text = "Status: Patching..." ;
using ( WebClient client = GetClient ( ) )
{
2020-08-23 21:38:10 +00:00
string url = gcipa . DownloadURL ;
2020-08-18 18:56:19 +00:00
await client . DownloadFileTaskAsync ( url , "IPA.zip" ) ;
2020-08-18 22:32:39 +00:00
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
2020-10-03 23:08:19 +00:00
File . Delete ( "IPA.zip" ) ;
2020-08-18 18:56:19 +00:00
}
}
2020-08-23 21:38:10 +00:00
GetInstalledMods ( ) ; //Update patcher state, should be fine for this rare event
2020-08-18 22:32:39 +00:00
status = CheckIfPatched ( ) ;
2020-08-18 18:56:19 +00:00
break ;
2020-06-16 17:22:29 +00:00
}
2020-08-18 18:56:19 +00:00
switch ( status )
2020-06-18 16:28:07 +00:00
{
2020-08-18 18:56:19 +00:00
case GameState . NoPatcher : //Make sure it actually worked
2020-08-23 21:38:10 +00:00
case GameState . OldPatcher :
2020-08-18 18:56:19 +00:00
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 ;
2020-06-16 17:22:29 +00:00
}
2020-08-18 18:56:19 +00:00
}
public enum GameState
{
NotFound ,
NoPatcher ,
2020-08-23 21:38:10 +00:00
OldPatcher ,
2020-08-18 18:56:19 +00:00
Unpatched ,
Patched
2020-06-16 17:22:29 +00:00
}
}
}