diff --git a/BSIPA.sln b/BSIPA.sln index 560c02bc..11836794 100644 --- a/BSIPA.sln +++ b/BSIPA.sln @@ -8,8 +8,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA", "IPA\IPA.csproj", "{1 {2A1AF16B-27F1-46E0-9A95-181516BC1CB7} = {2A1AF16B-27F1-46E0-9A95-181516BC1CB7} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA.Tests", "IPA.Tests\IPA.Tests.csproj", "{C66092B0-5C1E-44E9-B524-E0E8E1425379}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSBuildTasks", "MSBuildTasks\MSBuildTasks.csproj", "{F08C3C7A-3221-432E-BAB8-32BCE58408C8}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA.Loader", "IPA.Loader\IPA.Loader.csproj", "{5AD344F0-01A0-4CA8-92E5-9D095737744D}" @@ -79,28 +77,6 @@ Global {14092533-98BB-40A4-9AFC-27BB75672A70}.Verbose|x64.Build.0 = Verbose|Any CPU {14092533-98BB-40A4-9AFC-27BB75672A70}.Verbose|x86.ActiveCfg = Release|Any CPU {14092533-98BB-40A4-9AFC-27BB75672A70}.Verbose|x86.Build.0 = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|x64.ActiveCfg = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|x64.Build.0 = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|x86.ActiveCfg = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|x86.Build.0 = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.Build.0 = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|x64.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|x86.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|x86.Build.0 = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose_Release|Any CPU.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose_Release|Any CPU.Build.0 = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose_Release|x64.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose_Release|x86.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose_Release|x86.Build.0 = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose|Any CPU.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose|Any CPU.Build.0 = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose|x64.ActiveCfg = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose|x64.Build.0 = Debug|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose|x86.ActiveCfg = Release|Any CPU - {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Verbose|x86.Build.0 = Release|Any CPU {F08C3C7A-3221-432E-BAB8-32BCE58408C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F08C3C7A-3221-432E-BAB8-32BCE58408C8}.Debug|Any CPU.Build.0 = Debug|Any CPU {F08C3C7A-3221-432E-BAB8-32BCE58408C8}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/BSIPA.sln.DotSettings b/BSIPA.sln.DotSettings new file mode 100644 index 00000000..34f7d9cd --- /dev/null +++ b/BSIPA.sln.DotSettings @@ -0,0 +1,12 @@ + + BS + IPA + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> + True + True + True + True + True + True + True \ No newline at end of file diff --git a/CollectDependencies/Program.cs b/CollectDependencies/Program.cs index ef3c411c..0e1da50c 100644 --- a/CollectDependencies/Program.cs +++ b/CollectDependencies/Program.cs @@ -3,12 +3,10 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace CollectDependencies { - class Program + static class Program { static void Main(string[] args) { @@ -34,7 +32,7 @@ namespace CollectDependencies return v2; } - foreach (var line in depsfile.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)) + foreach (var line in depsfile.Split(new[] { Environment.NewLine }, StringSplitOptions.None)) { var parts = line.Split('"'); var path = parts.Last(); @@ -48,7 +46,7 @@ namespace CollectDependencies var arglist = string.Join(" ", parts); if (command == "from") { // an "import" type command - path = File.ReadAllText(Path.Combine(fdir, arglist)); + path = File.ReadAllText(Path.Combine(fdir ?? throw new InvalidOperationException(), arglist)); } else if (command == "prompt") { @@ -85,16 +83,17 @@ namespace CollectDependencies if (fname == "") continue; - var outp = Path.Combine(fdir, Path.GetFileName(fname)); + var outp = Path.Combine(fdir ?? throw new InvalidOperationException(), Path.GetFileName(fname) ?? throw new InvalidOperationException()); Console.WriteLine($"Copying \"{fname}\" to \"{outp}\""); if (File.Exists(outp)) File.Delete(outp); - if (Path.GetExtension(fname).ToLower() == ".dll") + if (Path.GetExtension(fname)?.ToLower() == ".dll") { + // ReSharper disable once StringLiteralTypo if (fparts.Length > 1 && fparts[1] == "virt") { var module = VirtualizedModule.Load(fname); - module.Virtualize(fname = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), Path.GetFileName(fname))); + module.Virtualize(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), Path.GetFileName(fname) ?? throw new InvalidOperationException())); } var modl = ModuleDefinition.ReadModule(fparts[0]); foreach (var t in modl.Types) diff --git a/CollectDependencies/Properties/AssemblyInfo.cs b/CollectDependencies/Properties/AssemblyInfo.cs index d806ff21..83c77d77 100644 --- a/CollectDependencies/Properties/AssemblyInfo.cs +++ b/CollectDependencies/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/CollectDependencies/Virtualizer.cs b/CollectDependencies/Virtualizer.cs index 324820d3..ac9db5c2 100644 --- a/CollectDependencies/Virtualizer.cs +++ b/CollectDependencies/Virtualizer.cs @@ -1,18 +1,13 @@ using Mono.Cecil; -using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; namespace CollectDependencies { class VirtualizedModule { - private const string ENTRY_TYPE = "Display"; - - private FileInfo _File; - private ModuleDefinition _Module; + private readonly FileInfo _file; + private ModuleDefinition _module; public static VirtualizedModule Load(string engineFile) { @@ -21,7 +16,7 @@ namespace CollectDependencies private VirtualizedModule(string assemblyFile) { - _File = new FileInfo(assemblyFile); + _file = new FileInfo(assemblyFile); LoadModules(); } @@ -29,29 +24,29 @@ namespace CollectDependencies private void LoadModules() { var resolver = new DefaultAssemblyResolver(); - resolver.AddSearchDirectory(_File.DirectoryName); + resolver.AddSearchDirectory(_file.DirectoryName); var parameters = new ReaderParameters { AssemblyResolver = resolver, }; - _Module = ModuleDefinition.ReadModule(_File.FullName, parameters); + _module = ModuleDefinition.ReadModule(_file.FullName, parameters); } - + /// /// /// - /// - public void Virtualize(string targetfile) + /// + public void Virtualize(string targetFile) { - foreach (var type in _Module.Types) + foreach (var type in _module.Types) { VirtualizeType(type); } - _Module.Write(targetfile); + _module.Write(targetFile); } private void VirtualizeType(TypeDefinition type) @@ -105,10 +100,11 @@ namespace CollectDependencies { get { - var awakeMethods = _Module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")); - if (awakeMethods.Count() == 0) return false; + var awakeMethods = _module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")); + var methodDefinitions = awakeMethods as MethodDefinition[] ?? awakeMethods.ToArray(); + if (!methodDefinitions.Any()) return false; - return ((float)awakeMethods.Count(m => m.IsVirtual) / awakeMethods.Count()) > 0.5f; + return ((float)methodDefinitions.Count(m => m.IsVirtual) / methodDefinitions.Count()) > 0.5f; } } } diff --git a/IPA.Injector/Backups/BackupManager.cs b/IPA.Injector/Backups/BackupManager.cs index 368a50a4..d2a47df9 100644 --- a/IPA.Injector/Backups/BackupManager.cs +++ b/IPA.Injector/Backups/BackupManager.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; namespace IPA.Injector.Backups { - public class BackupManager + public static class BackupManager { public static BackupUnit FindLatestBackup(string dir) { diff --git a/IPA.Injector/Backups/BackupUnit.cs b/IPA.Injector/Backups/BackupUnit.cs index 85b56c39..99b2158e 100644 --- a/IPA.Injector/Backups/BackupUnit.cs +++ b/IPA.Injector/Backups/BackupUnit.cs @@ -1,11 +1,7 @@ -using IPA.Logging; -using IPA.Utilities; +using IPA.Utilities; using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.IO; -using System.Linq; -using System.Text; namespace IPA.Injector.Backups { @@ -16,11 +12,11 @@ namespace IPA.Injector.Backups { public string Name { get; private set; } - private DirectoryInfo _BackupPath; - private HashSet _Files = new HashSet(); - private FileInfo _ManifestFile; - private static string _ManifestFileName = "$manifest$.txt"; - + private readonly DirectoryInfo _backupPath; + private readonly HashSet _files = new HashSet(); + private readonly FileInfo _manifestFile; + private const string ManifestFileName = "$manifest$.txt"; + public BackupUnit(string dir) : this(dir, DateTime.Now.ToString("yyyy-MM-dd_h-mm-ss")) { } @@ -28,8 +24,8 @@ namespace IPA.Injector.Backups private BackupUnit(string dir, string name) { Name = name; - _BackupPath = new DirectoryInfo(Path.Combine(dir, Name)); - _ManifestFile = new FileInfo(Path.Combine(_BackupPath.FullName, _ManifestFileName)); + _backupPath = new DirectoryInfo(Path.Combine(dir, Name)); + _manifestFile = new FileInfo(Path.Combine(_backupPath.FullName, ManifestFileName)); } public static BackupUnit FromDirectory(DirectoryInfo directory, string dir) @@ -37,19 +33,19 @@ namespace IPA.Injector.Backups var unit = new BackupUnit(dir, directory.Name); // Read Manifest - if (unit._ManifestFile.Exists) + if (unit._manifestFile.Exists) { - string manifest = File.ReadAllText(unit._ManifestFile.FullName); - foreach (var line in manifest.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - unit._Files.Add(line); + var manifest = File.ReadAllText(unit._manifestFile.FullName); + foreach (var line in manifest.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) + unit._files.Add(line); } else { foreach (var file in directory.GetFiles("*", SearchOption.AllDirectories)) { - if (file.Name == _ManifestFileName) continue; + if (file.Name == ManifestFileName) continue; var relativePath = file.FullName.Substring(directory.FullName.Length + 1); - unit._Files.Add(relativePath); + unit._files.Add(relativePath); } } @@ -63,20 +59,20 @@ namespace IPA.Injector.Backups internal void Delete() { - _BackupPath.Delete(true); + _backupPath.Delete(true); } /// /// Adds a file to the list of changed files and backups it. /// - /// + /// public void Add(FileInfo file) { var relativePath = LoneFunctions.GetRelativePath(file.FullName, Environment.CurrentDirectory); - var backupPath = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath)); + var backupPath = new FileInfo(Path.Combine(_backupPath.FullName, relativePath)); // Copy over - backupPath.Directory.Create(); + backupPath.Directory?.Create(); if (file.Exists) { if (File.Exists(backupPath.FullName)) @@ -89,17 +85,15 @@ namespace IPA.Injector.Backups backupPath.Create().Close(); } - if (!_Files.Contains(relativePath)) - { - if (!File.Exists(_ManifestFile.FullName)) - _ManifestFile.Create().Close(); - var stream = _ManifestFile.AppendText(); - stream.WriteLine(relativePath); - stream.Close(); + if (_files.Contains(relativePath)) return; + if (!File.Exists(_manifestFile.FullName)) + _manifestFile.Create().Close(); + var stream = _manifestFile.AppendText(); + stream.WriteLine(relativePath); + stream.Close(); - // Add to list - _Files.Add(relativePath); - } + // Add to list + _files.Add(relativePath); } } diff --git a/IPA.Injector/Bootstrapper.cs b/IPA.Injector/Bootstrapper.cs index 1bdc0ae6..caa937c9 100644 --- a/IPA.Injector/Bootstrapper.cs +++ b/IPA.Injector/Bootstrapper.cs @@ -1,24 +1,24 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using UnityEngine; +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnusedMember.Global namespace IPA.Injector { - class Bootstrapper : MonoBehaviour + internal class Bootstrapper : MonoBehaviour { public event Action Destroyed = delegate {}; - - void Awake() + + public void Awake() { } - void Start() + public void Start() { Destroy(gameObject); } - void OnDestroy() + + public void OnDestroy() { Destroyed(); } diff --git a/IPA.Injector/ConsoleWindow.cs b/IPA.Injector/ConsoleWindow.cs index 0882f467..a44e8d24 100644 --- a/IPA.Injector/ConsoleWindow.cs +++ b/IPA.Injector/ConsoleWindow.cs @@ -1,21 +1,19 @@ using System; -using System.Collections; -using System.Runtime.InteropServices; using System.IO; -using System.Text; +using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; -namespace IPA.Injector.Windows +namespace IPA.Injector { // https://stackoverflow.com/a/48864902/3117125 - static class WinConsole + internal static class WinConsole { - static public void Initialize(bool alwaysCreateNewConsole = true) + public static void Initialize(bool alwaysCreateNewConsole = true) { bool consoleAttached = true; if (alwaysCreateNewConsole - || (AttachConsole(ATTACH_PARRENT) == 0 - && Marshal.GetLastWin32Error() != ERROR_ACCESS_DENIED)) + || (AttachConsole(AttachParent) == 0 + && Marshal.GetLastWin32Error() != ErrorAccessDenied)) { consoleAttached = AllocConsole() != 0; } @@ -34,7 +32,7 @@ namespace IPA.Injector.Windows private static void InitializeOutStream() { - var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write); + var fs = CreateFileStream("CONOUT$", GenericWrite, FileShareWrite, FileAccess.Write); if (fs != null) { var writer = new StreamWriter(fs) { AutoFlush = true }; @@ -45,7 +43,7 @@ namespace IPA.Injector.Windows private static void InitializeInStream() { - var fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read); + var fs = CreateFileStream("CONIN$", GenericRead, FileShareRead, FileAccess.Read); if (fs != null) { Console.SetIn(new StreamReader(fs)); @@ -55,7 +53,7 @@ namespace IPA.Injector.Windows private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, FileAccess dotNetFileAccess) { - var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true); + var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OpenExisting, FileAttributeNormal, IntPtr.Zero), true); if (!file.IsInvalid) { var fs = new FileStream(file, dotNetFileAccess); @@ -77,7 +75,7 @@ namespace IPA.Injector.Windows SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] - private static extern UInt32 AttachConsole(UInt32 dwProcessId); + private static extern uint AttachConsole(uint dwProcessId); [DllImport("kernel32.dll", EntryPoint = "CreateFileW", @@ -86,23 +84,23 @@ namespace IPA.Injector.Windows CallingConvention = CallingConvention.StdCall)] private static extern IntPtr CreateFileW( string lpFileName, - UInt32 dwDesiredAccess, - UInt32 dwShareMode, + uint dwDesiredAccess, + uint dwShareMode, IntPtr lpSecurityAttributes, - UInt32 dwCreationDisposition, - UInt32 dwFlagsAndAttributes, + uint dwCreationDisposition, + uint dwFlagsAndAttributes, IntPtr hTemplateFile ); - private const UInt32 GENERIC_WRITE = 0x40000000; - private const UInt32 GENERIC_READ = 0x80000000; - private const UInt32 FILE_SHARE_READ = 0x00000001; - private const UInt32 FILE_SHARE_WRITE = 0x00000002; - private const UInt32 OPEN_EXISTING = 0x00000003; - private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80; - private const UInt32 ERROR_ACCESS_DENIED = 5; - - private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF; + private const uint GenericWrite = 0x40000000; + private const uint GenericRead = 0x80000000; + private const uint FileShareRead = 0x00000001; + private const uint FileShareWrite = 0x00000002; + private const uint OpenExisting = 0x00000003; + private const uint FileAttributeNormal = 0x80; + private const uint ErrorAccessDenied = 5; + + private const uint AttachParent = 0xFFFFFFFF; #endregion } diff --git a/IPA.Injector/IPA.Injector.csproj b/IPA.Injector/IPA.Injector.csproj index 5a432f6b..3a622776 100644 --- a/IPA.Injector/IPA.Injector.csproj +++ b/IPA.Injector/IPA.Injector.csproj @@ -61,7 +61,6 @@ - diff --git a/IPA.Injector/Injector.cs b/IPA.Injector/Injector.cs index 714011bd..e216ccdc 100644 --- a/IPA.Injector/Injector.cs +++ b/IPA.Injector/Injector.cs @@ -1,23 +1,23 @@ -using Harmony; -using IPA.Injector.Backups; +using IPA.Injector.Backups; using IPA.Loader; using IPA.Logging; using Mono.Cecil; using Mono.Cecil.Cil; using System; -using System.Collections.Generic; -using System.Linq; +using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; using UnityEngine; using static IPA.Logging.Logger; using MethodAttributes = Mono.Cecil.MethodAttributes; namespace IPA.Injector { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public static class Injector { + // ReSharper disable once UnusedParameter.Global public static void Main(string[] args) { // entry point for doorstop // At this point, literally nothing but mscorlib is loaded, @@ -28,7 +28,7 @@ namespace IPA.Injector try { if (!Environment.GetCommandLineArgs().Contains("--no-console")) - Windows.WinConsole.Initialize(); + WinConsole.Initialize(); SetupLibraryLoading(); @@ -96,30 +96,30 @@ namespace IPA.Injector else { var ilp = cctor.Body.GetILProcessor(); - for (int i = 0; i < Math.Min(2, cctor.Body.Instructions.Count); i++) + for (var i = 0; i < Math.Min(2, cctor.Body.Instructions.Count); i++) { var ins = cctor.Body.Instructions[i]; - if (i == 0) + switch (i) { - if (ins.OpCode != OpCodes.Call) - { + case 0 when ins.OpCode != OpCodes.Call: ilp.Replace(ins, ilp.Create(OpCodes.Call, cbs)); modified = true; - } - else + break; + case 0: { - var mref = ins.Operand as MethodReference; - if (mref.FullName != cbs.FullName) + var methodRef = ins.Operand as MethodReference; + if (methodRef?.FullName != cbs.FullName) { ilp.Replace(ins, ilp.Create(OpCodes.Call, cbs)); modified = true; } + + break; } - } - if (i == 1 && ins.OpCode != OpCodes.Ret) - { - ilp.Replace(ins, ilp.Create(OpCodes.Ret)); - modified = true; + case 1 when ins.OpCode != OpCodes.Ret: + ilp.Replace(ins, ilp.Create(OpCodes.Ret)); + modified = true; + break; } } } @@ -140,11 +140,11 @@ namespace IPA.Injector #endregion } - private static bool bootstrapped = false; + private static bool _bootstrapped; private static void CreateBootstrapper() { - if (bootstrapped) return; - bootstrapped = true; + if (_bootstrapped) return; + _bootstrapped = true; Application.logMessageReceived += delegate (string condition, string stackTrace, LogType type) { @@ -154,30 +154,31 @@ namespace IPA.Injector }; // need to reinit streams singe Unity seems to redirect stdout - Windows.WinConsole.InitializeStreams(); + WinConsole.InitializeStreams(); var bootstrapper = new GameObject("NonDestructiveBootstrapper").AddComponent(); bootstrapper.Destroyed += Bootstrapper_Destroyed; } - private static bool injected = false; + private static bool _injected; public static void Inject() { - if (!injected) + if (!_injected) { - injected = true; - Windows.WinConsole.Initialize(); + _injected = true; + WinConsole.Initialize(); SetupLibraryLoading(); var bootstrapper = new GameObject("Bootstrapper").AddComponent(); bootstrapper.Destroyed += Bootstrapper_Destroyed; } } - private static bool loadingDone = false; - public static void SetupLibraryLoading() + private static bool _loadingDone; + + private static void SetupLibraryLoading() { - if (loadingDone) return; - loadingDone = true; + if (_loadingDone) return; + _loadingDone = true; #region Add Library load locations AppDomain.CurrentDomain.AssemblyResolve += LibLoader.AssemblyLibLoader; /*try @@ -191,9 +192,11 @@ namespace IPA.Injector #endregion } +/* [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetDllDirectory(string lpPathName); +*/ private static void Bootstrapper_Destroyed() { diff --git a/IPA.Injector/LibLoader.cs b/IPA.Injector/LibLoader.cs index 34a378ae..d90afeae 100644 --- a/IPA.Injector/LibLoader.cs +++ b/IPA.Injector/LibLoader.cs @@ -1,20 +1,17 @@ -using IPA.Logging; -using System; +using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using IPA.Logging; using static IPA.Logging.Logger; namespace IPA.Injector { - internal class LibLoader + internal static class LibLoader { - public static string LibraryPath => Path.Combine(Environment.CurrentDirectory, "Libs"); - public static string NativeLibraryPath => Path.Combine(LibraryPath, "Native"); - private static Dictionary filenameLocations = null; + private static string LibraryPath => Path.Combine(Environment.CurrentDirectory, "Libs"); + private static string NativeLibraryPath => Path.Combine(LibraryPath, "Native"); + private static Dictionary filenameLocations; public static Assembly AssemblyLibLoader(object source, ResolveEventArgs e) { @@ -29,20 +26,18 @@ namespace IPA.Injector filenameLocations.Add(fn.Name, fn.FullName); } - var testFilen = $"{asmName.Name}.{asmName.Version}.dll"; - Log(Level.Debug, $"Looking for file {testFilen}"); + var testFile = $"{asmName.Name}.{asmName.Version}.dll"; + Log(Level.Debug, $"Looking for file {testFile}"); - if (filenameLocations.TryGetValue(testFilen, out string path)) + if (filenameLocations.TryGetValue(testFile, out string path)) { - Log(Level.Debug, $"Found file {testFilen} as {path}"); + Log(Level.Debug, $"Found file {testFile} as {path}"); if (File.Exists(path)) { return Assembly.LoadFrom(path); } - else - { - Log(Level.Critical, $"but {path} no longer exists!"); - } + + Log(Level.Critical, $"but {path} no longer exists!"); } Log(Level.Critical, $"No library {asmName} found"); @@ -67,13 +62,13 @@ namespace IPA.Injector // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree private static IEnumerable TraverseTree(string root, Func dirValidator = null) { - if (dirValidator == null) dirValidator = (s) => true; + if (dirValidator == null) dirValidator = s => true; // Data structure to hold names of subfolders to be // examined for files. Stack dirs = new Stack(32); - if (!System.IO.Directory.Exists(root)) + if (!Directory.Exists(root)) { throw new ArgumentException(); } @@ -85,7 +80,7 @@ namespace IPA.Injector string[] subDirs; try { - subDirs = System.IO.Directory.GetDirectories(currentDir); + subDirs = Directory.GetDirectories(currentDir); } // An UnauthorizedAccessException exception will be thrown if we do not have // discovery permission on a folder or file. It may or may not be acceptable @@ -101,16 +96,16 @@ namespace IPA.Injector //Console.WriteLine(e.Message); continue; } - catch (System.IO.DirectoryNotFoundException) + catch (DirectoryNotFoundException) { //Console.WriteLine(e.Message); continue; } - string[] files = null; + string[] files; try { - files = System.IO.Directory.GetFiles(currentDir); + files = Directory.GetFiles(currentDir); } catch (UnauthorizedAccessException) @@ -120,7 +115,7 @@ namespace IPA.Injector continue; } - catch (System.IO.DirectoryNotFoundException) + catch (DirectoryNotFoundException) { //Console.WriteLine(e.Message); continue; @@ -135,14 +130,14 @@ namespace IPA.Injector // Modify this block to perform your required task. foreach (string file in files) { - FileInfo nextValue = null; + FileInfo nextValue; try { // Perform whatever action is required in your scenario. - nextValue = new System.IO.FileInfo(file); + nextValue = new FileInfo(file); //Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime); } - catch (System.IO.FileNotFoundException) + catch (FileNotFoundException) { // If file was deleted by a separate application // or thread since the call to TraverseTree() diff --git a/IPA.Injector/Properties/AssemblyInfo.cs b/IPA.Injector/Properties/AssemblyInfo.cs index 01d79892..a421a594 100644 --- a/IPA.Injector/Properties/AssemblyInfo.cs +++ b/IPA.Injector/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ -using IPA.Injector; -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -23,7 +22,6 @@ using System.Runtime.InteropServices; // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("2a1af16b-27f1-46e0-9a95-181516bc1cb7")] [assembly: InternalsVisibleTo("IPA.Loader")] -[assembly: ForceAssemblyReference(typeof(SemVer.Version))] // Version information for an assembly consists of the following four values: // @@ -35,5 +33,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.11.1")] // will be patched by AppVeyor -[assembly: AssemblyFileVersion("3.11.1")] // will be patched by AppVeyor +[assembly: AssemblyVersion("3.11.2")] +[assembly: AssemblyFileVersion("3.11.2")] diff --git a/IPA.Injector/Updates.cs b/IPA.Injector/Updates.cs index 658483b8..ab7bc6c1 100644 --- a/IPA.Injector/Updates.cs +++ b/IPA.Injector/Updates.cs @@ -1,17 +1,13 @@ using IPA.Utilities; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using static IPA.Logging.Logger; namespace IPA.Injector { - class Updates + internal static class Updates { - public const string DeleteFileName = Updating.ModsaberML.Updater._SpecialDeletionsFile; + private const string DeleteFileName = Updating.ModSaber.Updater.SpecialDeletionsFile; public static void InstallPendingUpdates() { var pendingDir = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending"); diff --git a/IPA.Injector/Virtualizer.cs b/IPA.Injector/Virtualizer.cs index 21daec52..9aa04ae9 100644 --- a/IPA.Injector/Virtualizer.cs +++ b/IPA.Injector/Virtualizer.cs @@ -1,19 +1,14 @@ using Mono.Cecil; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; namespace IPA.Injector { internal class VirtualizedModule { - private const string ENTRY_TYPE = "Display"; - - public FileInfo file; - public ModuleDefinition module; + private readonly FileInfo file; + private ModuleDefinition module; public static VirtualizedModule Load(string engineFile) { @@ -35,11 +30,10 @@ namespace IPA.Injector /// /// /// - /// public void Virtualize(AssemblyName selfName, Action beforeChangeCallback = null) { - bool changed = false; - bool virtualize = true; + var changed = false; + var virtualize = true; foreach (var r in module.AssemblyReferences) { if (r.Name == selfName.Name) diff --git a/IPA.Injector/WtfThisDoesntNeedToExist.cs b/IPA.Injector/WtfThisDoesntNeedToExist.cs deleted file mode 100644 index b8514af2..00000000 --- a/IPA.Injector/WtfThisDoesntNeedToExist.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace IPA.Injector -{ - [AttributeUsage(AttributeTargets.Assembly)] - internal class ForceAssemblyReferenceAttribute : Attribute - { - public ForceAssemblyReferenceAttribute(Type forcedType) - { - //not sure if these two lines are required since - //the type is passed to constructor as parameter, - //thus effectively being used - Action noop = _ => { }; - noop(forcedType); - } - } -} diff --git a/IPA.Loader/Config/ConfigProviders/JsonConfigProvider.cs b/IPA.Loader/Config/ConfigProviders/JsonConfigProvider.cs index 6d07ef73..4c2eba10 100644 --- a/IPA.Loader/Config/ConfigProviders/JsonConfigProvider.cs +++ b/IPA.Loader/Config/ConfigProviders/JsonConfigProvider.cs @@ -1,12 +1,10 @@ -using IPA.Logging; +using System; +using System.Collections.Specialized; +using System.ComponentModel; +using System.IO; +using IPA.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IPA.Config.ConfigProviders { @@ -17,11 +15,11 @@ namespace IPA.Config.ConfigProviders // TODO: create a wrapper that allows empty object creation public dynamic Dynamic => jsonObj; - public bool HasChanged { get; private set; } = false; + public bool HasChanged { get; private set; } public DateTime LastModified => File.GetLastWriteTime(Filename + ".json"); - private string _filename = null; + private string _filename; public string Filename { get => _filename; @@ -37,10 +35,10 @@ namespace IPA.Config.ConfigProviders { Logger.config.Debug($"Loading file {Filename}.json"); - var finfo = new FileInfo(Filename + ".json"); - if (finfo.Exists) + var fileInfo = new FileInfo(Filename + ".json"); + if (fileInfo.Exists) { - string json = finfo.OpenText().ReadToEnd(); + var json = fileInfo.OpenText().ReadToEnd(); try { jsonObj = JObject.Parse(json); @@ -50,7 +48,7 @@ namespace IPA.Config.ConfigProviders Logger.config.Error($"Error parsing JSON in file {Filename}.json; resetting to empty JSON"); Logger.config.Error(e); jsonObj = new JObject(); - File.WriteAllText(finfo.FullName, JsonConvert.SerializeObject(jsonObj, Formatting.Indented)); + File.WriteAllText(fileInfo.FullName, JsonConvert.SerializeObject(jsonObj, Formatting.Indented)); } } else @@ -68,17 +66,17 @@ namespace IPA.Config.ConfigProviders jsonObj.CollectionChanged += JsonObj_CollectionChanged; } - private void JsonObj_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + private void JsonObj_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { HasChanged = true; } - private void JsonObj_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) + private void JsonObj_ListChanged(object sender, ListChangedEventArgs e) { HasChanged = true; } - private void JsonObj_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + private void JsonObj_PropertyChanged(object sender, PropertyChangedEventArgs e) { HasChanged = true; } @@ -92,9 +90,9 @@ namespace IPA.Config.ConfigProviders { Logger.config.Debug($"Saving file {Filename}.json"); - var finfo = new FileInfo(Filename + ".json"); + var fileInfo = new FileInfo(Filename + ".json"); - File.WriteAllText(finfo.FullName, JsonConvert.SerializeObject(jsonObj, Formatting.Indented)); + File.WriteAllText(fileInfo.FullName, JsonConvert.SerializeObject(jsonObj, Formatting.Indented)); HasChanged = false; } diff --git a/IPA.Loader/Config/IConfigProvider.cs b/IPA.Loader/Config/IConfigProvider.cs index 0390f667..d26816d3 100644 --- a/IPA.Loader/Config/IConfigProvider.cs +++ b/IPA.Loader/Config/IConfigProvider.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// ReSharper disable UnusedMember.Global namespace IPA.Config { diff --git a/IPA.Loader/Config/IniFile.cs b/IPA.Loader/Config/IniFile.cs index c7926f05..3ba9300b 100644 --- a/IPA.Loader/Config/IniFile.cs +++ b/IPA.Loader/Config/IniFile.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -72,28 +70,28 @@ namespace IPA.Config /// /// Write Data to the INI File /// - /// + /// /// Section name - /// + /// /// Key Name - /// + /// /// Value Name - public void IniWriteValue(string Section, string Key, string Value) + public void IniWriteValue(string section, string key, string value) { - WritePrivateProfileString(Section, Key, Value, IniFileInfo.FullName); + WritePrivateProfileString(section, key, value, IniFileInfo.FullName); } /// /// Read Data Value From the Ini File /// - /// - /// + /// + /// /// - public string IniReadValue(string Section, string Key) + public string IniReadValue(string section, string key) { - const int MAX_CHARS = 1023; - StringBuilder result = new StringBuilder(MAX_CHARS); - GetPrivateProfileString(Section, Key, "", result, MAX_CHARS, IniFileInfo.FullName); + const int maxChars = 1023; + StringBuilder result = new StringBuilder(maxChars); + GetPrivateProfileString(section, key, "", result, maxChars, IniFileInfo.FullName); return result.ToString(); } } diff --git a/IPA.Loader/Config/ModPrefs.cs b/IPA.Loader/Config/ModPrefs.cs index cdae6aac..709dbb6e 100644 --- a/IPA.Loader/Config/ModPrefs.cs +++ b/IPA.Loader/Config/ModPrefs.cs @@ -1,9 +1,8 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; -using System.Reflection; -using System.Text; namespace IPA.Config { @@ -85,43 +84,37 @@ namespace IPA.Config void SetBool(string section, string name, bool value); } + /// /// /// Allows to get and set preferences for your mod. /// public class ModPrefs : IModPrefs { - private static ModPrefs _staticInstance = null; - private static IModPrefs StaticInstace - { - get - { - if (_staticInstance == null) - _staticInstance = new ModPrefs(); - return _staticInstance; - } - } + private static ModPrefs _staticInstance; + private static IModPrefs StaticInstance => _staticInstance ?? (_staticInstance = new ModPrefs()); - internal static Dictionary ModPrefses { get; set; } = new Dictionary(); + // ReSharper disable once IdentifierTypo + internal static Dictionary ModPrefss { get; set; } = new Dictionary(); - private IniFile Instance; + private readonly IniFile _instance; /// /// Constructs a ModPrefs object for the provide plugin. /// /// the plugin to get the preferences file for public ModPrefs(IBeatSaberPlugin plugin) { - Instance = new IniFile(Path.Combine(Environment.CurrentDirectory, "UserData", "ModPrefs", $"{plugin.Name}.ini")); - ModPrefses.Add(plugin, this); + _instance = new IniFile(Path.Combine(Environment.CurrentDirectory, "UserData", "ModPrefs", $"{plugin.Name}.ini")); + ModPrefss.Add(plugin, this); } private ModPrefs() { - Instance = new IniFile(Path.Combine(Environment.CurrentDirectory, "UserData", "modprefs.ini")); + _instance = new IniFile(Path.Combine(Environment.CurrentDirectory, "UserData", "modprefs.ini")); } string IModPrefs.GetString(string section, string name, string defaultValue, bool autoSave) { - var value = Instance.IniReadValue(section, name); + var value = _instance.IniReadValue(section, name); if (value != "") return value; else if (autoSave) @@ -138,11 +131,11 @@ namespace IPA.Config /// Whether or not the default value should be written if no value is found. /// public static string GetString(string section, string name, string defaultValue = "", bool autoSave = false) - => StaticInstace.GetString(section, name, defaultValue, autoSave); + => StaticInstance.GetString(section, name, defaultValue, autoSave); int IModPrefs.GetInt(string section, string name, int defaultValue, bool autoSave) { - if (int.TryParse(Instance.IniReadValue(section, name), out var value)) + if (int.TryParse(_instance.IniReadValue(section, name), out var value)) return value; else if (autoSave) (this as IModPrefs).SetInt(section, name, defaultValue); @@ -158,11 +151,11 @@ namespace IPA.Config /// Whether or not the default value should be written if no value is found. /// public static int GetInt(string section, string name, int defaultValue = 0, bool autoSave = false) - => StaticInstace.GetInt(section, name, defaultValue, autoSave); + => StaticInstance.GetInt(section, name, defaultValue, autoSave); float IModPrefs.GetFloat(string section, string name, float defaultValue, bool autoSave) { - if (float.TryParse(Instance.IniReadValue(section, name), out var value)) + if (float.TryParse(_instance.IniReadValue(section, name), out var value)) return value; else if (autoSave) (this as IModPrefs).SetFloat(section, name, defaultValue); @@ -178,7 +171,7 @@ namespace IPA.Config /// Whether or not the default value should be written if no value is found. /// public static float GetFloat(string section, string name, float defaultValue = 0f, bool autoSave = false) - => StaticInstace.GetFloat(section, name, defaultValue, autoSave); + => StaticInstance.GetFloat(section, name, defaultValue, autoSave); bool IModPrefs.GetBool(string section, string name, bool defaultValue, bool autoSave) { @@ -203,11 +196,11 @@ namespace IPA.Config /// Whether or not the default value should be written if no value is found. /// public static bool GetBool(string section, string name, bool defaultValue = false, bool autoSave = false) - => StaticInstace.GetBool(section, name, defaultValue, autoSave); + => StaticInstance.GetBool(section, name, defaultValue, autoSave); bool IModPrefs.HasKey(string section, string name) { - return Instance.IniReadValue(section, name) != null; + return _instance.IniReadValue(section, name) != null; } /// /// Checks whether or not a key exists in the ini. @@ -215,11 +208,11 @@ namespace IPA.Config /// Section of the key. /// Name of the key. /// - public static bool HasKey(string section, string name) => StaticInstace.HasKey(section, name); + public static bool HasKey(string section, string name) => StaticInstance.HasKey(section, name); void IModPrefs.SetFloat(string section, string name, float value) { - Instance.IniWriteValue(section, name, value.ToString()); + _instance.IniWriteValue(section, name, value.ToString(CultureInfo.InvariantCulture)); } /// /// Sets a float in the ini. @@ -228,11 +221,11 @@ namespace IPA.Config /// Name of the key. /// Value that should be written. public static void SetFloat(string section, string name, float value) - => StaticInstace.SetFloat(section, name, value); + => StaticInstance.SetFloat(section, name, value); void IModPrefs.SetInt(string section, string name, int value) { - Instance.IniWriteValue(section, name, value.ToString()); + _instance.IniWriteValue(section, name, value.ToString()); } /// /// Sets an int in the ini. @@ -241,11 +234,11 @@ namespace IPA.Config /// Name of the key. /// Value that should be written. public static void SetInt(string section, string name, int value) - => StaticInstace.SetInt(section, name, value); + => StaticInstance.SetInt(section, name, value); void IModPrefs.SetString(string section, string name, string value) { - Instance.IniWriteValue(section, name, value); + _instance.IniWriteValue(section, name, value); } /// /// Sets a string in the ini. @@ -254,11 +247,11 @@ namespace IPA.Config /// Name of the key. /// Value that should be written. public static void SetString(string section, string name, string value) - => StaticInstace.SetString(section, name, value); + => StaticInstance.SetString(section, name, value); void IModPrefs.SetBool(string section, string name, bool value) { - Instance.IniWriteValue(section, name, value ? "1" : "0"); + _instance.IniWriteValue(section, name, value ? "1" : "0"); } /// /// Sets a bool in the ini. @@ -267,7 +260,7 @@ namespace IPA.Config /// Name of the key. /// Value that should be written. public static void SetBool(string section, string name, bool value) - => StaticInstace.SetBool(section, name, value); + => StaticInstance.SetBool(section, name, value); } /// @@ -280,7 +273,7 @@ namespace IPA.Config /// the plugin wanting the prefrences /// the ModPrefs object public static IModPrefs GetModPrefs(this IBeatSaberPlugin plugin) { - return ModPrefs.ModPrefses.First(o => o.Key == plugin).Value; + return ModPrefs.ModPrefss.First(o => o.Key == plugin).Value; } } } diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj index f77c4b7d..eeadb740 100644 --- a/IPA.Loader/IPA.Loader.csproj +++ b/IPA.Loader/IPA.Loader.csproj @@ -70,7 +70,7 @@ - + @@ -86,9 +86,8 @@ - - - + + @@ -107,7 +106,6 @@ 1.2.0 - - + \ No newline at end of file diff --git a/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs b/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs index 62b499d8..af63294a 100644 --- a/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs +++ b/IPA.Loader/Loader/Composite/CompositeBSPlugin.cs @@ -1,9 +1,5 @@ -using IPA; -using System; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; using UnityEngine.SceneManagement; using Logger = IPA.Logging.Logger; @@ -11,7 +7,7 @@ namespace IPA.Loader.Composite { internal class CompositeBSPlugin : IBeatSaberPlugin { - IEnumerable plugins; + private readonly IEnumerable plugins; private delegate void CompositeCall(IBeatSaberPlugin plugin); @@ -83,14 +79,12 @@ namespace IPA.Loader.Composite public string Version => throw new NotImplementedException(); - public Uri UpdateUri => throw new NotImplementedException(); - public ModsaberModInfo ModInfo => throw new NotImplementedException(); public void OnLateUpdate() { Invoke(plugin => { - if (plugin is IEnhancedBeatSaberPlugin) - ((IEnhancedBeatSaberPlugin) plugin).OnLateUpdate(); + if (plugin is IEnhancedBeatSaberPlugin saberPlugin) + saberPlugin.OnLateUpdate(); }); } } diff --git a/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs b/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs index 0bd25d3d..b254aa52 100644 --- a/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs +++ b/IPA.Loader/Loader/Composite/CompositeIPAPlugin.cs @@ -1,11 +1,6 @@ -using System; +using IPA.Old; +using System; using System.Collections.Generic; -using IPA; -using IPA.Old; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.SceneManagement; using Logger = IPA.Logging.Logger; namespace IPA.Loader.Composite @@ -13,7 +8,7 @@ namespace IPA.Loader.Composite #pragma warning disable CS0618 // Type or member is obsolete internal class CompositeIPAPlugin : IPlugin { - IEnumerable plugins; + private readonly IEnumerable plugins; private delegate void CompositeCall(IPlugin plugin); @@ -48,18 +43,14 @@ namespace IPA.Loader.Composite Invoke(plugin => plugin.OnFixedUpdate()); } - public string Name { - get { throw new NotImplementedException(); } - } + public string Name => throw new NotImplementedException(); - public string Version { - get { throw new NotImplementedException(); } - } + public string Version => throw new NotImplementedException(); public void OnLateUpdate() { Invoke(plugin => { - if (plugin is IEnhancedBeatSaberPlugin) - ((IEnhancedBeatSaberPlugin) plugin).OnLateUpdate(); + if (plugin is IEnhancedPlugin saberPlugin) + saberPlugin.OnLateUpdate(); }); } diff --git a/IPA.Loader/Loader/PluginComponent.cs b/IPA.Loader/Loader/PluginComponent.cs index f4915662..d0e1b36a 100644 --- a/IPA.Loader/Loader/PluginComponent.cs +++ b/IPA.Loader/Loader/PluginComponent.cs @@ -1,19 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Text; +using IPA.Loader.Composite; +using System; +using System.Diagnostics.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; -using IPA.Loader; -using IPA.Loader.Composite; -using IPA.Logging; +// ReSharper disable UnusedMember.Local namespace IPA.Loader { + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] internal class PluginComponent : MonoBehaviour { private CompositeBSPlugin bsPlugins; private CompositeIPAPlugin ipaPlugins; - private bool quitting = false; + private bool quitting; internal static PluginComponent Create() { @@ -29,7 +28,7 @@ namespace IPA.Loader ipaPlugins = new CompositeIPAPlugin(PluginManager.Plugins); #pragma warning restore CS0618 // Type or member is obsolete - gameObject.AddComponent(); + gameObject.AddComponent(); bsPlugins.OnApplicationStart(); ipaPlugins.OnApplicationStart(); diff --git a/IPA.Loader/Loader/PluginManager.cs b/IPA.Loader/Loader/PluginManager.cs index 64f6872c..b8c2e6b9 100644 --- a/IPA.Loader/Loader/PluginManager.cs +++ b/IPA.Loader/Loader/PluginManager.cs @@ -1,22 +1,20 @@ -using IPA; -using IPA.Config; -using IPA.Config.ConfigProviders; -using IPA.Logging; -using IPA.Old; -using IPA.Updating; -using IPA.Utilities; -using Mono.Cecil; -using System; +using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using System.Threading.Tasks; +using IPA.Config; +using IPA.Config.ConfigProviders; +using IPA.Logging; +using IPA.Old; +using IPA.Updating; +using IPA.Utilities; +using Mono.Cecil; +using UnityEngine; +using Logger = IPA.Logging.Logger; namespace IPA.Loader { @@ -35,9 +33,9 @@ namespace IPA.Loader internal IBeatSaberPlugin Plugin { get; set; } internal string Filename { get; set; } /// - /// The Modsaber updating info for the mod, or null. + /// The ModSaber updating info for the mod, or null. /// - public ModsaberModInfo ModsaberInfo { get; internal set; } + public ModsaberModInfo ModSaberInfo { get; internal set; } } /// @@ -51,10 +49,10 @@ namespace IPA.Loader { LoadPlugins(); } - return _bsPlugins.Select(p => p.Plugin); + return (_bsPlugins ?? throw new InvalidOperationException()).Select(p => p.Plugin); } } - private static List _bsPlugins = null; + private static List _bsPlugins; internal static IEnumerable BSMetas { get @@ -74,17 +72,17 @@ namespace IPA.Loader /// the plugin info for the requested plugin or null public static PluginInfo GetPlugin(string name) { - return BSMetas.Where(p => p.Plugin.Name == name).FirstOrDefault(); + return BSMetas.FirstOrDefault(p => p.Plugin.Name == name); } /// - /// Gets info about the plugin with the specified modsaber name. + /// Gets info about the plugin with the specified ModSaber name. /// - /// the modsaber name of the plugin to get (must be an exact match) + /// the ModSaber name of the plugin to get (must be an exact match) /// the plugin info for the requested plugin or null - public static PluginInfo GetPluginFromModsaberName(string name) + public static PluginInfo GetPluginFromModSaberName(string name) { - return BSMetas.Where(p => p.ModsaberInfo.InternalName == name).FirstOrDefault(); + return BSMetas.FirstOrDefault(p => p.ModSaberInfo.InternalName == name); } /// @@ -102,11 +100,11 @@ namespace IPA.Loader return _ipaPlugins; } } - private static List _ipaPlugins = null; + private static List _ipaPlugins; - internal static IConfigProvider SelfConfigProvider { get; set; } = null; + internal static IConfigProvider SelfConfigProvider { get; set; } - internal static List>> configProviders = new List>>(); + internal static readonly List>> configProviders = new List>>(); private static void LoadPlugins() { @@ -175,7 +173,7 @@ namespace IPA.Loader if (@ref.FullName == "IllusionInjector.Updating.Backup.BackupUnit") @ref.Namespace = "IPA.Updating.Backup"; //@ref.Name = ""; if (@ref.Namespace == "IllusionInjector.Utilities") @ref.Namespace = "IPA.Utilities"; //@ref.Name = ""; if (@ref.Namespace == "IllusionInjector.Logging.Printers") @ref.Namespace = "IPA.Logging.Printers"; //@ref.Name = ""; - if (@ref.Namespace == "IllusionInjector.Updating.ModsaberML") @ref.Namespace = "IPA.Updating.ModsaberML"; //@ref.Name = ""; + if (@ref.Namespace == "IllusionInjector.Updating.ModsaberML") @ref.Namespace = "IPA.Updating.ModSaber"; //@ref.Name = ""; } module.Write(pluginCopy); @@ -187,11 +185,11 @@ namespace IPA.Loader Filename = Path.Combine(Environment.CurrentDirectory, "IPA.exe"), Plugin = SelfPlugin.Instance }; - selfPlugin.ModsaberInfo = selfPlugin.Plugin.ModInfo; + selfPlugin.ModSaberInfo = selfPlugin.Plugin.ModInfo; _bsPlugins.Add(selfPlugin); - configProviders.Add(new KeyValuePair>(SelfConfigProvider = new JsonConfigProvider() { Filename = Path.Combine("UserData", SelfPlugin.IPA_Name) }, new Ref(SelfConfigProvider.LastModified))); + configProviders.Add(new KeyValuePair>(SelfConfigProvider = new JsonConfigProvider { Filename = Path.Combine("UserData", SelfPlugin.IPA_Name) }, new Ref(SelfConfigProvider.LastModified))); SelfConfigProvider.Load(); //Load copied plugins @@ -204,7 +202,7 @@ namespace IPA.Loader } Logger.log.Info(exeName); - Logger.log.Info($"Running on Unity {UnityEngine.Application.unityVersion}"); + Logger.log.Info($"Running on Unity {Application.unityVersion}"); Logger.log.Info($"Game version {BeatSaber.GameVersion}"); Logger.log.Info("-----------------------------"); Logger.log.Info($"Loading plugins from {LoneFunctions.GetRelativePath(pluginDirectory, Environment.CurrentDirectory)} and found {_bsPlugins.Count + _ipaPlugins.Count}"); @@ -294,7 +292,7 @@ namespace IPA.Loader { if (cfgProvider == null) { - cfgProvider = new JsonConfigProvider() { Filename = Path.Combine("UserData", $"{bsPlugin.Name}") }; + cfgProvider = new JsonConfigProvider { Filename = Path.Combine("UserData", $"{bsPlugin.Name}") }; configProviders.Add(new KeyValuePair>(cfgProvider, new Ref(cfgProvider.LastModified))); cfgProvider.Load(); } @@ -311,12 +309,12 @@ namespace IPA.Loader { Plugin = bsPlugin, Filename = file.Replace("\\.cache", ""), // quick and dirty fix - ModsaberInfo = bsPlugin.ModInfo + ModSaberInfo = bsPlugin.ModInfo }); } catch (AmbiguousMatchException) { - Logger.loader.Error($"Only one Init allowed per plugin"); + Logger.loader.Error("Only one Init allowed per plugin"); } } else diff --git a/IPA.Loader/Logging/LogPrinter.cs b/IPA.Loader/Logging/LogPrinter.cs index 3458cb61..2c82e9f6 100644 --- a/IPA.Loader/Logging/LogPrinter.cs +++ b/IPA.Loader/Logging/LogPrinter.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IPA.Logging { diff --git a/IPA.Loader/Logging/Logger.cs b/IPA.Loader/Logging/Logger.cs index 180b9f5a..88bf432c 100644 --- a/IPA.Loader/Logging/Logger.cs +++ b/IPA.Loader/Logging/Logger.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// ReSharper disable InconsistentNaming namespace IPA.Logging { @@ -25,7 +22,7 @@ namespace IPA.Logging internal static Logger libLoader => log.GetChildLogger("LibraryLoader"); internal static Logger loader => log.GetChildLogger("Loader"); internal static Logger config => log.GetChildLogger("Config"); - internal static bool LogCreated => _log != null || UnityLogInterceptor._logger != null; + internal static bool LogCreated => _log != null || UnityLogInterceptor.Logger != null; /// /// The standard format for log messages. diff --git a/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs b/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs index ab6fa4e3..39e6b22f 100644 --- a/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs +++ b/IPA.Loader/Logging/Printers/ColoredConsolePrinter.cs @@ -1,10 +1,4 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using IPA.Logging; namespace IPA.Logging.Printers { @@ -35,8 +29,8 @@ namespace IPA.Logging.Printers { if (((byte)level & (byte)StandardLogger.PrintFilter) == 0) return; Console.ForegroundColor = Color; - foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - Console.WriteLine(string.Format(Logger.LogFormat, line, logName, time, level.ToString().ToUpper())); + foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) + Console.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper()); Console.ResetColor(); } } diff --git a/IPA.Loader/Logging/Printers/GZFilePrinter.cs b/IPA.Loader/Logging/Printers/GZFilePrinter.cs index 7761f852..eb25ff56 100644 --- a/IPA.Loader/Logging/Printers/GZFilePrinter.cs +++ b/IPA.Loader/Logging/Printers/GZFilePrinter.cs @@ -1,12 +1,8 @@ -using IPA.Logging; -using Ionic.Zlib; +using Ionic.Zlib; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Runtime.InteropServices; using System.Text; -using System.Threading.Tasks; namespace IPA.Logging.Printers { @@ -26,7 +22,7 @@ namespace IPA.Logging.Printers /// /// The that writes to the GZip file. /// - protected StreamWriter fileWriter; + protected StreamWriter FileWriter; private GZipStream zstream; private FileStream fstream; @@ -47,7 +43,7 @@ namespace IPA.Logging.Printers fileInfo = new FileInfo(fileInfo.FullName + ".gz"); fileInfo.Create().Close(); - var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName, $"latest{ext}.gz")); + var symlink = new FileInfo(Path.Combine(fileInfo.DirectoryName ?? throw new InvalidOperationException(), $"latest{ext}.gz")); if (symlink.Exists) symlink.Delete(); try @@ -75,7 +71,7 @@ namespace IPA.Logging.Printers /// /// Called at the start of any print session. /// - public override sealed void StartPrint() + public sealed override void StartPrint() { InitLog(); @@ -84,21 +80,21 @@ namespace IPA.Logging.Printers { FlushMode = FlushType.Full }; - fileWriter = new StreamWriter(zstream, new UTF8Encoding(false)); + FileWriter = new StreamWriter(zstream, new UTF8Encoding(false)); } /// /// Called at the end of any print session. /// - public override sealed void EndPrint() + public sealed override void EndPrint() { - fileWriter.Flush(); + FileWriter.Flush(); zstream.Flush(); fstream.Flush(); - fileWriter.Close(); + FileWriter.Close(); zstream.Close(); fstream.Close(); - fileWriter.Dispose(); + FileWriter.Dispose(); zstream.Dispose(); fstream.Dispose(); } @@ -120,13 +116,13 @@ namespace IPA.Logging.Printers { if (disposing) { - fileWriter.Flush(); + FileWriter.Flush(); zstream.Flush(); fstream.Flush(); - fileWriter.Close(); + FileWriter.Close(); zstream.Close(); fstream.Close(); - fileWriter.Dispose(); + FileWriter.Dispose(); zstream.Dispose(); fstream.Dispose(); } diff --git a/IPA.Loader/Logging/Printers/GlobalLogFilePrinter.cs b/IPA.Loader/Logging/Printers/GlobalLogFilePrinter.cs index f8e67e7d..fffcb27d 100644 --- a/IPA.Loader/Logging/Printers/GlobalLogFilePrinter.cs +++ b/IPA.Loader/Logging/Printers/GlobalLogFilePrinter.cs @@ -1,10 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using IPA.Logging; namespace IPA.Logging.Printers { @@ -27,8 +22,8 @@ namespace IPA.Logging.Printers /// the message to print public override void Print(Logger.Level level, DateTime time, string logName, string message) { - foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - fileWriter.WriteLine(string.Format(Logger.LogFormat, line, logName, time, level.ToString().ToUpper())); + foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) + FileWriter.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper()); } /// diff --git a/IPA.Loader/Logging/Printers/PluginLogFilePrinter.cs b/IPA.Loader/Logging/Printers/PluginLogFilePrinter.cs index 6665f7da..bae0d762 100644 --- a/IPA.Loader/Logging/Printers/PluginLogFilePrinter.cs +++ b/IPA.Loader/Logging/Printers/PluginLogFilePrinter.cs @@ -1,10 +1,5 @@ -using IPA.Logging; -using System; -using System.Collections.Generic; +using System; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IPA.Logging.Printers { @@ -50,8 +45,8 @@ namespace IPA.Logging.Printers /// the message to print public override void Print(Logger.Level level, DateTime time, string logName, string message) { - foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - fileWriter.WriteLine(string.Format(Logger.LogFormat, line, logName, time, level.ToString().ToUpper())); + foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) + FileWriter.WriteLine(Logger.LogFormat, line, logName, time, level.ToString().ToUpper()); } } } diff --git a/IPA.Loader/Logging/Printers/PluginSubLogPrinter.cs b/IPA.Loader/Logging/Printers/PluginSubLogPrinter.cs index a3120ca3..d501c862 100644 --- a/IPA.Loader/Logging/Printers/PluginSubLogPrinter.cs +++ b/IPA.Loader/Logging/Printers/PluginSubLogPrinter.cs @@ -1,10 +1,5 @@ -using IPA.Logging; -using System; -using System.Collections.Generic; +using System; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IPA.Logging.Printers { @@ -53,8 +48,8 @@ namespace IPA.Logging.Printers /// the message to print public override void Print(Logger.Level level, DateTime time, string logName, string message) { - foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - fileWriter.WriteLine(string.Format("[{3} @ {2:HH:mm:ss}] {0}", line, logName, time, level.ToString().ToUpper())); + foreach (var line in message.Split(new[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) + FileWriter.WriteLine("[{2} @ {1:HH:mm:ss}] {0}", line, time, level.ToString().ToUpper()); } } } diff --git a/IPA.Loader/Logging/StandardLogger.cs b/IPA.Loader/Logging/StandardLogger.cs index d6e59c49..8bbb869c 100644 --- a/IPA.Loader/Logging/StandardLogger.cs +++ b/IPA.Loader/Logging/StandardLogger.cs @@ -1,20 +1,15 @@ -using IPA.Logging; +using IPA.Config; +using IPA.Logging.Printers; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; -using IPA; -using IPA.Logging.Printers; -using IPA.Config; namespace IPA.Logging { /// - /// The default implimentation. + /// The default implementation. /// public class StandardLogger : Logger { @@ -48,8 +43,8 @@ namespace IPA.Logging new GlobalLogFilePrinter() }; - private string logName; - private static readonly bool showSourceClass = true; + private readonly string logName; + private static readonly bool showSourceClass; /// /// All levels defined by this filter will be sent to loggers. All others will be ignored. /// @@ -122,32 +117,33 @@ namespace IPA.Logging { _logQueue.Add(new LogMessage { - level = level, - message = message, - logger = this, - time = DateTime.Now + Level = level, + Message = message, + Logger = this, + Time = DateTime.Now }); } + /// /// - /// An override to which shows the method that called it. + /// An override to which shows the method that called it. /// /// the message to log public override void Debug(string message) - { // add source to message - var stfm = new StackTrace().GetFrame(1).GetMethod(); - if (showSourceClass) - base.Debug($"{{{stfm.DeclaringType.FullName}::{stfm.Name}}} {message}"); - else - base.Debug(message); + { + // add source to message + var stackFrame = new StackTrace().GetFrame(1).GetMethod(); + base.Debug(showSourceClass + ? $"{{{stackFrame.DeclaringType?.FullName}::{stackFrame.Name}}} {message}" + : message); } - internal struct LogMessage + private struct LogMessage { - public Level level; - public StandardLogger logger; - public string message; - public DateTime time; + public Level Level; + public StandardLogger Logger; + public string Message; + public DateTime Time; } private static BlockingCollection _logQueue = new BlockingCollection(); @@ -157,11 +153,11 @@ namespace IPA.Logging { HashSet started = new HashSet(); while (_logQueue.TryTake(out LogMessage msg, Timeout.Infinite)) { - foreach (var printer in msg.logger.printers) + foreach (var printer in msg.Logger.printers) { try { - if (((byte)msg.level & (byte)printer.Filter) != 0) + if (((byte)msg.Level & (byte)printer.Filter) != 0) { if (!started.Contains(printer)) { @@ -169,7 +165,7 @@ namespace IPA.Logging started.Add(printer); } - printer.Print(msg.level, msg.time, msg.logger.logName, msg.message); + printer.Print(msg.Level, msg.Time, msg.Logger.logName, msg.Message); } } catch (Exception e) diff --git a/IPA.Loader/Logging/UnityLogInterceptor.cs b/IPA.Loader/Logging/UnityLogInterceptor.cs index 6b9d0fe3..3f36918f 100644 --- a/IPA.Loader/Logging/UnityLogInterceptor.cs +++ b/IPA.Loader/Logging/UnityLogInterceptor.cs @@ -1,23 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine; +using UnityEngine; namespace IPA.Logging { - internal class UnityLogInterceptor + internal static class UnityLogInterceptor { - internal static Logger _logger; - public static Logger UnityLogger { - get - { - if (_logger == null) - _logger = new StandardLogger("UnityEngine"); - return _logger; - } - } + internal static Logger Logger; + public static Logger UnityLogger => Logger ?? (Logger = new StandardLogger("UnityEngine")); public static Logger.Level LogTypeToLevel(LogType type) { diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs index 48dba55a..cbf40917 100644 --- a/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs +++ b/IPA.Loader/PluginInterfaces/BeatSaber/IBeatSaberPlugin.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine.SceneManagement; +using UnityEngine.SceneManagement; +// ReSharper disable CheckNamespace namespace IPA { @@ -23,7 +21,7 @@ namespace IPA string Version { get; } /// - /// Gets the info for the Modsaber release of this plugin. Return null if there is no Modsaber release. + /// Gets the info for the ModSaber release of this plugin. Return null if there is no ModSaber release. /// ModsaberModInfo ModInfo { get; } diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs b/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs index 3a31ef13..da67e31d 100644 --- a/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs +++ b/IPA.Loader/PluginInterfaces/BeatSaber/IEnhancedBeatSaberPlugin.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Text; - +// ReSharper disable CheckNamespace namespace IPA { + /// /// /// An enhanced version of a standard BeatSaber plugin. /// diff --git a/IPA.Loader/PluginInterfaces/BeatSaber/ModsaberModInfo.cs b/IPA.Loader/PluginInterfaces/BeatSaber/ModsaberModInfo.cs index a1c19fe5..dc4f8989 100644 --- a/IPA.Loader/PluginInterfaces/BeatSaber/ModsaberModInfo.cs +++ b/IPA.Loader/PluginInterfaces/BeatSaber/ModsaberModInfo.cs @@ -1,14 +1,12 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// ReSharper disable CheckNamespace namespace IPA { /// /// A class to provide information about a mod on ModSaber.ML /// + // ReSharper disable once IdentifierTypo public class ModsaberModInfo { /// @@ -16,12 +14,12 @@ namespace IPA /// public string InternalName { - get => _InternalName; + get => _internalName; set { - if (_InternalName == null) + if (_internalName == null) { - _InternalName = value; + _internalName = value; } else { @@ -29,19 +27,19 @@ namespace IPA } } } - private string _InternalName = null; + private string _internalName; /// /// The version of the currently installed mod. Used to compare to the version on ModSaber. Should be a valid SemVer version. /// public string CurrentVersion { - get => _CurrentVersion; + get => _currentVersion; set { - if (_CurrentVersion == null) + if (_currentVersion == null) { - _CurrentVersion = value; + _currentVersion = value; } else { @@ -49,6 +47,6 @@ namespace IPA } } } - private string _CurrentVersion = null; + private string _currentVersion; } } diff --git a/IPA.Loader/PluginInterfaces/IGenericEnhancedPlugin.cs b/IPA.Loader/PluginInterfaces/IGenericEnhancedPlugin.cs index b3c9a935..027c3e1f 100644 --- a/IPA.Loader/PluginInterfaces/IGenericEnhancedPlugin.cs +++ b/IPA.Loader/PluginInterfaces/IGenericEnhancedPlugin.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +// ReSharper disable CheckNamespace namespace IPA { /// @@ -12,7 +7,7 @@ namespace IPA public interface IGenericEnhancedPlugin { /// - /// Gets a list of executables this plugin should be excuted on (without the file ending) + /// Gets a list of executables this plugin should be executed on (without the file ending) /// /// { "PlayClub", "PlayClubStudio" } string[] Filter { get; } diff --git a/IPA.Loader/PluginInterfaces/IPA/IEnhancedPlugin.cs b/IPA.Loader/PluginInterfaces/IPA/IEnhancedPlugin.cs index 91c0e42e..054f0933 100644 --- a/IPA.Loader/PluginInterfaces/IPA/IEnhancedPlugin.cs +++ b/IPA.Loader/PluginInterfaces/IPA/IEnhancedPlugin.cs @@ -1,9 +1,9 @@ using System; -using System.Collections.Generic; -using System.Text; +// ReSharper disable CheckNamespace namespace IPA.Old { + /// /// /// An enhanced version of the standard IPA plugin. /// diff --git a/IPA.Loader/PluginInterfaces/IPA/IPlugin.cs b/IPA.Loader/PluginInterfaces/IPA/IPlugin.cs index fe9adba2..d3d7e17f 100644 --- a/IPA.Loader/PluginInterfaces/IPA/IPlugin.cs +++ b/IPA.Loader/PluginInterfaces/IPA/IPlugin.cs @@ -1,6 +1,5 @@ using System; -using System.Collections.Generic; -using System.Text; +// ReSharper disable CheckNamespace namespace IPA.Old { diff --git a/IPA.Loader/Updating/Backup/BackupUnit.cs b/IPA.Loader/Updating/Backup/BackupUnit.cs deleted file mode 100644 index f5b8f2e7..00000000 --- a/IPA.Loader/Updating/Backup/BackupUnit.cs +++ /dev/null @@ -1,147 +0,0 @@ -using IPA.Logging; -using IPA.Utilities; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Text; - -namespace IPA.Updating.Backup -{ - /// - /// A unit for backup. WIP. - /// - internal class BackupUnit - { - public string Name { get; private set; } - - private DirectoryInfo _BackupPath; - private List _Files = new List(); - private FileInfo _ManifestFile; - private static string _ManifestFileName = "$manifest$.txt"; - - public BackupUnit(string path) : this(path, DateTime.Now.ToString("yyyy-MM-dd_h-mm-ss")) - { - } - - internal BackupUnit(string path, string name) - { - Name = name; - _BackupPath = new DirectoryInfo(Path.Combine(path, Name)); - _ManifestFile = new FileInfo(Path.Combine(_BackupPath.FullName, _ManifestFileName)); - } - - public static BackupUnit FromDirectory(DirectoryInfo directory, string backupPath) - { - var unit = new BackupUnit(backupPath, directory.Name); - - // Read Manifest - if (unit._ManifestFile.Exists) - { - string manifest = File.ReadAllText(unit._ManifestFile.FullName); - foreach (var line in manifest.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - unit._Files.Add(line); - } - else - { - foreach (var file in directory.GetFiles("*", SearchOption.AllDirectories)) - { - if (file.Name == _ManifestFileName) continue; - var relativePath = file.FullName.Substring(directory.FullName.Length + 1); - unit._Files.Add(relativePath); - } - } - - return unit; - } - - public void Add(string file) - { - Add(new FileInfo(file)); - } - - internal void Delete() - { - if (_BackupPath.Exists) - _BackupPath.Delete(true); - } - - /// - /// Adds a file to the list of changed files and backups it. - /// - /// - public void Add(FileInfo file) - { - var relativePath = LoneFunctions.GetRelativePath(file.FullName, Environment.CurrentDirectory); - var backupPath = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath)); - - Logger.updater.Debug($"rp={relativePath}, bp={backupPath}"); - - if (_Files.Contains(relativePath)) - { - Logger.updater.Debug($"Skipping backup of {relativePath}"); - return; - } - - // Copy over - backupPath.Directory.Create(); - if (file.Exists) - { - file.CopyTo(backupPath.FullName); - } - else - { - // Make empty file - backupPath.Create().Close(); - } - - if (!File.Exists(_ManifestFile.FullName)) - _ManifestFile.Create().Close(); - var stream = _ManifestFile.AppendText(); - stream.WriteLine(relativePath); - stream.Close(); - - // Add to list - _Files.Add(relativePath); - } - - /// - /// Reverts the changes made in this unit. - /// - public void Restore() - { - foreach (var relativePath in _Files) - { - Logger.updater.Debug($"Restoring {relativePath}"); - // Original version - var backupFile = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath)); - var target = new FileInfo(Path.Combine(Environment.CurrentDirectory, relativePath)); - - if (backupFile.Exists) - { - if (backupFile.Length > 0) - { - Logger.updater.Debug($" {backupFile.FullName} => {target.FullName}"); - target.Directory.Create(); - backupFile.CopyTo(target.FullName, true); - } - else - { - Logger.updater.Debug($" x {target.FullName}"); - if (target.Exists) - { - target.Delete(); - } - } - } - else - { - Logger.updater.Error("Backup not found!"); - } - } - } - - - } -} diff --git a/IPA.Loader/Updating/Converters/ModsaberDependencyConverter.cs b/IPA.Loader/Updating/Converters/ModsaberDependencyConverter.cs index 43da9f89..f5415d3c 100644 --- a/IPA.Loader/Updating/Converters/ModsaberDependencyConverter.cs +++ b/IPA.Loader/Updating/Converters/ModsaberDependencyConverter.cs @@ -1,29 +1,25 @@ -using IPA.Updating.ModsaberML; +using System; using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using static IPA.Updating.ModsaberML.ApiEndpoint.Mod; +using SemVer; +using static IPA.Updating.ModSaber.ApiEndpoint.Mod; namespace IPA.Updating.Converters { - internal class ModsaberDependencyConverter : JsonConverter + internal class ModSaberDependencyConverter : JsonConverter { public override Dependency ReadJson(JsonReader reader, Type objectType, Dependency existingValue, bool hasExistingValue, JsonSerializer serializer) { - var parts = (reader.Value as string).Split('@'); - return new Dependency() + var parts = (reader.Value as string)?.Split('@'); + return new Dependency { - Name = parts[0], - VersionRange = new SemVer.Range(parts[1]) + Name = parts?[0], + VersionRange = new Range(parts?[1]) }; } public override void WriteJson(JsonWriter writer, Dependency value, JsonSerializer serializer) { - writer.WriteValue($"{value.Name}@{value.VersionRange.ToString()}"); + writer.WriteValue($"{value.Name}@{value.VersionRange}"); } } } diff --git a/IPA.Loader/Updating/Converters/SemverRangeConverter.cs b/IPA.Loader/Updating/Converters/SemverRangeConverter.cs index 46d2a8c2..08e837df 100644 --- a/IPA.Loader/Updating/Converters/SemverRangeConverter.cs +++ b/IPA.Loader/Updating/Converters/SemverRangeConverter.cs @@ -1,13 +1,11 @@ using Newtonsoft.Json; using SemVer; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; namespace IPA.Updating.Converters { + [SuppressMessage("ReSharper", "UnusedMember.Global")] internal class SemverRangeConverter : JsonConverter { public override Range ReadJson(JsonReader reader, Type objectType, Range existingValue, bool hasExistingValue, JsonSerializer serializer) => new Range(reader.Value as string); diff --git a/IPA.Loader/Updating/Converters/SemverVersionConverter.cs b/IPA.Loader/Updating/Converters/SemverVersionConverter.cs index 57804965..751a89ae 100644 --- a/IPA.Loader/Updating/Converters/SemverVersionConverter.cs +++ b/IPA.Loader/Updating/Converters/SemverVersionConverter.cs @@ -1,10 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using SemVer; +using Newtonsoft.Json; +using System; using Version = SemVer.Version; namespace IPA.Updating.Converters diff --git a/IPA.Loader/Updating/ModsaberML/ApiEndpoint.cs b/IPA.Loader/Updating/ModSaber/ApiEndpoint.cs similarity index 91% rename from IPA.Loader/Updating/ModsaberML/ApiEndpoint.cs rename to IPA.Loader/Updating/ModSaber/ApiEndpoint.cs index d723801f..b35b1970 100644 --- a/IPA.Loader/Updating/ModsaberML/ApiEndpoint.cs +++ b/IPA.Loader/Updating/ModSaber/ApiEndpoint.cs @@ -1,18 +1,13 @@ -using IPA.Logging; +using System; +using System.Collections.Generic; +using System.Linq; using IPA.Updating.Converters; using IPA.Utilities; using Newtonsoft.Json; -using Newtonsoft.Json.Converters; using SemVer; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Version = SemVer.Version; -namespace IPA.Updating.ModsaberML +namespace IPA.Updating.ModSaber { class ApiEndpoint { @@ -100,7 +95,7 @@ namespace IPA.Updating.ModsaberML public Dictionary FileHashes = new Dictionary(); [JsonProperty("url")] - public string DownloadPath = null; + public string DownloadPath; public override string ToString() { @@ -112,14 +107,14 @@ namespace IPA.Updating.ModsaberML public class FilesObject { [JsonProperty("steam")] - public PlatformFile Steam = null; + public PlatformFile Steam; [JsonProperty("oculus")] - public PlatformFile Oculus = null; + public PlatformFile Oculus; } [JsonProperty("files")] - public FilesObject Files = null; + public FilesObject Files; public class Dependency { @@ -127,10 +122,10 @@ namespace IPA.Updating.ModsaberML public Range VersionRange = null; } - [JsonProperty("dependsOn", ItemConverterType = typeof(ModsaberDependencyConverter))] + [JsonProperty("dependsOn", ItemConverterType = typeof(ModSaberDependencyConverter))] public Dependency[] Dependencies = new Dependency[0]; - [JsonProperty("conflictsWith", ItemConverterType = typeof(ModsaberDependencyConverter))] + [JsonProperty("conflictsWith", ItemConverterType = typeof(ModSaberDependencyConverter))] public Dependency[] Conflicts = new Dependency[0]; [JsonProperty("oldVersions", ItemConverterType = typeof(SemverVersionConverter))] diff --git a/IPA.Loader/Updating/ModsaberML/Updater.cs b/IPA.Loader/Updating/ModSaber/Updater.cs similarity index 84% rename from IPA.Loader/Updating/ModsaberML/Updater.cs rename to IPA.Loader/Updating/ModSaber/Updater.cs index 0ab9c9d3..5f4bc0db 100644 --- a/IPA.Loader/Updating/ModsaberML/Updater.cs +++ b/IPA.Loader/Updating/ModSaber/Updater.cs @@ -1,43 +1,40 @@ -using IPA.Utilities; -using IPA.Loader; -using Ionic.Zip; -using Newtonsoft.Json; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; +using System.Runtime.Serialization; using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Ionic.Zip; +using IPA.Utilities; +using Newtonsoft.Json; +using SemVer; using UnityEngine; using UnityEngine.Networking; -using SemVer; +using static IPA.Loader.PluginManager; using Logger = IPA.Logging.Logger; using Version = SemVer.Version; -using IPA.Updating.Backup; -using System.Runtime.Serialization; -using System.Reflection; -using static IPA.Loader.PluginManager; -namespace IPA.Updating.ModsaberML +namespace IPA.Updating.ModSaber { - class Updater : MonoBehaviour + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + internal class Updater : MonoBehaviour { - public static Updater instance; + public static Updater Instance; public void Awake() { try { - if (instance != null) + if (Instance != null) Destroy(this); else { - instance = this; + Instance = this; CheckForUpdates(); } } @@ -55,21 +52,21 @@ namespace IPA.Updating.ModsaberML private class DependencyObject { public string Name { get; set; } - public Version Version { get; set; } = null; - public Version ResolvedVersion { get; set; } = null; - public Range Requirement { get; set; } = null; - public Range Conflicts { get; set; } = null; - public bool Resolved { get; set; } = false; - public bool Has { get; set; } = false; + public Version Version { get; set; } + public Version ResolvedVersion { get; set; } + public Range Requirement { get; set; } + public Range Conflicts { get; set; } + public bool Resolved { get; set; } + public bool Has { get; set; } public HashSet Consumers { get; set; } = new HashSet(); - public bool MetaRequestFailed { get; set; } = false; + public bool MetaRequestFailed { get; set; } - public PluginInfo LocalPluginMeta { get; set; } = null; + public PluginInfo LocalPluginMeta { get; set; } public override string ToString() { - return $"{Name}@{Version}{(Resolved ? $" -> {ResolvedVersion}" : "")} - ({Requirement} ! {Conflicts}) {(Has ? $" Already have" : "")}"; + return $"{Name}@{Version}{(Resolved ? $" -> {ResolvedVersion}" : "")} - ({Requirement} ! {Conflicts}) {(Has ? " Already have" : "")}"; } } @@ -79,7 +76,6 @@ namespace IPA.Updating.ModsaberML if (requestCache.TryGetValue(url, out string value)) { result.Value = value; - yield break; } else { @@ -111,15 +107,14 @@ namespace IPA.Updating.ModsaberML } } - private Dictionary modCache = new Dictionary(); - private IEnumerator GetModInfo(string name, string ver, Ref result) + private readonly Dictionary modCache = new Dictionary(); + private IEnumerator GetModInfo(string modName, string ver, Ref result) { - var uri = string.Format(ApiEndpoint.GetModInfoEndpoint, Uri.EscapeUriString(name), Uri.EscapeUriString(ver)); + var uri = string.Format(ApiEndpoint.GetModInfoEndpoint, Uri.EscapeUriString(modName), Uri.EscapeUriString(ver)); if (modCache.TryGetValue(uri, out ApiEndpoint.Mod value)) { result.Value = value; - yield break; } else { @@ -136,20 +131,18 @@ namespace IPA.Updating.ModsaberML catch (Exception e) { result.Error = new Exception("Error decoding response", e); - yield break; } } } - private Dictionary> modVersionsCache = new Dictionary>(); - private IEnumerator GetModVersionsMatching(string name, string range, Ref> result) + private readonly Dictionary> modVersionsCache = new Dictionary>(); + private IEnumerator GetModVersionsMatching(string modName, string range, Ref> result) { - var uri = string.Format(ApiEndpoint.GetModsWithSemver, Uri.EscapeUriString(name), Uri.EscapeUriString(range)); + var uri = string.Format(ApiEndpoint.GetModsWithSemver, Uri.EscapeUriString(modName), Uri.EscapeUriString(range)); if (modVersionsCache.TryGetValue(uri, out List value)) { result.Value = value; - yield break; } else { @@ -166,7 +159,6 @@ namespace IPA.Updating.ModsaberML catch (Exception e) { result.Error = new Exception("Error decoding response", e); - yield break; } } } @@ -177,9 +169,9 @@ namespace IPA.Updating.ModsaberML foreach (var plugin in BSMetas) { // initialize with data to resolve (1.1) - if (plugin.ModsaberInfo != null) + if (plugin.ModSaberInfo != null) { // updatable - var msinfo = plugin.ModsaberInfo; + var msinfo = plugin.ModSaberInfo; depList.Value.Add(new DependencyObject { Name = msinfo.InternalName, Version = new Version(msinfo.CurrentVersion), @@ -190,17 +182,17 @@ namespace IPA.Updating.ModsaberML } foreach (var dep in depList.Value) - Logger.updater.Debug($"Phantom Dependency: {dep.ToString()}"); + Logger.updater.Debug($"Phantom Dependency: {dep}"); yield return DependencyResolveFirstPass(depList); foreach (var dep in depList.Value) - Logger.updater.Debug($"Dependency: {dep.ToString()}"); + Logger.updater.Debug($"Dependency: {dep}"); yield return DependencyResolveSecondPass(depList); foreach (var dep in depList.Value) - Logger.updater.Debug($"Dependency: {dep.ToString()}"); + Logger.updater.Debug($"Dependency: {dep}"); DependendyResolveFinalPass(depList); } @@ -226,8 +218,8 @@ namespace IPA.Updating.ModsaberML continue; } - list.Value.AddRange(mod.Value.Dependencies.Select(d => new DependencyObject { Name = d.Name, Requirement = d.VersionRange, Consumers = new HashSet() { dep.Name } })); - list.Value.AddRange(mod.Value.Conflicts.Select(d => new DependencyObject { Name = d.Name, Conflicts = d.VersionRange, Consumers = new HashSet() { dep.Name } })); + list.Value.AddRange(mod.Value.Dependencies.Select(d => new DependencyObject { Name = d.Name, Requirement = d.VersionRange, Consumers = new HashSet { dep.Name } })); + list.Value.AddRange(mod.Value.Conflicts.Select(d => new DependencyObject { Name = d.Name, Conflicts = d.VersionRange, Consumers = new HashSet { dep.Name } })); } var depNames = new HashSet(); @@ -290,6 +282,7 @@ namespace IPA.Updating.ModsaberML .Where(versionCheck => versionCheck.GameVersion == BeatSaber.GameVersion && versionCheck.Approved) .Where(conflictsCheck => dep.Conflicts == null || !dep.Conflicts.IsSatisfied(conflictsCheck.Version)) .Select(mod => mod.Version).Max(); // (2.1) + // ReSharper disable once AssignmentInConditionalExpression if (dep.Resolved = ver != null) dep.ResolvedVersion = ver; // (2.2) dep.Has = dep.Version == dep.ResolvedVersion && dep.Resolved; // dep.Version is only not null if its already installed } @@ -303,10 +296,10 @@ namespace IPA.Updating.ModsaberML { // figure out which ones need to be downloaded (3.1) if (dep.Resolved) { - Logger.updater.Debug($"Resolved: {dep.ToString()}"); + Logger.updater.Debug($"Resolved: {dep}"); if (!dep.Has) { - Logger.updater.Debug($"To Download: {dep.ToString()}"); + Logger.updater.Debug($"To Download: {dep}"); toDl.Add(dep); } } @@ -324,10 +317,10 @@ namespace IPA.Updating.ModsaberML Logger.updater.Debug($"Temp directory: {tempDirectory}"); foreach (var item in toDl) - StartCoroutine(UpdateModCoroutine(item, tempDirectory)); + StartCoroutine(UpdateModCoroutine(item)); } - private IEnumerator UpdateModCoroutine(DependencyObject item, string tempDirectory) + private IEnumerator UpdateModCoroutine(DependencyObject item) { // (3.2) Logger.updater.Debug($"Release: {BeatSaber.ReleaseType}"); @@ -351,12 +344,12 @@ namespace IPA.Updating.ModsaberML Logger.updater.Debug($"URL = {url}"); - const int MaxTries = 3; - int maxTries = MaxTries; - while (maxTries > 0) + const int maxTries = 3; + int tries = maxTries; + while (tries > 0) { - if (maxTries-- != MaxTries) - Logger.updater.Debug($"Re-trying download..."); + if (tries-- != maxTries) + Logger.updater.Debug("Re-trying download..."); using (var stream = new MemoryStream()) using (var request = UnityWebRequest.Get(url)) @@ -379,7 +372,7 @@ namespace IPA.Updating.ModsaberML } if (request.isHttpError) { - Logger.updater.Error($"Server returned an error code while trying to update mod"); + Logger.updater.Error("Server returned an error code while trying to update mod"); Logger.updater.Error(request.error); taskTokenSource.Cancel(); continue; @@ -388,16 +381,17 @@ namespace IPA.Updating.ModsaberML stream.Seek(0, SeekOrigin.Begin); // reset to beginning var downloadTask = Task.Run(() => - { // use slightly more multithreaded approach than coroutines - ExtractPluginAsync(stream, item, platformFile, tempDirectory); + { // use slightly more multi threaded approach than co-routines + // ReSharper disable once AccessToDisposedClosure + ExtractPluginAsync(stream, item, platformFile); }, taskTokenSource.Token); while (!(downloadTask.IsCompleted || downloadTask.IsCanceled || downloadTask.IsFaulted)) - yield return null; // pause coroutine until task is done + yield return null; // pause co-routine until task is done if (downloadTask.IsFaulted) { - if (downloadTask.Exception.InnerExceptions.Where(e => e is ModsaberInterceptException).Any()) + if (downloadTask.Exception != null && downloadTask.Exception.InnerExceptions.Any(e => e is ModsaberInterceptException)) { // any exception is an intercept exception Logger.updater.Error($"Modsaber did not return expected data for {item.Name}"); } @@ -411,8 +405,8 @@ namespace IPA.Updating.ModsaberML } } - if (maxTries == 0) - Logger.updater.Warn($"Plugin download failed {MaxTries} times, not re-trying"); + if (tries == 0) + Logger.updater.Warn($"Plugin download failed {maxTries} times, not re-trying"); else Logger.updater.Debug("Download complete"); } @@ -421,7 +415,7 @@ namespace IPA.Updating.ModsaberML { public MemoryStream Stream { get; set; } - public StreamDownloadHandler(MemoryStream stream) : base() + public StreamDownloadHandler(MemoryStream stream) { Stream = stream; } @@ -437,15 +431,15 @@ namespace IPA.Updating.ModsaberML Logger.updater.Debug("Download complete"); } - protected override bool ReceiveData(byte[] data, int dataLength) + protected override bool ReceiveData(byte[] rData, int dataLength) { - if (data == null || data.Length < 1) + if (rData == null || rData.Length < 1) { Logger.updater.Debug("CustomWebRequest :: ReceiveData - received a null/empty buffer"); return false; } - Stream.Write(data, 0, dataLength); + Stream.Write(rData, 0, dataLength); return true; } @@ -458,11 +452,11 @@ namespace IPA.Updating.ModsaberML public override string ToString() { - return $"{base.ToString()} ({Stream?.ToString()})"; + return $"{base.ToString()} ({Stream})"; } } - private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.PlatformFile fileInfo, string tempDirectory) + private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.PlatformFile fileInfo) { // (3.3) Logger.updater.Debug($"Extracting ZIP file for {item.Name}"); @@ -472,8 +466,6 @@ namespace IPA.Updating.ModsaberML if (!LoneFunctions.UnsafeCompare(hash, fileInfo.Hash)) throw new Exception("The hash for the file doesn't match what is defined"); - var newFiles = new List(); - var targetDir = Path.Combine(BeatSaber.InstallPath, "IPA", Path.GetRandomFileName() + "_Pending"); Directory.CreateDirectory(targetDir); @@ -517,7 +509,7 @@ namespace IPA.Updating.ModsaberML ostream.Seek(0, SeekOrigin.Begin); FileInfo targetFile = new FileInfo(Path.Combine(targetDir, entry.FileName)); - Directory.CreateDirectory(targetFile.DirectoryName); + Directory.CreateDirectory(targetFile.DirectoryName ?? throw new InvalidOperationException()); if (LoneFunctions.GetRelativePath(targetFile.FullName, targetDir) == LoneFunctions.GetRelativePath(item.LocalPluginMeta?.Filename, BeatSaber.InstallPath)) shouldDeleteOldFile = false; // overwriting old file, no need to delete @@ -538,7 +530,7 @@ namespace IPA.Updating.ModsaberML } if (shouldDeleteOldFile && item.LocalPluginMeta != null) - File.AppendAllLines(Path.Combine(targetDir, _SpecialDeletionsFile), new string[] { LoneFunctions.GetRelativePath(item.LocalPluginMeta.Filename, BeatSaber.InstallPath) }); + File.AppendAllLines(Path.Combine(targetDir, SpecialDeletionsFile), new[] { LoneFunctions.GetRelativePath(item.LocalPluginMeta.Filename, BeatSaber.InstallPath) }); } catch (Exception) { // something failed; restore @@ -554,7 +546,7 @@ namespace IPA.Updating.ModsaberML if (item.LocalPluginMeta?.Plugin is SelfPlugin) { // currently updating self, so copy to working dir and update LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(BeatSaber.InstallPath)); - if (File.Exists(Path.Combine(BeatSaber.InstallPath, _SpecialDeletionsFile))) File.Delete(Path.Combine(BeatSaber.InstallPath, _SpecialDeletionsFile)); + if (File.Exists(Path.Combine(BeatSaber.InstallPath, SpecialDeletionsFile))) File.Delete(Path.Combine(BeatSaber.InstallPath, SpecialDeletionsFile)); Process.Start(new ProcessStartInfo { FileName = item.LocalPluginMeta.Filename, @@ -563,13 +555,13 @@ namespace IPA.Updating.ModsaberML }); } else - LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(eventualOutput), _SpecialDeletionsFile); + LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(eventualOutput), SpecialDeletionsFile); Directory.Delete(targetDir, true); // delete extraction site Logger.updater.Debug("Extractor exited"); } - internal const string _SpecialDeletionsFile = "$$delete"; + internal const string SpecialDeletionsFile = "$$delete"; } [Serializable] diff --git a/IPA.Loader/Updating/SelfPlugin.cs b/IPA.Loader/Updating/SelfPlugin.cs index f21b76a7..03b4e9d4 100644 --- a/IPA.Loader/Updating/SelfPlugin.cs +++ b/IPA.Loader/Updating/SelfPlugin.cs @@ -1,17 +1,11 @@ -using IPA; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using UnityEngine.SceneManagement; +using UnityEngine.SceneManagement; namespace IPA.Updating { internal class SelfPlugin : IBeatSaberPlugin { internal const string IPA_Name = "Beat Saber IPA"; - internal const string IPA_Version = "3.11.1"; + internal const string IPA_Version = "3.11.2"; public static SelfPlugin Instance { get; set; } = new SelfPlugin(); diff --git a/IPA.Loader/Utilities/BeatSaber.cs b/IPA.Loader/Utilities/BeatSaber.cs index e7f6ec28..3576d78d 100644 --- a/IPA.Loader/Utilities/BeatSaber.cs +++ b/IPA.Loader/Utilities/BeatSaber.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SemVer; +using UnityEngine; using Version = SemVer.Version; namespace IPA.Utilities @@ -14,11 +10,11 @@ namespace IPA.Utilities /// public static class BeatSaber { - private static Version _gameVersion = null; + private static Version _gameVersion; /// /// Provides the current game version /// - public static Version GameVersion => _gameVersion ?? (_gameVersion = new Version(UnityEngine.Application.version)); + public static Version GameVersion => _gameVersion ?? (_gameVersion = new Version(Application.version)); /// /// The different types of releases of the game. @@ -34,7 +30,7 @@ namespace IPA.Utilities /// Oculus } - private static Release? _releaseCache = null; + private static Release? _releaseCache; /// /// Gets the type of this installation of Beat Saber /// @@ -56,11 +52,11 @@ namespace IPA.Utilities private static bool FindSteamVRAsset() { // these require assembly qualified names.... - var SteamVRCamera = Type.GetType("SteamVR_Camera, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", false); - var SteamVRExternalCamera = Type.GetType("SteamVR_ExternalCamera, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", false); - var SteamVRFade = Type.GetType("SteamVR_Fade, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", false); + var steamVRCamera = Type.GetType("SteamVR_Camera, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", false); + var steamVRExternalCamera = Type.GetType("SteamVR_ExternalCamera, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", false); + var steamVRFade = Type.GetType("SteamVR_Fade, Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", false); - return SteamVRCamera != null && SteamVRExternalCamera != null && SteamVRFade != null; + return steamVRCamera != null && steamVRExternalCamera != null && steamVRFade != null; } } } diff --git a/IPA.Loader/Utilities/Extensions.cs b/IPA.Loader/Utilities/Extensions.cs index 55d8e01b..4cd6b762 100644 --- a/IPA.Loader/Utilities/Extensions.cs +++ b/IPA.Loader/Utilities/Extensions.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IPA.Utilities { @@ -18,11 +14,7 @@ namespace IPA.Utilities /// the default value of public static object GetDefault(this Type type) { - if (type.IsValueType) - { - return Activator.CreateInstance(type); - } - return null; + return type.IsValueType ? Activator.CreateInstance(type) : null; } } } diff --git a/IPA.Loader/Utilities/LoneFunctions.cs b/IPA.Loader/Utilities/LoneFunctions.cs index eb44920c..ae03614d 100644 --- a/IPA.Loader/Utilities/LoneFunctions.cs +++ b/IPA.Loader/Utilities/LoneFunctions.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; -using System.Threading.Tasks; namespace IPA.Utilities { @@ -19,9 +16,9 @@ namespace IPA.Utilities /// the corresponding byte array public static byte[] StringToByteArray(string hex) { - int NumberChars = hex.Length; - byte[] bytes = new byte[NumberChars / 2]; - for (int i = 0; i < NumberChars; i += 2) + int numberChars = hex.Length; + byte[] bytes = new byte[numberChars / 2]; + for (int i = 0; i < numberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; } @@ -62,7 +59,7 @@ namespace IPA.Utilities if (*((long*)x1) != *((long*)x2)) return false; if ((l & 4) != 0) { if (*((int*)x1) != *((int*)x2)) return false; x1 += 4; x2 += 4; } if ((l & 2) != 0) { if (*((short*)x1) != *((short*)x2)) return false; x1 += 2; x2 += 2; } - if ((l & 1) != 0) if (*((byte*)x1) != *((byte*)x2)) return false; + if ((l & 1) != 0) if (*x1 != *x2) return false; return true; } } diff --git a/IPA.Loader/Utilities/Ref.cs b/IPA.Loader/Utilities/Ref.cs index bd9fdd63..933bcb04 100644 --- a/IPA.Loader/Utilities/Ref.cs +++ b/IPA.Loader/Utilities/Ref.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; namespace IPA.Utilities { @@ -28,7 +24,7 @@ namespace IPA.Utilities set => _value = value; } - private Exception _error = null; + private Exception _error; /// /// An exception that was generated while creating the value. /// @@ -64,14 +60,14 @@ namespace IPA.Utilities internal static class ExceptionUtilities { - private static readonly FieldInfo STACK_TRACE_STRING_FI = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance); - private static readonly Type TRACE_FORMAT_TI = Type.GetType("System.Diagnostics.StackTrace").GetNestedType("TraceFormat", BindingFlags.NonPublic); - private static readonly MethodInfo TRACE_TO_STRING_MI = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { TRACE_FORMAT_TI }, null); + private static readonly FieldInfo StackTraceStringFi = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance); + private static readonly Type TraceFormatTi = Type.GetType("System.Diagnostics.StackTrace")?.GetNestedType("TraceFormat", BindingFlags.NonPublic); + private static readonly MethodInfo TraceToStringMi = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { TraceFormatTi }, null); public static Exception SetStackTrace(this Exception target, StackTrace stack) { - var getStackTraceString = TRACE_TO_STRING_MI.Invoke(stack, new object[] { Enum.GetValues(TRACE_FORMAT_TI).GetValue(0) }); - STACK_TRACE_STRING_FI.SetValue(target, getStackTraceString); + var getStackTraceString = TraceToStringMi.Invoke(stack, new[] { Enum.GetValues(TraceFormatTi).GetValue(0) }); + StackTraceStringFi.SetValue(target, getStackTraceString); return target; } } diff --git a/IPA.Loader/Utilities/ReflectionUtil.cs b/IPA.Loader/Utilities/ReflectionUtil.cs index 5a716359..21c07104 100644 --- a/IPA.Loader/Utilities/ReflectionUtil.cs +++ b/IPA.Loader/Utilities/ReflectionUtil.cs @@ -18,7 +18,7 @@ namespace IPA.Utilities public static void SetPrivateField(this object obj, string fieldName, object value) { var prop = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - prop.SetValue(obj, value); + prop?.SetValue(obj, value); } /// @@ -31,7 +31,7 @@ namespace IPA.Utilities public static T GetPrivateField(this object obj, string fieldName) { var prop = obj.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance); - var value = prop.GetValue(obj); + var value = prop?.GetValue(obj); return (T) value; } @@ -45,7 +45,7 @@ namespace IPA.Utilities { var prop = obj.GetType() .GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - prop.SetValue(obj, value, null); + prop?.SetValue(obj, value, null); } /// @@ -58,7 +58,7 @@ namespace IPA.Utilities public static object InvokePrivateMethod(this object obj, string methodName, params object[] methodParams) { MethodInfo dynMethod = obj.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - return dynMethod.Invoke(obj, methodParams); + return dynMethod?.Invoke(obj, methodParams); } /// @@ -91,7 +91,7 @@ namespace IPA.Utilities while (type != typeof(MonoBehaviour)) { CopyForType(type, original, copy); - type = type.BaseType; + type = type?.BaseType; } return copy; @@ -116,7 +116,7 @@ namespace IPA.Utilities while (type != typeof(MonoBehaviour)) { CopyForType(type, original, copy); - type = type.BaseType; + type = type?.BaseType; } return copy; @@ -161,7 +161,6 @@ namespace IPA.Utilities if (type != null) { object instance = Activator.CreateInstance(type); - if (instance != null) { Type instType = instance.GetType(); MethodInfo methodInfo = instType.GetMethod(function, methodSig); @@ -169,20 +168,12 @@ namespace IPA.Utilities { return methodInfo.Invoke(instance, parameters); } - else - { - throw new Exception("Method not found"); - } - } - else - { - throw new Exception("Unable to instantiate object of type"); + + throw new Exception("Method not found"); } } - else - { - throw new ArgumentNullException("type"); - } + + throw new ArgumentNullException(nameof(type)); } /// diff --git a/IPA/Arguments.cs b/IPA/Arguments.cs index ae775acf..c3f52002 100644 --- a/IPA/Arguments.cs +++ b/IPA/Arguments.cs @@ -1,23 +1,20 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; using System.Text; -using System.Threading.Tasks; -namespace IPA.ArgParsing +namespace IPA { public class Arguments { - public static Arguments CmdLine = new Arguments(Environment.GetCommandLineArgs()); + public static readonly Arguments CmdLine = new Arguments(Environment.GetCommandLineArgs()); - private List positional = new List(); - private Dictionary longFlags = new Dictionary(); - private Dictionary flags = new Dictionary(); - private List flagObjects = new List(); + private readonly List positional = new List(); + private readonly Dictionary longFlags = new Dictionary(); + private readonly Dictionary flags = new Dictionary(); + private readonly List flagObjects = new List(); - private string[] toParse = null; + private string[] toParse; private Arguments(string[] args) { @@ -58,10 +55,10 @@ namespace IPA.ArgParsing { // parse as flags var argument = arg.Substring(1); // cut off first char - StringBuilder subBuildState = new StringBuilder(); - bool parsingValue = false; - char mainChar = ' '; - foreach (char chr in argument) + var subBuildState = new StringBuilder(); + var parsingValue = false; + var mainChar = ' '; + foreach (var chr in argument) { if (!parsingValue) { @@ -100,22 +97,20 @@ namespace IPA.ArgParsing foreach (var flag in flagObjects) { - foreach (var chflag in flag.shortFlags) + foreach (var charFlag in flag.ShortFlags) { - if (flag.exists = HasFlag(chflag)) - { - flag.value = GetFlagValue(chflag); - goto FoundValue; // continue to next flagObjects item - } + if (!(flag.exists_ = HasFlag(charFlag))) continue; + + flag.value_ = GetFlagValue(charFlag); + goto FoundValue; // continue to next flagObjects item } - foreach (var lflag in flag.longFlags) + foreach (var longFlag in flag.LongFlags) { - if (flag.exists = HasLongFlag(lflag)) - { - flag.value = GetLongFlagValue(lflag); - goto FoundValue; // continue to next flagObjects item - } + if (!(flag.exists_ = HasLongFlag(longFlag))) continue; + + flag.value_ = GetLongFlagValue(longFlag); + goto FoundValue; // continue to next flagObjects item } FoundValue:; @@ -145,8 +140,8 @@ namespace IPA.ArgParsing public void PrintHelp() { const string indent = " "; - string filename = Environment.GetCommandLineArgs()[0]; - string format = @"usage: + var filename = Environment.GetCommandLineArgs()[0]; + const string format = @"usage: {2}{0} [FLAGS] [ARGUMENTS] flags: @@ -155,12 +150,12 @@ flags: foreach (var flag in flagObjects) { flagsBuilder.AppendFormat("{2}{0}{3}{1}", - string.Join(", ", flag.shortFlags.Select(s => $"-{s}").Concat( flag.longFlags.Select(s => $"--{s}")) ), + string.Join(", ", flag.ShortFlags.Select(s => $"-{s}").Concat( flag.LongFlags.Select(s => $"--{s}")) ), Environment.NewLine, indent, flag.ValueString != null ? "=" + flag.ValueString : ""); flagsBuilder.AppendFormat("{2}{2}{0}{1}", flag.DocString, Environment.NewLine, indent); } - Console.Write(string.Format(format, filename, flagsBuilder.ToString(), indent)); + Console.Write(format, filename, flagsBuilder, indent); } public IReadOnlyList PositionalArgs => positional; @@ -168,11 +163,11 @@ flags: public class ArgumentFlag { - internal List shortFlags = new List(); - internal List longFlags = new List(); + internal readonly List ShortFlags = new List(); + internal readonly List LongFlags = new List(); - internal string value = null; - internal bool exists = false; + internal string value_; + internal bool exists_; public ArgumentFlag(params string[] flags) { @@ -183,18 +178,18 @@ flags: private void AddPart(string flagPart) { if (flagPart.StartsWith("--")) - longFlags.Add(flagPart.Substring(2)); + LongFlags.Add(flagPart.Substring(2)); else if (flagPart.StartsWith("-")) - shortFlags.Add(flagPart[1]); + ShortFlags.Add(flagPart[1]); } - public bool Exists => exists; - public string Value => value; + 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 string ValueString { get; set; } public static implicit operator bool(ArgumentFlag f) { diff --git a/IPA/PatchContext.cs b/IPA/PatchContext.cs index 2473fb46..2a829306 100644 --- a/IPA/PatchContext.cs +++ b/IPA/PatchContext.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; -using System.Text; namespace IPA { @@ -37,12 +34,12 @@ namespace IPA { Executable = exe }; - context.ProjectRoot = new FileInfo(context.Executable).Directory.FullName; - context.IPARoot = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "IPA"); - context.IPA = Assembly.GetExecutingAssembly()?.Location ?? Path.Combine(context.ProjectRoot, "IPA.exe"); + context.ProjectRoot = new FileInfo(context.Executable).Directory?.FullName; + context.IPARoot = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? throw new InvalidOperationException(), "IPA"); + context.IPA = Assembly.GetExecutingAssembly().Location; context.DataPathSrc = Path.Combine(context.IPARoot, "Data"); context.LibsPathSrc = Path.Combine(context.IPARoot, "Libs"); - context.PluginsFolder = Path.Combine(context.ProjectRoot, "Plugins"); + context.PluginsFolder = Path.Combine(context.ProjectRoot ?? throw new InvalidOperationException(), "Plugins"); context.ProjectName = Path.GetFileNameWithoutExtension(context.Executable); context.DataPathDst = Path.Combine(context.ProjectRoot, context.ProjectName + "_Data"); context.LibsPathDst = Path.Combine(context.ProjectRoot, "Libs"); diff --git a/IPA/Patcher/BackupManager.cs b/IPA/Patcher/BackupManager.cs index f21c07a9..b2c71f78 100644 --- a/IPA/Patcher/BackupManager.cs +++ b/IPA/Patcher/BackupManager.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; namespace IPA.Patcher { - public class BackupManager + public static class BackupManager { public static BackupUnit FindLatestBackup(PatchContext context) { @@ -42,7 +39,7 @@ namespace IPA.Patcher if (string.IsNullOrEmpty(dir)) throw new ArgumentException( "Starting directory is a null reference or an empty string", - "dir"); + nameof(dir)); try { @@ -53,15 +50,13 @@ namespace IPA.Patcher var entries = Directory.EnumerateFileSystemEntries(dir); - if (!entries.Any()) + if (entries.Any()) return; + try { - try - { - Directory.Delete(dir); - } - catch (UnauthorizedAccessException) { } - catch (DirectoryNotFoundException) { } + Directory.Delete(dir); } + catch (UnauthorizedAccessException) { } + catch (DirectoryNotFoundException) { } } catch (UnauthorizedAccessException) { } } diff --git a/IPA/Patcher/BackupUnit.cs b/IPA/Patcher/BackupUnit.cs index 5e84e4b1..7ac7b437 100644 --- a/IPA/Patcher/BackupUnit.cs +++ b/IPA/Patcher/BackupUnit.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.IO; -using System.Linq; -using System.Text; namespace IPA.Patcher { @@ -12,12 +9,12 @@ namespace IPA.Patcher /// public class BackupUnit { - public string Name { get; private set; } + private string Name { get; } - private DirectoryInfo _BackupPath; - private PatchContext _Context; - private List _Files = new List(); - private FileInfo _ManifestFile; + private readonly DirectoryInfo _backupPath; + private readonly PatchContext _context; + private readonly List _files = new List(); + private readonly FileInfo _manifestFile; private static string _ManifestFileName = "$manifest$.txt"; public BackupUnit(PatchContext context) : this(context, DateTime.Now.ToString("yyyy-MM-dd_h-mm-ss")) @@ -27,9 +24,9 @@ namespace IPA.Patcher private BackupUnit(PatchContext context, string name) { Name = name; - _Context = context; - _BackupPath = new DirectoryInfo(Path.Combine(_Context.BackupPath, Name)); - _ManifestFile = new FileInfo(Path.Combine(_BackupPath.FullName, _ManifestFileName)); + _context = context; + _backupPath = new DirectoryInfo(Path.Combine(_context.BackupPath, Name)); + _manifestFile = new FileInfo(Path.Combine(_backupPath.FullName, _ManifestFileName)); } public static BackupUnit FromDirectory(DirectoryInfo directory, PatchContext context) @@ -37,11 +34,11 @@ namespace IPA.Patcher var unit = new BackupUnit(context, directory.Name); // Read Manifest - if (unit._ManifestFile.Exists) + if (unit._manifestFile.Exists) { - string manifest = File.ReadAllText(unit._ManifestFile.FullName); - foreach (var line in manifest.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) - unit._Files.Add(line); + var manifest = File.ReadAllText(unit._manifestFile.FullName); + foreach (var line in manifest.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) + unit._files.Add(line); } else { @@ -49,7 +46,7 @@ namespace IPA.Patcher { if (file.Name == _ManifestFileName) continue; var relativePath = file.FullName.Substring(directory.FullName.Length + 1); - unit._Files.Add(relativePath); + unit._files.Add(relativePath); } } @@ -63,32 +60,32 @@ namespace IPA.Patcher internal void Delete() { - _BackupPath.Delete(true); + _backupPath.Delete(true); } /// /// Adds a file to the list of changed files and backups it. /// - /// + /// the file to add public void Add(FileInfo file) { - if(!file.FullName.StartsWith(_Context.ProjectRoot)) + if(!file.FullName.StartsWith(_context.ProjectRoot)) { Console.Error.WriteLine("Invalid file path for backup! {0}", file); return; } - var relativePath = file.FullName.Substring(_Context.ProjectRoot.Length + 1); - var backupPath = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath)); + var relativePath = file.FullName.Substring(_context.ProjectRoot.Length + 1); + var backupPath = new FileInfo(Path.Combine(_backupPath.FullName, relativePath)); - if(_Files.Contains(relativePath)) + if(_files.Contains(relativePath)) { Console.WriteLine("Skipping backup of {0}", relativePath); return; } // Copy over - backupPath.Directory.Create(); + backupPath.Directory?.Create(); if (file.Exists) { file.CopyTo(backupPath.FullName); @@ -99,14 +96,14 @@ namespace IPA.Patcher backupPath.Create().Close(); } - if (!File.Exists(_ManifestFile.FullName)) - _ManifestFile.Create().Close(); - var stream = _ManifestFile.AppendText(); + if (!File.Exists(_manifestFile.FullName)) + _manifestFile.Create().Close(); + var stream = _manifestFile.AppendText(); stream.WriteLine(relativePath); stream.Close(); // Add to list - _Files.Add(relativePath); + _files.Add(relativePath); } /// @@ -114,19 +111,19 @@ namespace IPA.Patcher /// public void Restore() { - foreach(var relativePath in _Files) + foreach(var relativePath in _files) { Console.WriteLine("Restoring {0}", relativePath); // Original version - var backupFile = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath)); - var target = new FileInfo(Path.Combine(_Context.ProjectRoot, relativePath)); + var backupFile = new FileInfo(Path.Combine(_backupPath.FullName, relativePath)); + var target = new FileInfo(Path.Combine(_context.ProjectRoot, relativePath)); if (backupFile.Exists) { if (backupFile.Length > 0) { Console.WriteLine(" {0} => {1}", backupFile.FullName, target.FullName); - target.Directory.Create(); + target.Directory?.Create(); backupFile.CopyTo(target.FullName, true); } else diff --git a/IPA/Patcher/Patcher.cs b/IPA/Patcher/Patcher.cs index a8ea3911..7fd69495 100644 --- a/IPA/Patcher/Patcher.cs +++ b/IPA/Patcher/Patcher.cs @@ -4,16 +4,15 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; namespace IPA.Patcher { - class PatchedModule + internal class PatchedModule { - private static readonly string[] ENTRY_TYPES = { "Input", "Display" }; + private static readonly string[] EntryTypes = { "Input", "Display" }; - private FileInfo _File; - private ModuleDefinition _Module; + private readonly FileInfo _file; + private ModuleDefinition _module; internal struct PatchData { public bool IsPatched; @@ -27,7 +26,7 @@ namespace IPA.Patcher private PatchedModule(string engineFile) { - _File = new FileInfo(engineFile); + _file = new FileInfo(engineFile); LoadModules(); } @@ -35,27 +34,33 @@ namespace IPA.Patcher private void LoadModules() { var resolver = new DefaultAssemblyResolver(); - resolver.AddSearchDirectory(_File.DirectoryName); + resolver.AddSearchDirectory(_file.DirectoryName); var parameters = new ReaderParameters { AssemblyResolver = resolver, }; - _Module = ModuleDefinition.ReadModule(_File.FullName, parameters); + _module = ModuleDefinition.ReadModule(_file.FullName, parameters); } public PatchData Data { get { - var IIdata = new PatchData { IsPatched = false, Version = null }; - foreach (var @ref in _Module.AssemblyReferences) { - if (@ref.Name == "IllusionInjector") IIdata = new PatchData { IsPatched = true, Version = new Version(0, 0, 0, 0) }; - if (@ref.Name == "IllusionPlugin") IIdata = new PatchData { IsPatched = true, Version = new Version(0, 0, 0, 0) }; - if (@ref.Name == "IPA.Injector") return new PatchData { IsPatched = true, Version = @ref.Version }; + var data = new PatchData { IsPatched = false, Version = null }; + foreach (var @ref in _module.AssemblyReferences) { + switch (@ref.Name) + { + case "IllusionInjector": + case "IllusionPlugin": + data = new PatchData { IsPatched = true, Version = new Version(0, 0, 0, 0) }; + break; + case "IPA.Injector": + return new PatchData { IsPatched = true, Version = @ref.Version }; + } } - return IIdata; + return data; } } @@ -63,26 +68,26 @@ namespace IPA.Patcher { // First, let's add the reference var nameReference = new AssemblyNameReference("IPA.Injector", v); - var injectorPath = Path.Combine(_File.DirectoryName, "IPA.Injector.dll"); + var injectorPath = Path.Combine(_file.DirectoryName ?? throw new InvalidOperationException(), "IPA.Injector.dll"); var injector = ModuleDefinition.ReadModule(injectorPath); bool hasIPAInjector = false; - for (int i = 0; i < _Module.AssemblyReferences.Count; i++) + 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--); - if (_Module.AssemblyReferences[i].Name == "IPA.Injector") + if (_module.AssemblyReferences[i].Name == "IllusionInjector") + _module.AssemblyReferences.RemoveAt(i--); + if (_module.AssemblyReferences[i].Name == "IllusionPlugin") + _module.AssemblyReferences.RemoveAt(i--); + if (_module.AssemblyReferences[i].Name == "IPA.Injector") { hasIPAInjector = true; - _Module.AssemblyReferences[i].Version = v; + _module.AssemblyReferences[i].Version = v; } } if (!hasIPAInjector) { - _Module.AssemblyReferences.Add(nameReference); + _module.AssemblyReferences.Add(nameReference); int patched = 0; foreach (var type in FindEntryTypes()) @@ -95,7 +100,7 @@ namespace IPA.Patcher if (patched > 0) { - _Module.Write(_File.FullName); + _module.Write(_file.FullName); } else { @@ -104,7 +109,7 @@ namespace IPA.Patcher } else { - _Module.Write(_File.FullName); + _module.Write(_file.FullName); } } @@ -113,7 +118,7 @@ namespace IPA.Patcher var targetMethod = targetType.Methods.FirstOrDefault(m => m.IsConstructor && m.IsStatic); if (targetMethod != null) { - var methodReference = _Module.Import(injector.GetType("IPA.Injector.Injector").Methods.First(m => m.Name == "Inject")); + var methodReference = _module.Import(injector.GetType("IPA.Injector.Injector").Methods.First(m => m.Name == "Inject")); targetMethod.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, methodReference)); return true; } @@ -123,7 +128,7 @@ namespace IPA.Patcher private IEnumerable FindEntryTypes() { - return _Module.GetTypes().Where(m => ENTRY_TYPES.Contains(m.Name)); + return _module.GetTypes().Where(m => EntryTypes.Contains(m.Name)); } } } diff --git a/IPA/Patcher/Virtualizer.cs b/IPA/Patcher/Virtualizer.cs index 8bce06a3..bfc3ce5b 100644 --- a/IPA/Patcher/Virtualizer.cs +++ b/IPA/Patcher/Virtualizer.cs @@ -1,18 +1,14 @@ using Mono.Cecil; using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; namespace IPA.Patcher { class VirtualizedModule { - private const string ENTRY_TYPE = "Display"; - - private FileInfo _File; - private ModuleDefinition _Module; + private readonly FileInfo _file; + private ModuleDefinition _module; public static VirtualizedModule Load(string engineFile) { @@ -21,7 +17,7 @@ namespace IPA.Patcher private VirtualizedModule(string assemblyFile) { - _File = new FileInfo(assemblyFile); + _file = new FileInfo(assemblyFile); LoadModules(); } @@ -29,30 +25,29 @@ namespace IPA.Patcher private void LoadModules() { var resolver = new DefaultAssemblyResolver(); - resolver.AddSearchDirectory(_File.DirectoryName); + resolver.AddSearchDirectory(_file.DirectoryName); var parameters = new ReaderParameters { AssemblyResolver = resolver, }; - _Module = ModuleDefinition.ReadModule(_File.FullName, parameters); + _module = ModuleDefinition.ReadModule(_file.FullName, parameters); } /// /// /// - /// public void Virtualize() { - foreach (var type in _Module.Types) + foreach (var type in _module.Types) { VirtualizeType(type); } Console.WriteLine(); - _Module.Write(_File.FullName); + _module.Write(_file.FullName); } private void VirtualizeType(TypeDefinition type) @@ -110,10 +105,11 @@ namespace IPA.Patcher { get { - var awakeMethods = _Module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")); - if (awakeMethods.Count() == 0) return false; + var awakeMethods = _module.GetTypes().SelectMany(t => t.Methods.Where(m => m.Name == "Awake")); + var methodDefinitions = awakeMethods as MethodDefinition[] ?? awakeMethods.ToArray(); + if (!methodDefinitions.Any()) return false; - return ((float)awakeMethods.Count(m => m.IsVirtual) / awakeMethods.Count()) > 0.5f; + return ((float)methodDefinitions.Count(m => m.IsVirtual) / methodDefinitions.Count()) > 0.5f; } } } diff --git a/IPA/Program.cs b/IPA/Program.cs index 69f4d81e..373eacb0 100644 --- a/IPA/Program.cs +++ b/IPA/Program.cs @@ -1,20 +1,21 @@ -using IPA.Patcher; -using System; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; -using IPA.ArgParsing; +using IPA.Patcher; namespace IPA { + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] public class Program { + [SuppressMessage("ReSharper", "InconsistentNaming")] public enum Architecture { x86, @@ -24,17 +25,17 @@ namespace IPA public 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", "-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" }; - public static ArgumentFlag ArgDestructive = new ArgumentFlag("--destructive", "-d") { DocString = "patches the game using the now outdated destructive methods" }; + public static readonly ArgumentFlag ArgHelp = new ArgumentFlag("--help", "-h") { DocString = "prints this message" }; + public static readonly ArgumentFlag ArgWaitFor = new ArgumentFlag("--waitfor", "-w") { DocString = "waits for the specified PID to exit", ValueString = "PID" }; + public static readonly ArgumentFlag ArgForce = new ArgumentFlag("--force", "-f") { DocString = "forces the operation to go through" }; + public static readonly ArgumentFlag ArgRevert = new ArgumentFlag("--revert", "-r") { DocString = "reverts the IPA installation" }; + public static readonly ArgumentFlag ArgNoWait = new ArgumentFlag("--nowait", "-n") { DocString = "doesn't wait for user input after the operation" }; + public static readonly ArgumentFlag ArgStart = new ArgumentFlag("--start", "-s") { DocString = "uses value_ as arguments to start the game after the patch/unpatch", ValueString = "ARGUMENTS" }; + public static readonly ArgumentFlag ArgLaunch = new ArgumentFlag("--launch", "-l") { DocString = "uses positional parameters as arguments to start the game after patch/unpatch" }; + public static readonly ArgumentFlag ArgDestructive = new ArgumentFlag("--destructive", "-d") { DocString = "patches the game using the now outdated destructive methods" }; [STAThread] - static void Main(string[] args) + public static void Main(string[] args) { Arguments.CmdLine.Flags(ArgHelp, ArgWaitFor, ArgForce, ArgRevert, ArgNoWait, ArgStart, ArgLaunch, ArgDestructive).Process(); @@ -48,7 +49,7 @@ namespace IPA { if (ArgWaitFor.HasValue) { // wait for process if necessary - int pid = int.Parse(ArgWaitFor.Value); + var pid = int.Parse(ArgWaitFor.Value); try { // wait for beat saber to exit (ensures we can modify the file) @@ -58,20 +59,26 @@ namespace IPA parent.WaitForExit(); } - catch (Exception) { } + catch (Exception) + { + // ignored + } } PatchContext context = null; Assembly AssemblyLibLoader(object source, ResolveEventArgs e) { + // ReSharper disable AccessToModifiedClosure + if (context == null) return null; var libsDir = context.LibsPathSrc; + // ReSharper enable AccessToModifiedClosure var asmName = new AssemblyName(e.Name); - var testFilen = Path.Combine(libsDir, $"{asmName.Name}.{asmName.Version}.dll"); + var testFile = Path.Combine(libsDir, $"{asmName.Name}.{asmName.Version}.dll"); - if (File.Exists(testFilen)) - return Assembly.LoadFile(testFilen); + if (File.Exists(testFile)) + return Assembly.LoadFile(testFile); Console.WriteLine($"Could not load library {asmName}"); @@ -369,11 +376,6 @@ namespace IPA yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, relevantBit.Substring("x86_64".Length + 1))); } - else - { - // Throw away - yield break; - } } else if (!isFlat && isFileFlat) { @@ -416,34 +418,35 @@ namespace IPA } // Copy each file into the new directory. - foreach (FileInfo fi in source.GetFiles()) + foreach (var fi in source.GetFiles()) { foreach (var targetFile in interceptor(fi, new FileInfo(Path.Combine(target.FullName, fi.Name)))) { - if (!targetFile.Exists || targetFile.LastWriteTimeUtc < fi.LastWriteTimeUtc || aggressive) - { - targetFile.Directory.Create(); + if (targetFile.Exists && targetFile.LastWriteTimeUtc >= fi.LastWriteTimeUtc && !aggressive) + continue; - Console.CursorTop--; - ClearLine(); - Console.WriteLine(@"Copying {0}", targetFile.FullName); - backup.Add(targetFile); - fi.CopyTo(targetFile.FullName, true); - } + Debug.Assert(targetFile.Directory != null, "targetFile.Directory != null"); + targetFile.Directory.Create(); + + Console.CursorTop--; + ClearLine(); + Console.WriteLine(@"Copying {0}", targetFile.FullName); + backup.Add(targetFile); + fi.CopyTo(targetFile.FullName, true); } } // Copy each subdirectory using recursion. - if (recurse) - foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) - { - DirectoryInfo nextTargetSubDir = new DirectoryInfo(Path.Combine(target.FullName, diSourceSubDir.Name)); - CopyAll(diSourceSubDir, nextTargetSubDir, aggressive, backup, interceptor, recurse); - } + if (!recurse) return; + foreach (var diSourceSubDir in source.GetDirectories()) + { + var nextTargetSubDir = new DirectoryInfo(Path.Combine(target.FullName, diSourceSubDir.Name)); + CopyAll(diSourceSubDir, nextTargetSubDir, aggressive, backup, interceptor); + } } - static void Fail(string message) + private static void Fail(string message) { Console.Error.WriteLine("ERROR: " + message); @@ -460,8 +463,8 @@ namespace IPA /// /// Encodes an argument for passing into a program /// - /// The value that should be received by the program - /// The value which needs to be passed to the program for the original value + /// The value_ that should be received by the program + /// The value_ which needs to be passed to the program for the original value_ /// to come through public static string EncodeParameterArgument(string original) { @@ -487,18 +490,15 @@ namespace IPA if (machine == 0x8664) // IMAGE_FILE_MACHINE_AMD64 return Architecture.x64; - else if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386 + if (machine == 0x014c) // IMAGE_FILE_MACHINE_I386 return Architecture.x86; - else if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64 + if (machine == 0x0200) // IMAGE_FILE_MACHINE_IA64 return Architecture.x64; - else - return Architecture.Unknown; - } - else - { - // Not a supported binary return Architecture.Unknown; } + + // Not a supported binary + return Architecture.Unknown; } } diff --git a/IPA/Properties/AssemblyInfo.cs b/IPA/Properties/AssemblyInfo.cs index 3126faea..4ba62089 100644 --- a/IPA/Properties/AssemblyInfo.cs +++ b/IPA/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -32,5 +31,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.11.1")] // will be patched by AppVeyor -[assembly: AssemblyFileVersion("3.11.1")] // will be patched by AppVeyor +[assembly: AssemblyVersion("3.11.2")] +[assembly: AssemblyFileVersion("3.11.2")] diff --git a/IPA/Shortcut.cs b/IPA/Shortcut.cs index 980bdc13..570b2375 100644 --- a/IPA/Shortcut.cs +++ b/IPA/Shortcut.cs @@ -1,14 +1,15 @@ using System; +using System.Reflection; using System.Runtime.InteropServices; namespace IPA { - public class Shortcut + public static class Shortcut { - private static Type m_type = Type.GetTypeFromProgID("WScript.Shell"); - private static object m_shell = Activator.CreateInstance(m_type); + private static readonly Type MType = Type.GetTypeFromProgID("WScript.Shell"); + private static readonly object MShell = Activator.CreateInstance(MType); - [ComImport, TypeLibType((short)0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")] + [ComImport, TypeLibType(0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")] private interface IWshShortcut { [DispId(0)] @@ -38,8 +39,8 @@ namespace IPA [DispId(0x3ef)] string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] set; } - [TypeLibFunc((short)0x40), DispId(0x7d0)] - void Load([In, MarshalAs(UnmanagedType.BStr)] string PathLink); + [TypeLibFunc(0x40), DispId(0x7d0)] + void Load([In, MarshalAs(UnmanagedType.BStr)] string pathLink); [DispId(0x7d1)] void Save(); @@ -47,7 +48,7 @@ namespace IPA public static void Create(string fileName, string targetPath, string arguments, string workingDirectory, string description, string hotkey, string iconPath) { - IWshShortcut shortcut = (IWshShortcut)m_type.InvokeMember("CreateShortcut", System.Reflection.BindingFlags.InvokeMethod, null, m_shell, new object[] { fileName }); + IWshShortcut shortcut = (IWshShortcut)MType.InvokeMember("CreateShortcut", BindingFlags.InvokeMethod, null, MShell, new object[] { fileName }); shortcut.Description = description; shortcut.Hotkey = hotkey; shortcut.TargetPath = targetPath; diff --git a/MSBuildTasks/AssemblyRenameTask.cs b/MSBuildTasks/AssemblyRenameTask.cs index 6e6b3639..486d8dd9 100644 --- a/MSBuildTasks/AssemblyRenameTask.cs +++ b/MSBuildTasks/AssemblyRenameTask.cs @@ -1,24 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Mono.Cecil; +using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -using Microsoft.Build.Framework; +using Mono.Cecil; +using System; using System.IO; namespace MSBuildTasks { public class AssemblyRename : Task { - private ITaskItem[] assemblies; [Required] - public ITaskItem[] Assemblies - { - get => assemblies; - set => assemblies = value; - } + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public ITaskItem[] Assemblies { get; set; } public override bool Execute() { @@ -47,7 +40,7 @@ namespace MSBuildTasks var name = asmName.Name; var version = asmName.Version; var newFilen = $"{name}.{version}.dll"; - var newFilePath = Path.Combine(Path.GetDirectoryName(assembly.ItemSpec), newFilen); + var newFilePath = Path.Combine(Path.GetDirectoryName(assembly.ItemSpec) ?? throw new InvalidOperationException(), newFilen); Log.LogMessage(MessageImportance.Normal, $"Old file: {assembly.ItemSpec}, new file: {newFilePath}"); diff --git a/MSBuildTasks/Properties/AssemblyInfo.cs b/MSBuildTasks/Properties/AssemblyInfo.cs index fafa1211..74f94c1c 100644 --- a/MSBuildTasks/Properties/AssemblyInfo.cs +++ b/MSBuildTasks/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/appveyor.yml b/appveyor.yml index f97618f2..604ae09e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ version: 'BSIPA-{branch}-{build}' environment: - bsipa_version: '3.11.1' + bsipa_version: '3.11.2' pull_requests: do_not_increment_build_number: true install: @@ -20,7 +20,7 @@ skip_tags: true deploy: - provider: GitHub release: BSIPA $(bsipa_version)-draft - tag: $(bsipa_version) + tag: $(bsipa_version)-d description: | **Build:** [$(bsipa_version)-$(APPVEYOR_BUILD_NUMBER)](https://ci.appveyor.com/project/nike4613/beatsaber-ipa-reloaded/builds/$(APPVEYOR_BUILD_ID)) [$(configuration)|$(platform)] **Latest Commit:** $(APPVEYOR_REPO_COMMIT)