diff --git a/IPA.Tests/IPA.Tests.csproj b/IPA.Tests/IPA.Tests.csproj
index 9765195f..fb98f0df 100644
--- a/IPA.Tests/IPA.Tests.csproj
+++ b/IPA.Tests/IPA.Tests.csproj
@@ -32,6 +32,7 @@
TRACE
prompt
4
+ true
diff --git a/IPA/Arguments.cs b/IPA/Arguments.cs
index 53bb301f..ae775acf 100644
--- a/IPA/Arguments.cs
+++ b/IPA/Arguments.cs
@@ -21,7 +21,7 @@ namespace IPA.ArgParsing
private Arguments(string[] args)
{
- toParse = args;
+ toParse = args.Skip(1).ToArray();
}
public Arguments Flags(params ArgumentFlag[] toAdd)
@@ -145,8 +145,8 @@ namespace IPA.ArgParsing
public void PrintHelp()
{
const string indent = " ";
- string filename = Path.GetFileName(Assembly.GetExecutingAssembly().Location);
- string format = @"help:
+ string filename = Environment.GetCommandLineArgs()[0];
+ string format = @"usage:
{2}{0} [FLAGS] [ARGUMENTS]
flags:
@@ -154,9 +154,9 @@ flags:
var flagsBuilder = new StringBuilder();
foreach (var flag in flagObjects)
{
- flagsBuilder.AppendFormat("{2}{0}{1}",
+ flagsBuilder.AppendFormat("{2}{0}{3}{1}",
string.Join(", ", flag.shortFlags.Select(s => $"-{s}").Concat( flag.longFlags.Select(s => $"--{s}")) ),
- Environment.NewLine, indent);
+ Environment.NewLine, indent, flag.ValueString != null ? "=" + flag.ValueString : "");
flagsBuilder.AppendFormat("{2}{2}{0}{1}", flag.DocString, Environment.NewLine, indent);
}
@@ -191,7 +191,10 @@ flags:
public bool Exists => exists;
public string Value => value;
+ public bool HasValue => Exists && Value != null;
+
public string DocString { get; set; } = "";
+ public string ValueString { get; set; } = null;
public static implicit operator bool(ArgumentFlag f)
{
diff --git a/IPA/IPA.csproj b/IPA/IPA.csproj
index c16ab006..f55672d3 100644
--- a/IPA/IPA.csproj
+++ b/IPA/IPA.csproj
@@ -34,6 +34,7 @@
prompt
4
false
+ true
favicon.ico
diff --git a/IPA/PatchContext.cs b/IPA/PatchContext.cs
index 580e5f0e..81ec755c 100644
--- a/IPA/PatchContext.cs
+++ b/IPA/PatchContext.cs
@@ -22,7 +22,6 @@ namespace IPA
public string LibsPathDst { get; private set; }
public string ManagedPath { get; private set; }
public string EngineFile { get; private set; }
- public string EngineWebRequestFile { get; private set; }
public string AssemblyFile { get; private set; }
public string ProjectRoot { get; private set; }
public string IPARoot { get; private set; }
diff --git a/IPA/Patcher/BackupUnit.cs b/IPA/Patcher/BackupUnit.cs
index 70674834..22763338 100644
--- a/IPA/Patcher/BackupUnit.cs
+++ b/IPA/Patcher/BackupUnit.cs
@@ -110,7 +110,8 @@ namespace IPA.Patcher
Console.WriteLine(" {0} => {1}", backupFile.FullName, target.FullName);
target.Directory.Create();
backupFile.CopyTo(target.FullName, true);
- } else
+ }
+ else
{
Console.WriteLine(" x {0}", target.FullName);
if(target.Exists)
@@ -118,7 +119,8 @@ namespace IPA.Patcher
target.Delete();
}
}
- } else {
+ } else
+ {
Console.Error.WriteLine("Backup not found!");
}
}
diff --git a/IPA/Patcher/Patcher.cs b/IPA/Patcher/Patcher.cs
index 2826f1f8..0a4527ce 100644
--- a/IPA/Patcher/Patcher.cs
+++ b/IPA/Patcher/Patcher.cs
@@ -49,21 +49,34 @@ namespace IPA.Patcher
{
get
{
+ var IIdata = new PatchData { IsPatched = false, Version = null };
foreach (var @ref in _Module.AssemblyReferences) {
- if (@ref.Name == "IllusionInjector") return new PatchData { IsPatched = true, Version = @ref.Version};
+ if (@ref.Name == "IllusionInjector") IIdata = new PatchData { IsPatched = true, Version = new Version(0,0,0,0) };
+ if (@ref.Name == "IllusionPlugin") return new PatchData { IsPatched = true, Version = @ref.Version };
}
- return new PatchData { IsPatched = false, Version = null};
+ return IIdata;
}
}
public void Patch(Version v)
{
// First, let's add the reference
- var nameReference = new AssemblyNameReference("IllusionInjector", v);
+ var nameReference = new AssemblyNameReference("IllusionInjector", new Version(1,0,0,0));
+ var versionNameReference = new AssemblyNameReference("IllusionPlugin", v);
var injectorPath = Path.Combine(_File.DirectoryName, "IllusionInjector.dll");
var injector = ModuleDefinition.ReadModule(injectorPath);
+ for (int i = 0; i < _Module.AssemblyReferences.Count; i++)
+ {
+ if (_Module.AssemblyReferences[i].Name == "IllusionInjector")
+ _Module.AssemblyReferences.RemoveAt(i--);
+ if (_Module.AssemblyReferences[i].Name == "IllusionPlugin")
+ _Module.AssemblyReferences.RemoveAt(i--);
+ }
+
_Module.AssemblyReferences.Add(nameReference);
+ _Module.AssemblyReferences.Add(versionNameReference);
+
int patched = 0;
foreach(var type in FindEntryTypes())
{
diff --git a/IPA/Patcher/Virtualizer.cs b/IPA/Patcher/Virtualizer.cs
index c5dab7a2..8bce06a3 100644
--- a/IPA/Patcher/Virtualizer.cs
+++ b/IPA/Patcher/Virtualizer.cs
@@ -45,10 +45,12 @@ namespace IPA.Patcher
///
public void Virtualize()
{
+
foreach (var type in _Module.Types)
{
VirtualizeType(type);
}
+ Console.WriteLine();
_Module.Write(_File.FullName);
}
@@ -67,7 +69,10 @@ namespace IPA.Patcher
// These two don't seem to work.
if (type.Name == "SceneControl" || type.Name == "ConfigUI") return;
- Console.WriteLine("Virtualizing {0}", type.Name);
+ //Console.CursorTop--;
+ Console.CursorLeft = 0;
+ Program.ClearLine();
+ Console.Write("Virtualizing {0}", type.Name);
// Take care of sub types
foreach (var subType in type.NestedTypes)
{
diff --git a/IPA/Program.cs b/IPA/Program.cs
index 14c4d5be..257c3452 100644
--- a/IPA/Program.cs
+++ b/IPA/Program.cs
@@ -21,13 +21,13 @@ namespace IPA {
private static Version Version => Assembly.GetEntryAssembly().GetName().Version;
- public static ArgumentFlag ArgHelp = new ArgumentFlag("--help", "-h") { DocString = "prints this message" };
- public static ArgumentFlag ArgWaitFor = new ArgumentFlag("--waitfor") { DocString = "waits for the specified PID to exit" };
- public static ArgumentFlag ArgForce = new ArgumentFlag("--force", "-f") { DocString = "forces the operation to go through" };
- public static ArgumentFlag ArgRevert = new ArgumentFlag("--revert") { DocString = "reverts the IPA installation" };
- public static ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait") { DocString = "doesn't wait for user input after the operation" };
- public static ArgumentFlag ArgStart = new ArgumentFlag("--start") { DocString = "uses value as arguments to start the game after the patch/unpatch" };
- public static ArgumentFlag ArgLaunch = new ArgumentFlag("--launch") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" };
+ public static ArgumentFlag ArgHelp = new ArgumentFlag("--help", "-h") { DocString = "prints this message" };
+ public static ArgumentFlag ArgWaitFor = new ArgumentFlag("--waitfor", "-w") { DocString = "waits for the specified PID to exit", ValueString = "PID" };
+ public static ArgumentFlag ArgForce = new ArgumentFlag("--force", "-f") { DocString = "forces the operation to go through" };
+ public static ArgumentFlag ArgRevert = new ArgumentFlag("--revert", "-r") { DocString = "reverts the IPA installation" };
+ public static ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait", "-n") { DocString = "doesn't wait for user input after the operation" };
+ public static ArgumentFlag ArgStart = new ArgumentFlag("--start", "-s") { DocString = "uses value as arguments to start the game after the patch/unpatch", ValueString = "ARGUMENTS" };
+ public static ArgumentFlag ArgLaunch = new ArgumentFlag("--launch", "-l") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" };
static void Main(string[] args)
{
@@ -41,8 +41,8 @@ namespace IPA {
try
{
- if (ArgWaitFor && ArgWaitFor.Value != null)
- {
+ if (ArgWaitFor.HasValue)
+ { // wait for process if necessary
int pid = int.Parse(ArgWaitFor.Value);
try
@@ -57,29 +57,20 @@ namespace IPA {
}
PatchContext context;
-
+
var argExeName = Arguments.CmdLine.PositionalArgs.FirstOrDefault(s => s.EndsWith(".exe"));
-
if (argExeName == null)
- {
- //Fail("Drag an (executable) file on the exe!");
context = PatchContext.Create(new DirectoryInfo(Directory.GetCurrentDirectory()).GetFiles()
- .First(o => o.FullName.EndsWith(".exe"))
+ .First(o => o.Extension == ".exe" && o.FullName != Assembly.GetCallingAssembly().Location)
.FullName);
- }
else
- {
context = PatchContext.Create(argExeName);
- }
-
- bool isRevert = ArgRevert || Keyboard.IsKeyDown(Keys.LMenu);
+
// Sanitizing
Validate(context);
- if (isRevert)
- {
+ if (ArgRevert || Keyboard.IsKeyDown(Keys.LMenu))
Revert(context);
- }
else
{
Install(context);
@@ -89,6 +80,19 @@ namespace IPA {
catch (Exception e) {
Fail(e.Message);
}
+
+ WaitForEnd();
+ }
+
+ private static void WaitForEnd()
+ {
+ if (!ArgNoWait)
+ {
+ Console.ForegroundColor = ConsoleColor.DarkYellow;
+ Console.WriteLine("[Press any key to continue]");
+ Console.ResetColor();
+ Console.ReadLine();
+ }
}
private static void Validate(PatchContext c) {
@@ -113,7 +117,7 @@ namespace IPA {
Console.WriteLine(
$"Preparing for update, {(patchedModule.Data.Version == null ? "UnPatched" : patchedModule.Data.Version.ToString())} => {Version}");
Console.WriteLine("--- Starting ---");
- Revert(context, new[] {"newVersion"});
+ Revert(context);
Console.ResetColor();
@@ -179,7 +183,7 @@ namespace IPA {
if (File.Exists(context.AssemblyFile)) {
var virtualizedModule = VirtualizedModule.Load(context.AssemblyFile);
if (!virtualizedModule.IsVirtualized) {
- Console.ForegroundColor = ConsoleColor.Blue;
+ Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Virtualizing Assembly-Csharp.dll... ");
backup.Add(context.AssemblyFile);
virtualizedModule.Virtualize();
@@ -191,45 +195,40 @@ namespace IPA {
#endregion
#region Creating shortcut
- /*if(!File.Exists(context.ShortcutPath))
+ if(!File.Exists(context.ShortcutPath))
{
- Console.Write("Creating shortcut to IPA ({0})... ", context.IPA);
+ Console.ForegroundColor = ConsoleColor.DarkGreen;
+ Console.WriteLine("Creating shortcut to IPA ({0})... ", context.IPA);
try
{
Shortcut.Create(
fileName: context.ShortcutPath,
targetPath: context.IPA,
- arguments: Args(context.Executable, "--launch"),
+ arguments: Args(context.Executable, "-ln"),
workingDirectory: context.ProjectRoot,
description: "Launches the game and makes sure it's in a patched state",
hotkey: "",
iconPath: context.Executable
);
- Console.WriteLine("Created");
- } catch (Exception e)
+ } catch (Exception)
{
+ Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Failed to create shortcut, but game was patched!");
}
- }*/
+ Console.ResetColor();
+ }
#endregion
}
- catch (Exception e) {
- Fail("Oops! This should not have happened.\n\n" + e);
- }
-
-
- if (!ArgNoWait)
+ catch (Exception e)
{
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine("Finished!");
- Console.ResetColor();
- Console.ReadLine();
+ Console.ForegroundColor = ConsoleColor.Red;
+ Fail("Oops! This should not have happened.\n\n" + e);
}
+ Console.ResetColor();
}
- private static void Revert(PatchContext context, string[] args = null) {
+ private static void Revert(PatchContext context) {
Console.ForegroundColor = ConsoleColor.Cyan;
- bool isNewVersion = (args != null && args.Contains("newVersion"));
Console.Write("Restoring backup... ");
if (BackupManager.Restore(context)) {
@@ -248,16 +247,11 @@ namespace IPA {
Console.WriteLine("");
Console.WriteLine("--- Done reverting ---");
- if (!ArgNoWait && !isNewVersion) {
- Console.WriteLine("\n\n[Press any key to quit]");
- Console.ReadKey();
- }
-
Console.ResetColor();
}
private static void StartIfNeedBe(PatchContext context) {
- if (ArgStart && ArgStart.Value != null)
+ if (ArgStart.HasValue)
{
Process.Start(context.Executable, ArgStart.Value);
}
@@ -315,6 +309,14 @@ namespace IPA {
}
}
+ public static void ClearLine()
+ {
+ Console.SetCursorPosition(0, Console.CursorTop);
+ int tpos = Console.CursorTop;
+ Console.Write(new string(' ', Console.WindowWidth));
+ Console.SetCursorPosition(0, tpos);
+ }
+
private static IEnumerable PassThroughInterceptor(FileInfo from, FileInfo to) {
yield return to;
}
@@ -331,6 +333,8 @@ namespace IPA {
if (!targetFile.Exists || targetFile.LastWriteTimeUtc < fi.LastWriteTimeUtc || aggressive) {
targetFile.Directory.Create();
+ Console.CursorTop--;
+ ClearLine();
Console.WriteLine(@"Copying {0}", targetFile.FullName);
backup.Add(targetFile);
fi.CopyTo(targetFile.FullName, true);
@@ -348,10 +352,8 @@ namespace IPA {
static void Fail(string message) {
Console.Error.Write("ERROR: " + message);
- if (!ArgNoWait) {
- Console.WriteLine("\n\n[Press any key to quit]");
- Console.ReadKey();
- }
+
+ WaitForEnd();
Environment.Exit(1);
}
diff --git a/IPA/Properties/AssemblyInfo.cs b/IPA/Properties/AssemblyInfo.cs
index 8f1f5f30..abe9ca50 100644
--- a/IPA/Properties/AssemblyInfo.cs
+++ b/IPA/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("3.8.8.*")]
-[assembly: AssemblyFileVersion("3.8.8")]
+[assembly: AssemblyVersion("3.8.9.*")]
+[assembly: AssemblyFileVersion("3.8.9")]
diff --git a/IllusionInjector/IllusionInjector.csproj b/IllusionInjector/IllusionInjector.csproj
index cb8d83c6..1b4be7e6 100644
--- a/IllusionInjector/IllusionInjector.csproj
+++ b/IllusionInjector/IllusionInjector.csproj
@@ -36,6 +36,7 @@
4
false
true
+ true
diff --git a/IllusionInjector/Updating/SelfPlugin.cs b/IllusionInjector/Updating/SelfPlugin.cs
index a09b9026..39863d70 100644
--- a/IllusionInjector/Updating/SelfPlugin.cs
+++ b/IllusionInjector/Updating/SelfPlugin.cs
@@ -12,7 +12,7 @@ namespace IllusionInjector.Updating
internal class SelfPlugin : IBeatSaberPlugin
{
internal const string IPA_Name = "Beat Saber IPA";
- internal const string IPA_Version = "3.8.8";
+ internal const string IPA_Version = "3.8.9";
public string Name => IPA_Name;
diff --git a/IllusionPlugin/IllusionPlugin.csproj b/IllusionPlugin/IllusionPlugin.csproj
index d61d19fd..f5f34363 100644
--- a/IllusionPlugin/IllusionPlugin.csproj
+++ b/IllusionPlugin/IllusionPlugin.csproj
@@ -33,6 +33,7 @@
4
bin\Release\IllusionPlugin.XML
false
+ true
diff --git a/MSBuildTasks/MSBuildTasks.csproj b/MSBuildTasks/MSBuildTasks.csproj
index 86734fe5..c21cbf16 100644
--- a/MSBuildTasks/MSBuildTasks.csproj
+++ b/MSBuildTasks/MSBuildTasks.csproj
@@ -29,6 +29,7 @@
TRACE
prompt
4
+ true