/// <summary> /// Adds a file to the list of changed files and backups it. /// </summary> /// <param name="path"></param> public void Add(FileInfo file) { var relativePath = LoneFunctions.GetRelativePath(Environment.CurrentDirectory, file.FullName); var backupPath = new FileInfo(Path.Combine(_BackupPath.FullName, relativePath)); if (_Files.Contains(relativePath)) { Console.WriteLine("Skipping backup of {0}", relativePath); return; } // Copy over backupPath.Directory.Create(); if (file.Exists) { file.CopyTo(backupPath.FullName, true); } else { // Make empty file backupPath.Create().Close(); } // Add to list _Files.Add(relativePath); }
/// <summary> /// Adds a file to the list of changed files and backups it. /// </summary> /// <param name="file"></param> public void Add(FileInfo file) { var relativePath = LoneFunctions.GetRelativePath(file.FullName, Environment.CurrentDirectory); var backupPath = new FileInfo(Path.Combine(_backupPath.FullName, relativePath)); // Copy over backupPath.Directory?.Create(); if (file.Exists) { if (File.Exists(backupPath.FullName)) { File.Delete(backupPath.FullName); } file.CopyTo(backupPath.FullName); } else { // Make empty file backupPath.Create().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); }
private static void LoadPlugins() { string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins"); // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL, // so we need to resort to P/Invoke string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath); Logger.log.Info(exeName); _bsPlugins = new List <BSPluginMeta>(); _ipaPlugins = new List <IPlugin>(); if (!Directory.Exists(pluginDirectory)) { return; } string cacheDir = Path.Combine(pluginDirectory, ".cache"); if (!Directory.Exists(cacheDir)) { Directory.CreateDirectory(cacheDir); } else { foreach (string plugin in Directory.GetFiles(cacheDir, "*")) { File.Delete(plugin); } } //Copy plugins to .cache string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll"); foreach (string s in originalPlugins) { string pluginCopy = Path.Combine(cacheDir, Path.GetFileName(s)); File.Copy(Path.Combine(pluginDirectory, s), pluginCopy); } var selfPlugin = new BSPluginMeta { Filename = Path.Combine(Environment.CurrentDirectory, "IPA.exe"), Plugin = new SelfPlugin() }; selfPlugin.ModsaberInfo = selfPlugin.Plugin.ModInfo; _bsPlugins.Add(selfPlugin); //Load copied plugins string[] copiedPlugins = Directory.GetFiles(cacheDir, "*.dll"); foreach (string s in copiedPlugins) { var result = LoadPluginsFromFile(s, exeName); _bsPlugins.AddRange(result.Item1); _ipaPlugins.AddRange(result.Item2); } // DEBUG Logger.log.Info($"Running on Unity {UnityEngine.Application.unityVersion}"); Logger.log.Info($"Game version {UnityEngine.Application.version}"); Logger.log.Info("-----------------------------"); Logger.log.Info($"Loading plugins from {LoneFunctions.GetRelativePath(pluginDirectory, Environment.CurrentDirectory)} and found {_bsPlugins.Count + _ipaPlugins.Count}"); Logger.log.Info("-----------------------------"); foreach (var plugin in _bsPlugins) { Logger.log.Info($"{plugin.Plugin.Name}: {plugin.Plugin.Version}"); } Logger.log.Info("-----------------------------"); foreach (var plugin in _ipaPlugins) { Logger.log.Info($"{plugin.Name}: {plugin.Version}"); } Logger.log.Info("-----------------------------"); }
private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.PlatformFile fileInfo) { // (3.3) Logger.updater.Debug($"Extracting ZIP file for {item.Name}"); var data = stream.GetBuffer(); SHA1 sha = new SHA1CryptoServiceProvider(); var hash = sha.ComputeHash(data); if (!LoneFunctions.UnsafeCompare(hash, fileInfo.Hash)) { throw new Exception("The hash for the file doesn't match what is defined"); } var targetDir = Path.Combine(BeatSaber.InstallPath, "IPA", Path.GetRandomFileName() + "_Pending"); Directory.CreateDirectory(targetDir); var eventualOutput = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending"); if (!Directory.Exists(eventualOutput)) { Directory.CreateDirectory(eventualOutput); } try { bool shouldDeleteOldFile = !(item.LocalPluginMeta?.Plugin is SelfPlugin); using (var zipFile = ZipFile.Read(stream)) { Logger.updater.Debug("Streams opened"); foreach (var entry in zipFile) { if (entry.IsDirectory) { Logger.updater.Debug($"Creating directory {entry.FileName}"); Directory.CreateDirectory(Path.Combine(targetDir, entry.FileName)); } else { using (var ostream = new MemoryStream((int)entry.UncompressedSize)) { entry.Extract(ostream); ostream.Seek(0, SeekOrigin.Begin); sha = new SHA1CryptoServiceProvider(); var fileHash = sha.ComputeHash(ostream); try { if (!LoneFunctions.UnsafeCompare(fileHash, fileInfo.FileHashes[entry.FileName])) { throw new Exception("The hash for the file doesn't match what is defined"); } } catch (KeyNotFoundException) { throw new ModsaberInterceptException("ModSaber did not send the hashes for the zip's content!"); } ostream.Seek(0, SeekOrigin.Begin); FileInfo targetFile = new FileInfo(Path.Combine(targetDir, entry.FileName)); 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 } /*if (targetFile.Exists) * backup.Add(targetFile); * else * newFiles.Add(targetFile);*/ Logger.updater.Debug($"Extracting file {targetFile.FullName}"); targetFile.Delete(); using (var fstream = targetFile.Create()) ostream.CopyTo(fstream); } } } } if (shouldDeleteOldFile && item.LocalPluginMeta != null) { File.AppendAllLines(Path.Combine(targetDir, SpecialDeletionsFile), new[] { LoneFunctions.GetRelativePath(item.LocalPluginMeta.Filename, BeatSaber.InstallPath) }); } } catch (Exception) { // something failed; restore /*foreach (var file in newFiles) * file.Delete(); * backup.Restore(); * backup.Delete();*/ Directory.Delete(targetDir, true); // delete extraction site throw; } 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)); } Process.Start(new ProcessStartInfo { FileName = item.LocalPluginMeta.Filename, Arguments = $"-nw={Process.GetCurrentProcess().Id}", UseShellExecute = false }); } else { LoneFunctions.CopyAll(new DirectoryInfo(targetDir), new DirectoryInfo(eventualOutput), SpecialDeletionsFile); } Directory.Delete(targetDir, true); // delete extraction site Logger.updater.Debug("Extractor exited"); }
private static void LoadPlugins() { string pluginDirectory = Path.Combine(Environment.CurrentDirectory, "Plugins"); // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL, // so we need to resort to P/Invoke string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath); _bsPlugins = new List <PluginInfo>(); _ipaPlugins = new List <IPlugin>(); if (!Directory.Exists(pluginDirectory)) { return; } string cacheDir = Path.Combine(pluginDirectory, ".cache"); if (!Directory.Exists(cacheDir)) { Directory.CreateDirectory(cacheDir); } else { foreach (string plugin in Directory.GetFiles(cacheDir, "*")) { File.Delete(plugin); } } //Copy plugins to .cache string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll"); foreach (string s in originalPlugins) { string pluginCopy = Path.Combine(cacheDir, Path.GetFileName(s)); File.Copy(Path.Combine(pluginDirectory, s), pluginCopy); #region Fix assemblies for refactor var module = ModuleDefinition.ReadModule(Path.Combine(pluginDirectory, s)); foreach (var @ref in module.AssemblyReferences) { // fix assembly references if (@ref.Name == "IllusionPlugin" || @ref.Name == "IllusionInjector") { @ref.Name = "IPA.Loader"; } } foreach (var @ref in module.GetTypeReferences()) { // fix type references if (@ref.FullName == "IllusionPlugin.IPlugin") { @ref.Namespace = "IPA.Old"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.IEnhancedPlugin") { @ref.Namespace = "IPA.Old"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.IBeatSaberPlugin") { @ref.Namespace = "IPA"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.IEnhancedBeatSaberPlugin") { @ref.Namespace = "IPA"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.BeatSaber.ModsaberModInfo") { @ref.Namespace = "IPA"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.IniFile") { @ref.Namespace = "IPA.Config"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.IModPrefs") { @ref.Namespace = "IPA.Config"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.ModPrefs") { @ref.Namespace = "IPA.Config"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.Utils.ReflectionUtil") { @ref.Namespace = "IPA.Utilities"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.Logging.Logger") { @ref.Namespace = "IPA.Logging"; //@ref.Name = ""; } if (@ref.FullName == "IllusionPlugin.Logging.LogPrinter") { @ref.Namespace = "IPA.Logging"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.PluginManager") { @ref.Namespace = "IPA.Loader"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.PluginComponent") { @ref.Namespace = "IPA.Loader"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.CompositeBSPlugin") { @ref.Namespace = "IPA.Loader.Composite"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.CompositeIPAPlugin") { @ref.Namespace = "IPA.Loader.Composite"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.Logging.UnityLogInterceptor") { @ref.Namespace = "IPA.Logging"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.Logging.StandardLogger") { @ref.Namespace = "IPA.Logging"; //@ref.Name = ""; } if (@ref.FullName == "IllusionInjector.Updating.SelfPlugin") { @ref.Namespace = "IPA.Updating"; //@ref.Name = ""; } 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.ModSaber"; //@ref.Name = ""; } } module.Write(pluginCopy); #endregion } var selfPlugin = new PluginInfo { Filename = Path.Combine(Environment.CurrentDirectory, "IPA.exe"), Plugin = SelfPlugin.Instance }; selfPlugin.ModSaberInfo = selfPlugin.Plugin.ModInfo; _bsPlugins.Add(selfPlugin); configProviders.Add(new KeyValuePair <IConfigProvider, Ref <DateTime> >(SelfConfigProvider = new JsonConfigProvider { Filename = Path.Combine("UserData", SelfPlugin.IPA_Name) }, new Ref <DateTime>(SelfConfigProvider.LastModified))); SelfConfigProvider.Load(); //Load copied plugins string[] copiedPlugins = Directory.GetFiles(cacheDir, "*.dll"); foreach (string s in copiedPlugins) { var result = LoadPluginsFromFile(s, exeName); _bsPlugins.AddRange(result.Item1); _ipaPlugins.AddRange(result.Item2); } Logger.log.Info(exeName); 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}"); Logger.log.Info("-----------------------------"); foreach (var plugin in _bsPlugins) { Logger.log.Info($"{plugin.Plugin.Name}: {plugin.Plugin.Version}"); } Logger.log.Info("-----------------------------"); foreach (var plugin in _ipaPlugins) { Logger.log.Info($"{plugin.Name}: {plugin.Version}"); } Logger.log.Info("-----------------------------"); }