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