Add overwolf support and fix curseforge
This commit is contained in:
parent
43b9ea727e
commit
0ccd38359a
@ -31,4 +31,9 @@
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.6"/>
|
||||
<PackageReference Include="FluentAvalonia.ProgressRing" Version="1.69.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\MiNET.LevelDB\MiNET.LevelDB\MiNET.LevelDB.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VaultSmpInstaller", "VaultSmpInstaller.csproj", "{5111A3E1-248F-43AF-A70B-51248B418BE9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiNET.LevelDB", "..\..\MiNET.LevelDB\MiNET.LevelDB\MiNET.LevelDB.csproj", "{7CD1B124-DEEE-4745-820F-C499E7AE3A6B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -12,5 +14,9 @@ Global
|
||||
{5111A3E1-248F-43AF-A70B-51248B418BE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5111A3E1-248F-43AF-A70B-51248B418BE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5111A3E1-248F-43AF-A70B-51248B418BE9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7CD1B124-DEEE-4745-820F-C499E7AE3A6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7CD1B124-DEEE-4745-820F-C499E7AE3A6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7CD1B124-DEEE-4745-820F-C499E7AE3A6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7CD1B124-DEEE-4745-820F-C499E7AE3A6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@ -2,8 +2,10 @@
|
||||
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;
|
||||
@ -14,11 +16,13 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
|
||||
public ReactiveCommand<Unit, ProfileWindow2ViewModel.InstanceInfo?> UseCurseforgeCommand { get; }
|
||||
public ReactiveCommand<Unit, ProfileWindow2ViewModel.InstanceInfo?> UsePrismCommand { get; }
|
||||
public ReactiveCommand<Unit, ProfileWindow2ViewModel.InstanceInfo?> UseOverwolfCommand { get; }
|
||||
|
||||
public ProfileWindow1ViewModel()
|
||||
{
|
||||
var curseforgeDir = CurseforgeInstanceDir;
|
||||
var prismDir = PrismInstanceDir;
|
||||
var overwolfDir = OverwolfInstanceDir;
|
||||
|
||||
ShowProfileSelectionDialog = new Interaction<ProfileWindow2ViewModel, ProfileWindow2ViewModel.InstanceInfo?>();
|
||||
|
||||
@ -33,6 +37,12 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -81,6 +91,26 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -90,11 +120,18 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
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)) return false;
|
||||
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)) return false;
|
||||
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");
|
||||
@ -123,4 +160,61 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ public class ProfileWindow2ViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InstanceType.Curseforge:
|
||||
case InstanceType.Curseforge: case InstanceType.Overwolf:
|
||||
foreach (var directory in Directory.EnumerateDirectories(instancesDir))
|
||||
{
|
||||
if (!File.Exists(Path.Combine(directory, "minecraftinstance.json"))) continue;
|
||||
@ -88,7 +88,7 @@ public class ProfileWindow2ViewModel : ViewModelBase
|
||||
|
||||
public enum InstanceType
|
||||
{
|
||||
Prism, Curseforge
|
||||
Prism, Curseforge, Overwolf
|
||||
}
|
||||
|
||||
public record InstanceInfo(String InstanceName, String InstancePath, String MinecraftPath, String ModsPath, String ConfigPath, String ScriptsPath);
|
||||
|
||||
@ -4,8 +4,6 @@ using System.IO.Compression;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
@ -193,14 +191,14 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
}
|
||||
}
|
||||
|
||||
if(!Directory.Exists(Path.Combine(viewModel.SelectedInstance.InstancePath, "originalFiles")))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(viewModel.SelectedInstance.InstancePath, "originalFiles"));
|
||||
}
|
||||
foreach (var path in viewModel.LatestInstanceConfig.ReplaceFiles.Keys)
|
||||
{
|
||||
var pathParts = path.Split(Path.DirectorySeparatorChar);
|
||||
var pathParts = path.Split('/');
|
||||
var currentPath = "";
|
||||
if(!Directory.Exists(Path.Combine(viewModel.SelectedInstance.InstancePath, "originalFiles")))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(viewModel.SelectedInstance.InstancePath, "originalFiles"));
|
||||
}
|
||||
foreach (var part in pathParts[0..^1])
|
||||
{
|
||||
currentPath = Path.Combine(currentPath, part);
|
||||
|
||||
@ -11,9 +11,10 @@
|
||||
Width="400" Height="175"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False">
|
||||
<Grid Background="{Binding Background}" RowDefinitions="Auto, *, *">
|
||||
<Grid Background="{Binding Background}" RowDefinitions="Auto, *, *, *">
|
||||
<TextBlock Grid.Row="0" FontSize="18" Margin="0, 10">Please Select Prism Launcher or Curseforge</TextBlock>
|
||||
<Button Grid.Row="1" Command="{Binding UsePrismCommand}" FontSize="18" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Margin="25, 5" Content="{Binding PrismButtonText}" IsEnabled="{Binding IsPrismInstalled}"/>
|
||||
<Button Grid.Row="2" Command="{Binding UseCurseforgeCommand}" FontSize="18" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Margin="25, 5" Content="{Binding CurseforgeButtonText}" IsEnabled="{Binding IsCurseforgeInstalled}"/>
|
||||
<Button Grid.Row="3" Command="{Binding UseOverwolfCommand}" FontSize="18" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Margin="25, 5" Content="{Binding OverwolfButtonText}" IsEnabled="{Binding IsOverwolfInstalled}"/>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@ -14,6 +14,7 @@ public partial class ProfileWindow1 : ReactiveWindow<ProfileWindow1ViewModel>
|
||||
|
||||
this.WhenActivated(d => d(ViewModel!.UseCurseforgeCommand.Subscribe(Close)));
|
||||
this.WhenActivated(d => d(ViewModel!.UsePrismCommand.Subscribe(Close)));
|
||||
this.WhenActivated(d => d(ViewModel!.UseOverwolfCommand.Subscribe(Close)));
|
||||
|
||||
this.WhenActivated(action =>
|
||||
action(ViewModel!.ShowProfileSelectionDialog.RegisterHandler(DoShowDialogAsync)));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user