Vortex Installer implemented

This commit is contained in:
Justin Swanson 2019-12-02 20:38:33 -06:00
parent a27268c9c1
commit d609e50afb
10 changed files with 234 additions and 68 deletions

View File

@ -336,7 +336,7 @@ namespace Wabbajack.Lib
new IgnoreDisabledVortexMods(this),
new IncludeVortexDeployment(this),
new IgnoreVortex(this),
new IgnoreRegex(this, "^*__vortex_staging_folder$"),
new IgnoreRegex(this, $"^*{StagingMarkerName}$"),
Game == Game.DarkestDungeon ? new IncludeRegex(this, "project\\.xml$") : null,
@ -396,6 +396,11 @@ namespace Wabbajack.Lib
{
return IsValidBaseStagingFolder(Path.GetDirectoryName(path));
}
public static bool IsActiveVortexGame(Game g)
{
return GameRegistry.Games[g].SupportedModManager == ModManager.Vortex && !GameRegistry.Games[g].Disabled;
}
}
public class VortexDeployment

View File

@ -47,10 +47,10 @@ namespace Wabbajack
public class InstallerSettings
{
public string LastInstalledListLocation { get; set; }
public Dictionary<string, ModlistInstallationSettings> ModlistSettings { get; } = new Dictionary<string, ModlistInstallationSettings>();
public Dictionary<string, Mo2ModlistInstallationSettings> Mo2ModlistSettings { get; } = new Dictionary<string, Mo2ModlistInstallationSettings>();
}
public class ModlistInstallationSettings
public class Mo2ModlistInstallationSettings
{
public string InstallationLocation { get; set; }
public string DownloadLocation { get; set; }

View File

@ -23,7 +23,7 @@ namespace Wabbajack
private static readonly ObservableCollectionExtended<GameVM> _gameOptions = new ObservableCollectionExtended<GameVM>(
EnumExt.GetValues<Game>()
.Where(g => GameRegistry.Games[g].SupportedModManager == ModManager.Vortex && !GameRegistry.Games[g].Disabled)
.Where(g => VortexCompiler.IsActiveVortexGame(g))
.Select(g => new GameVM(g))
.OrderBy(g => g.DisplayName));

View File

@ -1,4 +1,4 @@
using Syroot.Windows.IO;
using Syroot.Windows.IO;
using System;
using ReactiveUI;
using System.Diagnostics;
@ -49,10 +49,6 @@ namespace Wabbajack
[Reactive]
public bool InstallingMode { get; set; }
public FilePickerVM Location { get; }
public FilePickerVM DownloadLocation { get; }
private readonly ObservableAsPropertyHelper<ImageSource> _image;
public ImageSource Image => _image.Value;
@ -77,9 +73,6 @@ namespace Wabbajack
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
public ObservableCollectionExtended<string> Log => MWVM.Log;
private readonly ObservableAsPropertyHelper<ModlistInstallationSettings> _CurrentSettings;
public ModlistInstallationSettings CurrentSettings => _CurrentSettings.Value;
private readonly ObservableAsPropertyHelper<ModManager?> _TargetManager;
public ModManager? TargetManager => _TargetManager.Value;
@ -104,22 +97,6 @@ namespace Wabbajack
MWVM = mainWindowVM;
Location = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.ExistCheckOptions.Off,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select Installation Directory",
};
Location.AdditionalError = this.WhenAny(x => x.Location.TargetPath)
.Select(x => Utils.IsDirectoryPathValid(x));
DownloadLocation = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.ExistCheckOptions.Off,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select a location for MO2 downloads",
};
DownloadLocation.AdditionalError = this.WhenAny(x => x.DownloadLocation.TargetPath)
.Select(x => Utils.IsDirectoryPathValid(x));
ModListPath = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
@ -138,7 +115,7 @@ namespace Wabbajack
case ModManager.MO2:
return new MO2InstallerVM(this);
case ModManager.Vortex:
throw new NotImplementedException();
return new VortexInstallerVM(this);
default:
return null;
}
@ -153,21 +130,11 @@ namespace Wabbajack
.ToProperty(this, nameof(Installer));
// Load settings
_CurrentSettings = this.WhenAny(x => x.ModListPath.TargetPath)
.Select(path => path == null ? null : MWVM.Settings.Installer.ModlistSettings.TryCreate(path))
.ToProperty(this, nameof(CurrentSettings));
this.WhenAny(x => x.CurrentSettings)
.Pairwise()
.Subscribe(settingsPair =>
{
SaveSettings(settingsPair.Previous);
if (settingsPair.Current == null) return;
Location.TargetPath = settingsPair.Current.InstallationLocation;
DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation;
})
.DisposeWith(CompositeDisposable);
MWVM.Settings.SaveSignal
.Subscribe(_ => SaveSettings(CurrentSettings))
.Subscribe(_ =>
{
MWVM.Settings.Installer.LastInstalledListLocation = ModListPath.TargetPath;
})
.DisposeWith(CompositeDisposable);
_modList = this.WhenAny(x => x.ModListPath.TargetPath)
@ -267,18 +234,6 @@ namespace Wabbajack
.Select(x => x?.StartsWith("https://") ?? false)
.ObserveOnGuiThread());
// Have Installation location updates modify the downloads location if empty
this.WhenAny(x => x.Location.TargetPath)
.Skip(1) // Don't do it initially
.Subscribe(installPath =>
{
if (string.IsNullOrWhiteSpace(DownloadLocation.TargetPath))
{
DownloadLocation.TargetPath = Path.Combine(installPath, "downloads");
}
})
.DisposeWith(CompositeDisposable);
_progressTitle = Observable.CombineLatest(
this.WhenAny(x => x.Installing),
this.WhenAny(x => x.InstallingMode),
@ -346,13 +301,5 @@ namespace Wabbajack
}
}
}
private void SaveSettings(ModlistInstallationSettings settings)
{
MWVM.Settings.Installer.LastInstalledListLocation = ModListPath.TargetPath;
if (settings == null) return;
settings.InstallationLocation = Location.TargetPath;
settings.DownloadLocation = DownloadLocation.TargetPath;
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
@ -13,17 +15,45 @@ namespace Wabbajack
{
public class MO2InstallerVM : ViewModel, ISubInstallerVM
{
private InstallerVM _installerVM;
public IReactiveCommand BeginCommand { get; }
[Reactive]
public AInstaller ActiveInstallation { get; private set; }
private readonly ObservableAsPropertyHelper<Mo2ModlistInstallationSettings> _CurrentSettings;
public Mo2ModlistInstallationSettings CurrentSettings => _CurrentSettings.Value;
public FilePickerVM Location { get; }
public FilePickerVM DownloadLocation { get; }
public MO2InstallerVM(InstallerVM installerVM)
{
_installerVM = installerVM;
Location = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.ExistCheckOptions.Off,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select Installation Directory",
};
Location.AdditionalError = this.WhenAny(x => x.Location.TargetPath)
.Select(x => Utils.IsDirectoryPathValid(x));
DownloadLocation = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.ExistCheckOptions.Off,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select a location for MO2 downloads",
};
DownloadLocation.AdditionalError = this.WhenAny(x => x.DownloadLocation.TargetPath)
.Select(x => Utils.IsDirectoryPathValid(x));
BeginCommand = ReactiveCommand.CreateFromTask(
canExecute: Observable.CombineLatest(
installerVM.WhenAny(x => x.Location.InError),
installerVM.WhenAny(x => x.DownloadLocation.InError),
this.WhenAny(x => x.Location.InError),
this.WhenAny(x => x.DownloadLocation.InError),
resultSelector: (loc, download) =>
{
return !loc && !download;
@ -38,8 +68,8 @@ namespace Wabbajack
installer = new MO2Installer(
archive: installerVM.ModListPath.TargetPath,
modList: installerVM.ModList.SourceModList,
outputFolder: installerVM.Location.TargetPath,
downloadFolder: installerVM.DownloadLocation.TargetPath);
outputFolder: Location.TargetPath,
downloadFolder: DownloadLocation.TargetPath);
}
catch (Exception ex)
{
@ -75,10 +105,49 @@ namespace Wabbajack
}
});
});
// Have Installation location updates modify the downloads location if empty
this.WhenAny(x => x.Location.TargetPath)
.Skip(1) // Don't do it initially
.Subscribe(installPath =>
{
if (string.IsNullOrWhiteSpace(DownloadLocation.TargetPath))
{
DownloadLocation.TargetPath = Path.Combine(installPath, "downloads");
}
})
.DisposeWith(CompositeDisposable);
// Load settings
_CurrentSettings = installerVM.WhenAny(x => x.ModListPath.TargetPath)
.Select(path => path == null ? null : installerVM.MWVM.Settings.Installer.Mo2ModlistSettings.TryCreate(path))
.ToProperty(this, nameof(CurrentSettings));
this.WhenAny(x => x.CurrentSettings)
.Pairwise()
.Subscribe(settingsPair =>
{
SaveSettings(settingsPair.Previous);
if (settingsPair.Current == null) return;
Location.TargetPath = settingsPair.Current.InstallationLocation;
DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation;
})
.DisposeWith(CompositeDisposable);
installerVM.MWVM.Settings.SaveSignal
.Subscribe(_ => SaveSettings(CurrentSettings))
.DisposeWith(CompositeDisposable);
}
public void Unload()
{
SaveSettings(this.CurrentSettings);
}
private void SaveSettings(Mo2ModlistInstallationSettings settings)
{
_installerVM.MWVM.Settings.Installer.LastInstalledListLocation = _installerVM.ModListPath.TargetPath;
if (settings == null) return;
settings.InstallationLocation = Location.TargetPath;
settings.DownloadLocation = DownloadLocation.TargetPath;
}
}
}

View File

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.Lib;
namespace Wabbajack
{
public class VortexInstallerVM : ViewModel, ISubInstallerVM
{
public IReactiveCommand BeginCommand { get; }
[Reactive]
public AInstaller ActiveInstallation { get; private set; }
private readonly ObservableAsPropertyHelper<string> _DownloadLocation;
public string DownloadLocation => _DownloadLocation.Value;
private readonly ObservableAsPropertyHelper<string> _StagingLocation;
public string StagingLocation => _StagingLocation.Value;
private readonly ObservableAsPropertyHelper<Game> _TargetGame;
public Game TargetGame => _TargetGame.Value;
public VortexInstallerVM(InstallerVM installerVM)
{
_TargetGame = installerVM.WhenAny(x => x.ModList.SourceModList.GameType)
.ToProperty(this, nameof(TargetGame));
BeginCommand = ReactiveCommand.CreateFromTask(
canExecute: this.WhenAny(x => x.TargetGame)
.Select(game => VortexCompiler.IsActiveVortexGame(game)),
execute: async () =>
{
AInstaller installer;
try
{
var download = VortexCompiler.RetrieveDownloadLocation(TargetGame);
var staging = VortexCompiler.RetrieveStagingLocation(TargetGame);
installer = new VortexInstaller(
archive: installerVM.ModListPath.TargetPath,
modList: installerVM.ModList.SourceModList,
outputFolder: staging,
downloadFolder: download);
}
catch (Exception ex)
{
while (ex.InnerException != null) ex = ex.InnerException;
Utils.Log(ex.StackTrace);
Utils.Log(ex.ToString());
Utils.Log($"{ex.Message} - Can't continue");
ActiveInstallation = null;
return;
}
await Task.Run(async () =>
{
IDisposable subscription = null;
try
{
var workTask = installer.Begin();
ActiveInstallation = installer;
await workTask;
}
catch (Exception ex)
{
while (ex.InnerException != null) ex = ex.InnerException;
Utils.Log(ex.StackTrace);
Utils.Log(ex.ToString());
Utils.Log($"{ex.Message} - Can't continue");
}
finally
{
// Dispose of CPU tracking systems
subscription?.Dispose();
ActiveInstallation = null;
}
});
});
}
public void Unload()
{
}
}
}

View File

@ -324,6 +324,9 @@
<DataTemplate DataType="{x:Type local:MO2InstallerVM}">
<local:MO2InstallerConfigView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:VortexInstallerVM}">
<local:VortexInstallerConfigView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>

View File

@ -0,0 +1,14 @@
<UserControl
x:Class="Wabbajack.VortexInstallerConfigView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<!-- Nothing so far -->
</Grid>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for VortexInstallerConfigView.xaml
/// </summary>
public partial class VortexInstallerConfigView : UserControl
{
public VortexInstallerConfigView()
{
InitializeComponent();
}
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@ -174,6 +174,7 @@
</Compile>
<Compile Include="View Models\Installers\ISubInstallerVM.cs" />
<Compile Include="View Models\Installers\MO2InstallerVM.cs" />
<Compile Include="View Models\Installers\VortexInstallerVM.cs" />
<Compile Include="View Models\ModListGalleryVM.cs" />
<Compile Include="View Models\ModListMetadataVM.cs" />
<Compile Include="Views\Common\HeatedBackgroundView.xaml.cs">
@ -246,6 +247,9 @@
<Compile Include="Views\Compilers\VortexCompilerConfigView.xaml.cs">
<DependentUpon>VortexCompilerConfigView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Installers\VortexInstallerConfigView.xaml.cs">
<DependentUpon>VortexInstallerConfigView.xaml</DependentUpon>
</Compile>
<Page Include="Views\Installers\MO2InstallerConfigView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -332,6 +336,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Installers\VortexInstallerConfigView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">