2016-12-15 20:07:03 +00:00
using IPA.Patcher ;
using System ;
2016-12-14 21:45:50 +00:00
using System.Collections.Generic ;
2017-01-20 19:29:51 +00:00
using System.Diagnostics ;
2016-12-14 21:45:50 +00:00
using System.IO ;
using System.Linq ;
2017-01-20 19:29:51 +00:00
using System.Reflection ;
using System.Runtime.InteropServices ;
2016-12-14 21:45:50 +00:00
using System.Text ;
2017-01-20 19:29:51 +00:00
using System.Text.RegularExpressions ;
using System.Windows.Forms ;
2016-12-14 21:45:50 +00:00
namespace IPA
{
2017-01-20 19:29:51 +00:00
2016-12-14 21:45:50 +00:00
class Program
{
2017-01-20 19:29:51 +00:00
2016-12-14 21:45:50 +00:00
static void Main ( string [ ] args )
{
if ( args . Length < 1 | | ! args [ 0 ] . EndsWith ( ".exe" ) )
{
Fail ( "Drag an (executable) file on the exe!" ) ;
}
2017-01-20 19:29:51 +00:00
try
{
var context = PatchContext . Create ( args ) ;
bool isRevert = args . Contains ( "--revert" ) | | Keyboard . IsKeyDown ( Keys . LMenu ) ;
// Sanitizing
Validate ( context ) ;
2016-12-15 20:07:03 +00:00
2017-01-20 19:29:51 +00:00
if ( isRevert )
{
Revert ( context ) ;
}
else
{
Install ( context ) ;
StartIfNeedBe ( context ) ;
}
} catch ( Exception e )
{
Fail ( e . Message ) ;
}
}
2016-12-14 21:45:50 +00:00
2017-01-20 19:29:51 +00:00
private static void Validate ( PatchContext c )
{
if ( ! File . Exists ( c . LauncherPathSrc ) ) Fail ( "Couldn't find DLLs! Make sure you extracted all contents of the release archive." ) ;
if ( ! Directory . Exists ( c . DataPathDst ) | | ! File . Exists ( c . EngineFile ) | | ! File . Exists ( c . AssemblyFile ) )
2016-12-15 20:07:03 +00:00
{
2017-01-20 19:29:51 +00:00
Fail ( "Game does not seem to be a Unity project. Could not find the libraries to patch." ) ;
}
}
2016-12-14 21:45:50 +00:00
2017-01-20 19:29:51 +00:00
private static void Install ( PatchContext context )
{
2016-12-14 21:45:50 +00:00
try
{
2016-12-15 20:07:03 +00:00
// Copying
2017-01-08 16:49:11 +00:00
Console . Write ( "Updating files... " ) ;
2017-01-20 19:29:51 +00:00
CopyAll ( new DirectoryInfo ( context . DataPathSrc ) , new DirectoryInfo ( context . DataPathDst ) ) ;
2017-01-08 16:49:11 +00:00
Console . WriteLine ( "Successfully updated files!" ) ;
2016-12-15 20:07:03 +00:00
2017-01-20 19:29:51 +00:00
if ( ! Directory . Exists ( context . PluginsFolder ) )
2016-12-15 20:07:03 +00:00
{
2017-01-08 16:49:11 +00:00
Console . WriteLine ( "Creating plugins folder... " ) ;
2017-01-20 19:29:51 +00:00
Directory . CreateDirectory ( context . PluginsFolder ) ;
2016-12-15 20:07:03 +00:00
}
// Patching
2017-01-20 19:29:51 +00:00
var patchedModule = PatchedModule . Load ( context . EngineFile ) ;
if ( ! patchedModule . IsPatched )
2016-12-15 20:07:03 +00:00
{
2017-01-08 16:49:11 +00:00
Console . Write ( "Patching UnityEngine.dll... " ) ;
2017-01-20 19:29:51 +00:00
BackupManager . MakeBackup ( context . EngineFile ) ;
2016-12-15 20:07:03 +00:00
patchedModule . Patch ( ) ;
2017-01-08 16:49:11 +00:00
Console . WriteLine ( "Done!" ) ;
2016-12-15 20:07:03 +00:00
}
// Virtualizing
2017-01-20 19:29:51 +00:00
var virtualizedModule = VirtualizedModule . Load ( context . AssemblyFile ) ;
if ( ! virtualizedModule . IsVirtualized )
2016-12-15 20:07:03 +00:00
{
2017-01-08 16:49:11 +00:00
Console . Write ( "Virtualizing Assembly-Csharp.dll... " ) ;
2017-01-20 19:29:51 +00:00
BackupManager . MakeBackup ( context . AssemblyFile ) ;
2016-12-15 20:07:03 +00:00
virtualizedModule . Virtualize ( ) ;
2017-01-08 16:49:11 +00:00
Console . WriteLine ( "Done!" ) ;
2016-12-15 20:07:03 +00:00
}
2017-01-20 19:29:51 +00:00
// Creating shortcut
if ( ! File . Exists ( context . ShortcutPath ) )
{
Console . Write ( "Creating shortcut... " ) ;
Shortcut . Create ( context . ShortcutPath , Assembly . GetExecutingAssembly ( ) . Location , Args ( context . Executable , "--launch" ) , context . ProjectRoot , "Launches the game and makes sure it's in a patched state" , "" , context . Executable ) ;
Console . WriteLine ( "Created" ) ;
}
}
catch ( Exception e )
2016-12-14 21:45:50 +00:00
{
Fail ( "Oops! This should not have happened.\n\n" + e ) ;
}
2017-01-08 16:49:11 +00:00
Console . WriteLine ( "Finished!" ) ;
2017-01-20 19:29:51 +00:00
}
private static void Revert ( PatchContext context )
{
Console . Write ( "Restoring game assembly... " ) ;
if ( BackupManager . Restore ( context . AssemblyFile ) )
{
Console . WriteLine ( "Done!" ) ;
} else
{
Console . WriteLine ( "Already vanilla!" ) ;
}
Console . Write ( "Restoring unity engine... " ) ;
if ( BackupManager . Restore ( context . EngineFile ) )
{
Console . WriteLine ( "Done!" ) ;
}
else
{
Console . WriteLine ( "Already vanilla!" ) ;
}
if ( File . Exists ( context . ShortcutPath ) )
{
Console . WriteLine ( "Deleting shortcut..." ) ;
File . Delete ( context . ShortcutPath ) ;
}
Console . WriteLine ( "" ) ;
Console . WriteLine ( "--- Done reverting ---" ) ;
if ( ! Environment . CommandLine . Contains ( "--nowait" ) )
{
Console . WriteLine ( "\n\n[Press any key to quit]" ) ;
Console . ReadKey ( ) ;
}
}
private static void StartIfNeedBe ( PatchContext context )
{
var argList = context . Args . ToList ( ) ;
bool launch = argList . Remove ( "--launch" ) ;
argList . RemoveAt ( 0 ) ;
if ( launch )
{
Process . Start ( context . Executable , Args ( argList . ToArray ( ) ) ) ;
}
2016-12-14 21:45:50 +00:00
}
public static void CopyAll ( DirectoryInfo source , DirectoryInfo target )
{
Directory . CreateDirectory ( target . FullName ) ;
// Copy each file into the new directory.
foreach ( FileInfo fi in source . GetFiles ( ) )
{
2016-12-15 20:07:03 +00:00
string targetFile = Path . Combine ( target . FullName , fi . Name ) ;
if ( ! File . Exists ( targetFile ) | | File . GetLastWriteTimeUtc ( targetFile ) < fi . LastWriteTimeUtc )
{
Console . WriteLine ( @"Copying {0}\{1}" , target . FullName , fi . Name ) ;
fi . CopyTo ( Path . Combine ( target . FullName , fi . Name ) , true ) ;
}
2016-12-14 21:45:50 +00:00
}
// Copy each subdirectory using recursion.
foreach ( DirectoryInfo diSourceSubDir in source . GetDirectories ( ) )
{
DirectoryInfo nextTargetSubDir =
target . CreateSubdirectory ( diSourceSubDir . Name ) ;
CopyAll ( diSourceSubDir , nextTargetSubDir ) ;
}
}
static void Fail ( string message )
{
2016-12-15 20:07:03 +00:00
Console . Error . Write ( "ERROR: " + message ) ;
if ( ! Environment . CommandLine . Contains ( "--nowait" ) )
{
2016-12-15 20:13:27 +00:00
Console . WriteLine ( "\n\n[Press any key to quit]" ) ;
Console . ReadKey ( ) ;
2016-12-15 20:07:03 +00:00
}
2016-12-14 21:45:50 +00:00
Environment . Exit ( 1 ) ;
}
2017-01-20 19:29:51 +00:00
public static string Args ( params string [ ] args )
{
return string . Join ( " " , args . Select ( EncodeParameterArgument ) . ToArray ( ) ) ;
}
/// <summary>
/// Encodes an argument for passing into a program
/// </summary>
/// <param name="original">The value that should be received by the program</param>
/// <returns>The value which needs to be passed to the program for the original value
/// to come through</returns>
public static string EncodeParameterArgument ( string original )
{
if ( string . IsNullOrEmpty ( original ) )
return original ;
string value = Regex . Replace ( original , @"(\\*)" + "\"" , @"$1\$0" ) ;
value = Regex . Replace ( value , @"^(.*\s.*?)(\\*)$" , "\"$1$2$2\"" ) ;
return value ;
}
public abstract class Keyboard
{
[Flags]
private enum KeyStates
{
None = 0 ,
Down = 1 ,
Toggled = 2
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern short GetKeyState ( int keyCode ) ;
private static KeyStates GetKeyState ( Keys key )
{
KeyStates state = KeyStates . None ;
short retVal = GetKeyState ( ( int ) key ) ;
//If the high-order bit is 1, the key is down
//otherwise, it is up.
if ( ( retVal & 0x8000 ) = = 0x8000 )
state | = KeyStates . Down ;
//If the low-order bit is 1, the key is toggled.
if ( ( retVal & 1 ) = = 1 )
state | = KeyStates . Toggled ;
return state ;
}
public static bool IsKeyDown ( Keys key )
{
return KeyStates . Down = = ( GetKeyState ( key ) & KeyStates . Down ) ;
}
public static bool IsKeyToggled ( Keys key )
{
return KeyStates . Toggled = = ( GetKeyState ( key ) & KeyStates . Toggled ) ;
}
}
2016-12-14 21:45:50 +00:00
}
}