VRCMelonAssistant/ModAssistant/Classes/Utils.cs

399 lines
16 KiB
C#
Raw Normal View History

using Microsoft.Win32;
2019-04-22 18:41:43 +12:00
using System;
using System.Collections.Generic;
2020-02-05 17:58:35 +13:00
using System.Diagnostics;
2019-04-22 18:41:43 +12:00
using System.IO;
using System.Linq;
2020-02-05 17:58:35 +13:00
using System.Management;
2019-04-22 18:41:43 +12:00
using System.Security.Cryptography;
2020-02-05 17:58:35 +13:00
using System.Security.Principal;
2019-04-22 18:41:43 +12:00
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
2020-02-05 17:58:35 +13:00
using System.Windows;
using static ModAssistant.Http;
2019-04-22 18:41:43 +12:00
namespace ModAssistant
{
public class Utils
{
public static bool IsAdmin = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
public static string ExePath = Process.GetCurrentProcess().MainModule.FileName;
2019-04-22 18:41:43 +12:00
public class Constants
{
public const string BeatSaberAPPID = "620980";
public const string BeatModsAPIUrl = "https://beatmods.com/api/v1/";
2019-12-20 18:25:34 +13:00
public const string TeknikAPIUrl = "https://api.teknik.io/v1/";
2019-04-22 18:41:43 +12:00
public const string BeatModsURL = "https://beatmods.com";
2020-02-18 21:39:31 +13:00
public const string BeatModsAlias = "https://alias.beatmods.com/aliases.json";
2019-12-21 00:06:21 +13:00
public const string WeebCDNAPIURL = "https://pat.assistant.moe/api/v1.0/";
2019-04-22 18:41:43 +12:00
public const string BeatModsModsOptions = "mod?status=approved";
public const string MD5Spacer = " ";
public static readonly char[] IllegalCharacters = new char[]
{
'<', '>', ':', '/', '\\', '|', '?', '*', '"',
'\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007',
'\u0008', '\u0009', '\u000a', '\u000b', '\u000c', '\u000d', '\u000e', '\u000d',
'\u000f', '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016',
'\u0017', '\u0018', '\u0019', '\u001a', '\u001b', '\u001c', '\u001d', '\u001f',
};
2019-04-22 18:41:43 +12:00
}
2019-12-20 18:25:34 +13:00
public class TeknikPasteResponse
{
public Result result;
public class Result
{
public string id;
public string url;
public string title;
public string syntax;
public DateTime? expiration;
public string password;
}
}
2019-12-21 00:06:21 +13:00
public class WeebCDNRandomResponse
{
public int index;
public string url;
public string ext;
}
2020-02-02 18:43:32 +13:00
public static void SendNotify(string message, string title = null)
2019-04-22 18:41:43 +12:00
{
2020-02-02 18:43:32 +13:00
string defaultTitle = (string)Application.Current.FindResource("Utils:NotificationTitle");
2019-04-22 18:41:43 +12:00
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
2020-02-02 18:43:32 +13:00
BalloonTipTitle = title ?? defaultTitle,
2019-04-22 18:41:43 +12:00
BalloonTipText = message
};
notification.ShowBalloonTip(5000);
notification.Dispose();
}
public static void StartAsAdmin(string Arguments, bool Close = false)
{
2020-02-02 21:38:11 +13:00
using (Process process = new Process())
{
2020-02-02 21:38:11 +13:00
process.StartInfo.FileName = Process.GetCurrentProcess().MainModule.FileName;
process.StartInfo.Arguments = Arguments;
process.StartInfo.UseShellExecute = true;
process.StartInfo.Verb = "runas";
try
{
process.Start();
if (!Close)
{
process.WaitForExit();
}
}
catch
{
MessageBox.Show((string)Application.Current.FindResource("Utils:RunAsAdmin"));
2020-02-02 21:38:11 +13:00
}
if (Close) Application.Current.Shutdown();
}
}
2019-04-22 18:41:43 +12:00
public static string CalculateMD5(string filename)
{
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(filename))
{
var hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
public static string GetInstallDir()
{
2020-02-02 21:12:25 +13:00
string InstallDir = Properties.Settings.Default.InstallFolder;
2020-02-02 21:42:15 +13:00
if (!string.IsNullOrEmpty(InstallDir)
&& Directory.Exists(InstallDir)
&& Directory.Exists(Path.Combine(InstallDir, "Beat Saber_Data", "Plugins"))
&& File.Exists(Path.Combine(InstallDir, "Beat Saber.exe")))
2019-04-22 18:41:43 +12:00
{
return InstallDir;
}
try
{
InstallDir = GetSteamDir();
}
catch { }
2020-02-02 21:42:15 +13:00
if (!string.IsNullOrEmpty(InstallDir))
2019-04-22 18:41:43 +12:00
{
return InstallDir;
}
try
{
InstallDir = GetOculusDir();
}
catch { }
2020-02-02 21:42:15 +13:00
if (!string.IsNullOrEmpty(InstallDir))
2019-04-22 18:41:43 +12:00
{
return InstallDir;
}
2020-02-02 18:43:32 +13:00
MessageBox.Show((string)Application.Current.FindResource("Utils:NoInstallFolder"));
2019-04-22 18:41:43 +12:00
InstallDir = GetManualDir();
2020-02-02 21:42:15 +13:00
if (!string.IsNullOrEmpty(InstallDir))
2019-04-22 18:41:43 +12:00
{
return InstallDir;
}
return null;
}
public static string SetDir(string directory, string store)
{
App.BeatSaberInstallDirectory = directory;
App.BeatSaberInstallType = store;
2019-05-25 08:32:34 +12:00
Pages.Options.Instance.InstallDirectory = directory;
Pages.Options.Instance.InstallType = store;
2019-04-22 18:41:43 +12:00
Properties.Settings.Default.InstallFolder = directory;
Properties.Settings.Default.StoreType = store;
Properties.Settings.Default.Save();
return directory;
}
public static string GetSteamDir()
{
string SteamInstall = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)?.OpenSubKey("SOFTWARE")?.OpenSubKey("WOW6432Node")?.OpenSubKey("Valve")?.OpenSubKey("Steam")?.GetValue("InstallPath").ToString();
if (string.IsNullOrEmpty(SteamInstall))
2019-04-22 18:41:43 +12:00
{
SteamInstall = Registry.LocalMachine.OpenSubKey("SOFTWARE")?.OpenSubKey("WOW6432Node")?.OpenSubKey("Valve")?.OpenSubKey("Steam")?.GetValue("InstallPath").ToString();
2019-04-22 18:41:43 +12:00
}
2020-02-02 21:38:11 +13:00
2020-02-02 21:42:15 +13:00
if (string.IsNullOrEmpty(SteamInstall)) return null;
2019-04-22 18:41:43 +12:00
string vdf = Path.Combine(SteamInstall, @"steamapps\libraryfolders.vdf");
if (!File.Exists(@vdf)) return null;
Regex regex = new Regex("\\s\"\\d\"\\s+\"(.+)\"");
2020-02-02 21:38:29 +13:00
List<string> SteamPaths = new List<string>
{
Path.Combine(SteamInstall, @"steamapps")
};
2019-04-22 18:41:43 +12:00
using (StreamReader reader = new StreamReader(@vdf))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Match match = regex.Match(line);
if (match.Success)
{
SteamPaths.Add(Path.Combine(match.Groups[1].Value.Replace(@"\\", @"\"), @"steamapps"));
}
}
}
regex = new Regex("\\s\"installdir\"\\s+\"(.+)\"");
foreach (string path in SteamPaths)
{
if (File.Exists(Path.Combine(@path, @"appmanifest_" + Constants.BeatSaberAPPID + ".acf")))
{
2020-02-03 00:04:30 +13:00
using (StreamReader reader = new StreamReader(Path.Combine(@path, @"appmanifest_" + Constants.BeatSaberAPPID + ".acf")))
2019-04-22 18:41:43 +12:00
{
string line;
while ((line = reader.ReadLine()) != null)
{
Match match = regex.Match(line);
if (match.Success)
{
if (File.Exists(Path.Combine(@path, @"common", match.Groups[1].Value, "Beat Saber.exe")))
{
return SetDir(Path.Combine(@path, @"common", match.Groups[1].Value), "Steam");
}
}
}
}
}
}
return null;
}
2019-12-19 16:27:11 +13:00
public static string GetVersion()
{
2019-12-19 16:27:11 +13:00
string filename = Path.Combine(App.BeatSaberInstallDirectory, "Beat Saber_Data", "globalgamemanagers");
using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
2019-12-19 16:27:11 +13:00
byte[] file = File.ReadAllBytes(filename);
byte[] bytes = new byte[16];
2019-12-19 16:27:11 +13:00
fs.Read(file, 0, Convert.ToInt32(fs.Length));
fs.Close();
int index = Encoding.Default.GetString(file).IndexOf("public.app-category.games") + 136;
2019-12-19 16:27:11 +13:00
Array.Copy(file, index, bytes, 0, 16);
string version = Encoding.Default.GetString(bytes).Trim(Utils.Constants.IllegalCharacters);
2019-12-19 16:27:11 +13:00
return version;
}
}
2019-04-22 18:41:43 +12:00
public static string GetOculusDir()
{
string OculusInstall = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)?.OpenSubKey("SOFTWARE")?.OpenSubKey("Wow6432Node")?.OpenSubKey("Oculus VR, LLC")?.OpenSubKey("Oculus")?.OpenSubKey("Config")?.GetValue("InitialAppLibrary").ToString();
2020-02-02 21:42:15 +13:00
if (string.IsNullOrEmpty(OculusInstall)) return null;
2019-04-22 18:41:43 +12:00
2020-02-02 21:42:15 +13:00
if (!string.IsNullOrEmpty(OculusInstall))
2019-04-22 18:41:43 +12:00
{
2019-05-22 12:59:51 +12:00
if (File.Exists(Path.Combine(OculusInstall, "Software", "hyperbolic-magnetism-beat-saber", "Beat Saber.exe")))
2019-04-22 18:41:43 +12:00
{
2019-05-22 12:59:51 +12:00
return SetDir(Path.Combine(OculusInstall, "Software", "hyperbolic-magnetism-beat-saber"), "Oculus");
2019-04-22 18:41:43 +12:00
}
}
// Yoinked this code from Umbranox's Mod Manager. Lot's of thanks and love for Umbra <3
using (RegistryKey librariesKey = Registry.CurrentUser.OpenSubKey("Software")?.OpenSubKey("Oculus VR, LLC")?.OpenSubKey("Oculus")?.OpenSubKey("Libraries"))
{
// Oculus libraries uses GUID volume paths like this "\\?\Volume{0fea75bf-8ad6-457c-9c24-cbe2396f1096}\Games\Oculus Apps", we need to transform these to "D:\Game"\Oculus Apps"
WqlObjectQuery wqlQuery = new WqlObjectQuery("SELECT * FROM Win32_Volume");
2020-02-02 21:38:11 +13:00
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(wqlQuery))
2019-04-22 18:41:43 +12:00
{
2020-02-02 21:38:11 +13:00
Dictionary<string, string> guidLetterVolumes = new Dictionary<string, string>();
2019-04-22 18:41:43 +12:00
2020-02-02 21:38:11 +13:00
foreach (ManagementBaseObject disk in searcher.Get())
2019-04-22 18:41:43 +12:00
{
2020-02-02 21:38:11 +13:00
var diskId = ((string)disk.GetPropertyValue("DeviceID")).Substring(11, 36);
var diskLetter = ((string)disk.GetPropertyValue("DriveLetter")) + @"\";
if (!string.IsNullOrWhiteSpace(diskLetter))
{
guidLetterVolumes.Add(diskId, diskLetter);
}
2019-04-22 18:41:43 +12:00
}
2020-02-02 21:38:11 +13:00
// Search among the library folders
foreach (string libraryKeyName in librariesKey.GetSubKeyNames())
2019-04-22 18:41:43 +12:00
{
2020-02-02 21:38:11 +13:00
using (RegistryKey libraryKey = librariesKey.OpenSubKey(libraryKeyName))
2019-04-22 18:41:43 +12:00
{
2020-02-02 21:38:11 +13:00
string libraryPath = (string)libraryKey.GetValue("Path");
// Yoinked this code from Megalon's fix. <3
string GUIDLetter = guidLetterVolumes.FirstOrDefault(x => libraryPath.Contains(x.Key)).Value;
2020-02-02 21:42:15 +13:00
if (!string.IsNullOrEmpty(GUIDLetter))
{
2020-02-02 21:38:11 +13:00
string finalPath = Path.Combine(GUIDLetter, libraryPath.Substring(49), @"Software\hyperbolic-magnetism-beat-saber");
if (File.Exists(Path.Combine(finalPath, "Beat Saber.exe")))
{
return SetDir(finalPath, "Oculus");
}
}
2019-04-22 18:41:43 +12:00
}
}
}
}
2020-02-02 21:38:11 +13:00
2019-04-22 18:41:43 +12:00
return null;
}
public static string GetManualDir()
{
var dialog = new Microsoft.Win32.SaveFileDialog()
{
2020-02-02 18:43:32 +13:00
Title = (string)Application.Current.FindResource("Utils:InstallDir:DialogTitle"),
2019-04-22 18:41:43 +12:00
Filter = "Directory|*.this.directory",
FileName = "select"
};
if (dialog.ShowDialog() == true)
{
string path = dialog.FileName;
path = path.Replace("\\select.this.directory", "");
path = path.Replace(".this.directory", "");
2019-05-30 13:27:20 +12:00
path = path.Replace("\\select.directory", "");
2019-04-22 18:41:43 +12:00
if (File.Exists(Path.Combine(path, "Beat Saber.exe")))
{
string store;
if (File.Exists(Path.Combine(path, "Beat Saber_Data", "Plugins", "steam_api64.dll")))
{
store = "Steam";
}
else
{
store = "Oculus";
}
return SetDir(path, store);
}
}
return null;
}
2020-02-02 21:11:06 +13:00
public static bool IsVoid()
{
string directory = App.BeatSaberInstallDirectory;
if (File.Exists(Path.Combine(directory, "IGG-GAMES.COM.url")) ||
File.Exists(Path.Combine(directory, "SmartSteamEmu.ini")) ||
File.Exists(Path.Combine(directory, "GAMESTORRENT.CO.url")) ||
File.Exists(Path.Combine(directory, "Beat Saber_Data", "Plugins", "BSteam crack.dll")) ||
File.Exists(Path.Combine(directory, "Beat Saber_Data", "Plugins", "HUHUVR_steam_api64.dll")) ||
Directory.GetFiles(Path.Combine(directory, "Beat Saber_Data", "Plugins"), "*.ini", SearchOption.TopDirectoryOnly).Length > 0)
return true;
return false;
}
2020-02-19 16:00:02 +13:00
public static byte[] StreamToArray(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
public static async Task Download(string link, string output)
{
var resp = await HttpClient.GetAsync(link);
using (var stream = await resp.Content.ReadAsStreamAsync())
using (var fs = new FileStream(output, FileMode.OpenOrCreate, FileAccess.Write))
{
await stream.CopyToAsync(fs);
}
}
private delegate void ShowMessageBoxDelegate(string Message, string Caption);
private static void ShowMessageBox(string Message, string Caption)
{
MessageBox.Show(Message, Caption);
}
public static void ShowMessageBoxAsync(string Message, string Caption)
{
ShowMessageBoxDelegate caller = new ShowMessageBoxDelegate(ShowMessageBox);
caller.BeginInvoke(Message, Caption, null, null);
}
public static void ShowMessageBoxAsync(string Message)
{
ShowMessageBoxDelegate caller = new ShowMessageBoxDelegate(ShowMessageBox);
caller.BeginInvoke(Message, null, null, null);
}
2019-04-22 18:41:43 +12:00
}
}