using System; using System.IO; using System.Reactive; using System.Reactive.Linq; using System.Text; using System.Text.Json.Nodes; using Avalonia.Media; using MiNET.LevelDB; using ReactiveUI; namespace VaultSmpInstaller.ViewModels; public class ProfileWindow1ViewModel : ViewModelBase { public Interaction ShowProfileSelectionDialog { get; } public ReactiveCommand UseCurseforgeCommand { get; } public ReactiveCommand UsePrismCommand { get; } public ReactiveCommand UseOverwolfCommand { get; } public ProfileWindow1ViewModel() { var curseforgeDir = CurseforgeInstanceDir; var prismDir = PrismInstanceDir; var overwolfDir = OverwolfInstanceDir; ShowProfileSelectionDialog = new Interaction(); UseCurseforgeCommand = ReactiveCommand.CreateFromTask(async () => { var profileWindowModel = new ProfileWindow2ViewModel(ProfileWindow2ViewModel.InstanceType.Curseforge, curseforgeDir); return await ShowProfileSelectionDialog.Handle(profileWindowModel); }); UsePrismCommand = ReactiveCommand.CreateFromTask(async () => { var profileWindowModel = new ProfileWindow2ViewModel(ProfileWindow2ViewModel.InstanceType.Prism, prismDir); return await ShowProfileSelectionDialog.Handle(profileWindowModel); }); UseOverwolfCommand = ReactiveCommand.CreateFromTask(async () => { var profileWindowModel = new ProfileWindow2ViewModel(ProfileWindow2ViewModel.InstanceType.Overwolf, overwolfDir); return await ShowProfileSelectionDialog.Handle(profileWindowModel); }); } public static Brush Background => SolidColorBrush.Parse("#282A36"); public static Brush SecondaryBackground => SolidColorBrush.Parse("#44475A"); public static Brush ButtonBackground => SolidColorBrush.Parse("#6272A4"); public static Brush TextColor => SolidColorBrush.Parse("#F8F8F2"); private string? _curseforgeInstanceDir = null; public bool IsCurseforgeInstalled { get; set; } = false; public string CurseforgeButtonText => IsCurseforgeInstalled ? "Curseforge" : "Curseforge Not Detected"; public string? CurseforgeInstanceDir { get { if (_curseforgeInstanceDir == null && TryGetCurseforgeMinecraftRoot(out _curseforgeInstanceDir)) { IsCurseforgeInstalled = true; this.RaisePropertyChanged(nameof(IsCurseforgeInstalled)); this.RaisePropertyChanged(nameof(CurseforgeButtonText)); this.RaisePropertyChanged(); } return _curseforgeInstanceDir; } } public bool IsPrismInstalled { get; set; } = false; private string? _prismInstanceDir = null; public string PrismButtonText => IsPrismInstalled ? "Prism Launcher" : "Prism Launcher Not Detected"; public string? PrismInstanceDir { get { if (_prismInstanceDir == null && TryGetPrismMinecraftRoot(out _prismInstanceDir)) { IsPrismInstalled = true; this.RaisePropertyChanged(nameof(IsPrismInstalled)); this.RaisePropertyChanged(nameof(PrismButtonText)); this.RaisePropertyChanged(); } return _prismInstanceDir; } } public bool IsOverwolfInstalled { get; set; } = false; private string? _overwolfInstanceDir = null; public string OverwolfButtonText => IsOverwolfInstalled ? "Curseforge (Overwolf)" : "Curseforge (Overwolf) Not Detected"; public string? OverwolfInstanceDir { get { if (_overwolfInstanceDir == null && TryGetOverwolfMinecraftRoot(out _overwolfInstanceDir)) { IsOverwolfInstalled = true; this.RaisePropertyChanged(nameof(IsOverwolfInstalled)); this.RaisePropertyChanged(nameof(OverwolfButtonText)); this.RaisePropertyChanged(); } return _overwolfInstanceDir; } } public bool TryGetCurseforgeMinecraftRoot(out string? minecraftRoot) { minecraftRoot = null; var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); if (!File.Exists(Path.Combine(appData, "Curseforge", "storage.json"))) return false; var curseforgeConfig = JsonNode.Parse(File.ReadAllText(Path.Combine(appData, "Curseforge", "storage.json")))!.AsObject(); if (!curseforgeConfig.TryGetPropertyValue("minecraft-settings", out var minecraftSettingsNode)) { minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances"); return true; } if (!minecraftSettingsNode!.AsValue().TryGetValue(out string? minecraftSettingsString)) return false; var minecraftSettings = JsonNode.Parse(minecraftSettingsString); if (!minecraftSettings!.AsObject().TryGetPropertyValue("minecraftRoot", out var minecraftRootNode)) { minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances"); return true; } if (!minecraftRootNode!.AsValue().TryGetValue(out minecraftRoot)) return false; minecraftRoot = Path.Combine(minecraftRoot, "Instances"); return true; } public bool TryGetPrismMinecraftRoot(out string? minecraftRoot) { minecraftRoot = null; var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); if (!File.Exists(Path.Combine(appData, "PrismLauncher", "prismlauncher.cfg"))) return false; foreach(String line in File.ReadLines(Path.Combine(appData, "PrismLauncher", "prismlauncher.cfg"))) { if (line.StartsWith("InstanceDir")) { string path = line.Split('=', 2)[1]; if (Path.IsPathFullyQualified(path)) minecraftRoot = path; else minecraftRoot = Path.Combine(appData, "PrismLauncher", path); return true; } } return false; } public bool TryGetOverwolfMinecraftRoot(out string? minecraftRoot) { minecraftRoot = null; var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var overwolfDbDirectory = Path.Combine(localAppData, "Overwolf", "BrowserCache", "Local Storage", "leveldb"); if (!Directory.Exists(overwolfDbDirectory)) return false; var overwolfDb = new Database(new(overwolfDbDirectory), false, new Options() { ReadOnly = true }); byte[] databaseKey = new byte[] { 0x5F, 0x6F, 0x76, 0x65, 0x72, 0x77, 0x6F, 0x6C, 0x66, 0x2D, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x2F, 0x2F, 0x63, 0x63, 0x68, 0x68, 0x63, 0x61, 0x69, 0x61, 0x70, 0x65, 0x69, 0x6B, 0x6A, 0x62, 0x64, 0x62, 0x70, 0x66, 0x70, 0x6C, 0x67, 0x6D, 0x70, 0x6F, 0x62, 0x62, 0x63, 0x64, 0x6B, 0x64, 0x61, 0x70, 0x68, 0x63, 0x6C, 0x62, 0x6D, 0x6B, 0x62, 0x6A, 0x00, 0x01, 0x6D, 0x69, 0x6E, 0x65, 0x63, 0x72, 0x61, 0x66, 0x74, 0x2D, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73 }; String? curseforgeMinecraftSettings = ""; try { overwolfDb.Open(); curseforgeMinecraftSettings = Encoding.ASCII.GetString(overwolfDb.Get(databaseKey))[1..]; } catch (NullReferenceException e) { minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances"); return true; } finally { overwolfDb.Close(); overwolfDb.Dispose(); } if(String.IsNullOrEmpty(curseforgeMinecraftSettings)) { minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances"); return true; } var minecraftSettings = JsonNode.Parse(curseforgeMinecraftSettings); if (!minecraftSettings!.AsObject().TryGetPropertyValue("minecraftRoot", out var minecraftRootNode)) { minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances"); return true; } if (!minecraftRootNode!.AsValue().TryGetValue(out minecraftRoot)) return false; minecraftRoot = Path.Combine(minecraftRoot, "Instances"); return true; } }