mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Merge remote-tracking branch 'wabbajack-tools/master' into modlist-image-fix
This commit is contained in:
commit
8af8e1bf14
BIN
Branding/PNGs/Wabba_Ded.png
Normal file
BIN
Branding/PNGs/Wabba_Ded.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
BIN
Branding/Project files/Wabba_Ded.psd
Normal file
BIN
Branding/Project files/Wabba_Ded.psd
Normal file
Binary file not shown.
@ -18,7 +18,14 @@ namespace Wabbajack
|
||||
{
|
||||
if (Exception != null)
|
||||
{
|
||||
return Exception.ToString();
|
||||
if (string.IsNullOrWhiteSpace(_reason))
|
||||
{
|
||||
return Exception.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{_reason}: {Exception.Message}";
|
||||
}
|
||||
}
|
||||
return _reason;
|
||||
}
|
||||
@ -53,9 +60,9 @@ namespace Wabbajack
|
||||
return new ErrorResponse(true, reason);
|
||||
}
|
||||
|
||||
public static ErrorResponse Fail(string reason)
|
||||
public static ErrorResponse Fail(string reason, Exception ex = null)
|
||||
{
|
||||
return new ErrorResponse(false, reason: reason);
|
||||
return new ErrorResponse(false, reason: reason, ex: ex);
|
||||
}
|
||||
|
||||
public static ErrorResponse Fail(Exception ex)
|
||||
|
@ -96,6 +96,12 @@ namespace Wabbajack.Common
|
||||
return Games.Values.FirstOrDefault(g => g.NexusName == gameName.ToLower());
|
||||
}
|
||||
|
||||
public static GameMetaData GetBySteamID(int id)
|
||||
{
|
||||
return Games.Values
|
||||
.FirstOrDefault(g => g.SteamIDs != null && g.SteamIDs.Count > 0 && g.SteamIDs.Any(i => i == id));
|
||||
}
|
||||
|
||||
public static IReadOnlyDictionary<Game, GameMetaData> Games = new Dictionary<Game, GameMetaData>
|
||||
{
|
||||
{
|
||||
|
@ -794,7 +794,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return ErrorResponse.Fail("Path was empty.");
|
||||
return ErrorResponse.Fail("Path is empty.");
|
||||
}
|
||||
try
|
||||
{
|
||||
@ -819,7 +819,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
return ErrorResponse.Fail("Path was empty");
|
||||
return ErrorResponse.Fail("Path is empty");
|
||||
}
|
||||
try
|
||||
{
|
||||
|
@ -18,15 +18,23 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
public bool IgnoreMissingFiles { get; internal set; } = false;
|
||||
|
||||
public string OutputFolder { get; set; }
|
||||
public string DownloadFolder { get; set; }
|
||||
public string OutputFolder { get; private set; }
|
||||
public string DownloadFolder { get; private set; }
|
||||
|
||||
public ModManager ModManager;
|
||||
public abstract ModManager ModManager { get; }
|
||||
|
||||
public string ModListArchive { get; internal set; }
|
||||
public ModList ModList { get; internal set; }
|
||||
public string ModListArchive { get; private set; }
|
||||
public ModList ModList { get; private set; }
|
||||
public Dictionary<string, string> HashedArchives { get; set; }
|
||||
|
||||
public AInstaller(string archive, ModList modList, string outputFolder, string downloadFolder)
|
||||
{
|
||||
ModList = modList;
|
||||
ModListArchive = archive;
|
||||
OutputFolder = outputFolder;
|
||||
DownloadFolder = downloadFolder;
|
||||
}
|
||||
|
||||
public void Info(string msg)
|
||||
{
|
||||
Utils.Log(msg);
|
||||
|
@ -23,7 +23,7 @@ namespace Wabbajack.Lib
|
||||
typeof(MegaDownloader.State), typeof(ModDBDownloader.State), typeof(NexusDownloader.State),
|
||||
typeof(BSAStateObject), typeof(BSAFileStateObject), typeof(BA2StateObject), typeof(BA2DX10EntryState),
|
||||
typeof(BA2FileEntryState), typeof(MediaFireDownloader.State), typeof(ArchiveMeta),
|
||||
typeof(PropertyFile)
|
||||
typeof(PropertyFile), typeof(SteamMeta), typeof(SteamWorkshopDownloader), typeof(SteamWorkshopDownloader.State)
|
||||
|
||||
}
|
||||
};
|
||||
|
70
Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs
Normal file
70
Wabbajack.Lib/CompilationSteps/IncludeSteamWorkshopItems.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
public class IncludeSteamWorkshopItems : ACompilationStep
|
||||
{
|
||||
private readonly SteamGame _game;
|
||||
private readonly Regex _regex = new Regex("steamWorkshopItem_\\d*\\.meta$");
|
||||
|
||||
public IncludeSteamWorkshopItems(ACompiler compiler, SteamGame steamGame) : base(compiler)
|
||||
{
|
||||
_game = steamGame;
|
||||
}
|
||||
|
||||
public override Directive Run(RawSourceFile source)
|
||||
{
|
||||
if (!_regex.IsMatch(source.Path))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var lines = File.ReadAllLines(source.AbsolutePath);
|
||||
var id = 0;
|
||||
lines.Where(l => l.StartsWith("itemID=")).Do(l => int.TryParse(l.Replace("itemID=", ""), out id));
|
||||
if (id == 0)
|
||||
return null;
|
||||
|
||||
SteamWorkshopItem item = null;
|
||||
_game.WorkshopItems.Where(i => i.ItemID == id).Do(i => item = i);
|
||||
if (item == null)
|
||||
return null;
|
||||
|
||||
var fromSteam = source.EvolveTo<SteamMeta>();
|
||||
fromSteam.SourceDataID = _compiler.IncludeFile(source.AbsolutePath);
|
||||
fromSteam.ItemID = item.ItemID;
|
||||
fromSteam.Size = item.Size;
|
||||
return fromSteam;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.LogToFile($"Exception while trying to evolve source to FromSteam\n{e}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override IState GetState()
|
||||
{
|
||||
return new State(_game);
|
||||
}
|
||||
|
||||
public class State : IState
|
||||
{
|
||||
private readonly SteamGame _game;
|
||||
|
||||
public State(SteamGame game)
|
||||
{
|
||||
_game = game;
|
||||
}
|
||||
|
||||
public ICompilationStep CreateStep(ACompiler compiler)
|
||||
{
|
||||
return new IncludeSteamWorkshopItems(compiler, _game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -169,6 +169,15 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
}
|
||||
|
||||
public class SteamMeta : ArchiveMeta
|
||||
{
|
||||
public int ItemID;
|
||||
/// <summary>
|
||||
/// Size is in bytes
|
||||
/// </summary>
|
||||
public int Size;
|
||||
}
|
||||
|
||||
[MemberConfig(TargetMember.All)]
|
||||
public class FromArchive : Directive
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@ -95,7 +96,6 @@ namespace Wabbajack.Lib.Downloaders
|
||||
{
|
||||
}
|
||||
|
||||
;
|
||||
if (stream.IsFaulted || response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
Utils.Log($"While downloading {Url} - {stream.Exception.ExceptionToString()}");
|
||||
@ -111,6 +111,11 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
var contentSize = headerVar != null ? long.Parse(headerVar) : 1;
|
||||
|
||||
FileInfo fileInfo = new FileInfo(destination);
|
||||
if (!fileInfo.Directory.Exists)
|
||||
{
|
||||
Directory.CreateDirectory(fileInfo.Directory.FullName);
|
||||
}
|
||||
|
||||
using (var webs = stream.Result)
|
||||
using (var fs = File.OpenWrite(destination))
|
||||
|
97
Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs
Normal file
97
Wabbajack.Lib/Downloaders/SteamWorkshopDownloader.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.Validation;
|
||||
|
||||
namespace Wabbajack.Lib.Downloaders
|
||||
{
|
||||
public class SteamWorkshopDownloader : IUrlDownloader
|
||||
{
|
||||
private SteamWorkshopItem _item;
|
||||
|
||||
public AbstractDownloadState GetDownloaderState(dynamic archiveINI)
|
||||
{
|
||||
var id = archiveINI?.General?.itemID;
|
||||
var steamID = archiveINI?.General?.steamID;
|
||||
var size = archiveINI?.General?.itemSize;
|
||||
_item = new SteamWorkshopItem
|
||||
{
|
||||
ItemID = id != null ? int.Parse(id) : 0,
|
||||
Size = size != null ? int.Parse(size) : 0,
|
||||
Game = steamID != null ? GameRegistry.GetBySteamID(int.Parse(steamID)) : null
|
||||
};
|
||||
return new State {Item = _item};
|
||||
}
|
||||
|
||||
public void Prepare()
|
||||
{
|
||||
}
|
||||
|
||||
public AbstractDownloadState GetDownloaderState(string url)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public class State : AbstractDownloadState
|
||||
{
|
||||
public SteamWorkshopItem Item { get; set; }
|
||||
public override bool IsWhitelisted(ServerWhitelist whitelist)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Download(Archive a, string destination)
|
||||
{
|
||||
var currentLib = "";
|
||||
SteamHandler.Instance.InstallFolders.Where(f => f.Contains(Item.Game.InstallDir)).Do(s => currentLib = s);
|
||||
|
||||
var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", Item.Game.AppId.ToString());
|
||||
var contentFolder = Path.Combine(currentLib, "workshop", "content", Item.Game.AppId.ToString());
|
||||
var p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = Path.Combine(SteamHandler.Instance.SteamPath, "steam.exe"),
|
||||
CreateNoWindow = true,
|
||||
Arguments = $"console +workshop_download_item {Item.Game.AppId} {Item.ItemID}"
|
||||
}
|
||||
};
|
||||
|
||||
p.Start();
|
||||
|
||||
//TODO: async
|
||||
var finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
if(!Directory.Exists(Path.Combine(downloadFolder, Item.ItemID.ToString())))
|
||||
if (Directory.Exists(Path.Combine(contentFolder, Item.ItemID.ToString())))
|
||||
finished = true;
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Verify()
|
||||
{
|
||||
//TODO: find a way to verify steam workshop items
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IDownloader GetDownloader()
|
||||
{
|
||||
return DownloadDispatcher.GetInstance<SteamWorkshopDownloader>();
|
||||
}
|
||||
|
||||
public override string GetReportEntry(Archive a)
|
||||
{
|
||||
return $"* Steam - [{Item.ItemID}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,18 +16,20 @@ namespace Wabbajack.Lib
|
||||
public class MO2Installer : AInstaller
|
||||
{
|
||||
public bool WarnOnOverwrite { get; set; } = true;
|
||||
|
||||
public MO2Installer(string archive, ModList modList, string outputFolder)
|
||||
{
|
||||
ModManager = ModManager.MO2;
|
||||
ModListArchive = archive;
|
||||
OutputFolder = outputFolder;
|
||||
DownloadFolder = Path.Combine(OutputFolder, "downloads");
|
||||
ModList = modList;
|
||||
}
|
||||
|
||||
public override ModManager ModManager => ModManager.MO2;
|
||||
|
||||
public string GameFolder { get; set; }
|
||||
|
||||
public MO2Installer(string archive, ModList modList, string outputFolder, string downloadFolder)
|
||||
: base(
|
||||
archive: archive,
|
||||
modList: modList,
|
||||
outputFolder: outputFolder,
|
||||
downloadFolder: downloadFolder)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool _Begin()
|
||||
{
|
||||
ConfigureProcessor(17, RecommendQueueSize());
|
||||
|
@ -73,6 +73,14 @@ namespace Wabbajack.Lib
|
||||
NoWrapText($" * Size : {archive.Size.ToFileSizeString()}");
|
||||
NoWrapText($" * SHA256 : [{hash}](https://www.virustotal.com/gui/file/{hash})");
|
||||
}
|
||||
lst.Directives.Where(d => d is SteamMeta).Do(f =>
|
||||
{
|
||||
if (f is SteamMeta s)
|
||||
{
|
||||
var link = $"https://steamcommunity.com/sharedfiles/filedetails/?id={s.ItemID}";
|
||||
NoWrapText($"* Steam Workshop Item: [{s.ItemID}]({link}) | Size: {s.Size}");
|
||||
}
|
||||
});
|
||||
|
||||
Text("\n\n");
|
||||
var patched = lst.Directives.OfType<PatchedFromArchive>().OrderBy(p => p.To).ToList();
|
||||
@ -134,4 +142,4 @@ namespace Wabbajack.Lib
|
||||
return lstArchives.OrderByDescending(a => a.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ namespace Wabbajack.Lib
|
||||
public const string StagingMarkerName = "__vortex_staging_folder";
|
||||
public const string DownloadMarkerName = "__vortex_downloads_folder";
|
||||
|
||||
private bool _isSteamGame;
|
||||
private SteamGame _steamGame;
|
||||
private bool _hasSteamWorkshopItems;
|
||||
|
||||
public VortexCompiler(Game game, string gamePath, string vortexFolder, string downloadsFolder, string stagingFolder, string outputFile)
|
||||
{
|
||||
Game = game;
|
||||
@ -52,6 +56,15 @@ namespace Wabbajack.Lib
|
||||
ModListOutputFolder = "output_folder";
|
||||
ModListOutputFile = outputFile;
|
||||
|
||||
// there can be max one game after filtering
|
||||
SteamHandler.Instance.Games.Where(g => g.Game != null && g.Game == game).Do(g =>
|
||||
{
|
||||
_isSteamGame = true;
|
||||
_steamGame = g;
|
||||
SteamHandler.Instance.LoadWorkshopItems(_steamGame);
|
||||
_hasSteamWorkshopItems = _steamGame.WorkshopItems.Count > 0;
|
||||
});
|
||||
|
||||
ActiveArchives = new List<string>();
|
||||
}
|
||||
|
||||
@ -310,6 +323,38 @@ namespace Wabbajack.Lib
|
||||
ActiveArchives.Add(Path.GetFileNameWithoutExtension(f));
|
||||
}
|
||||
});
|
||||
|
||||
Utils.Log($"Checking for Steam Workshop Items...");
|
||||
if (!_isSteamGame || _steamGame == null || _steamGame.WorkshopItems.Count <= 0)
|
||||
return;
|
||||
|
||||
_steamGame.WorkshopItems.Do(item =>
|
||||
{
|
||||
Utils.Log($"Creating meta file for {item.ItemID}");
|
||||
var metaString = "[General]\n" +
|
||||
"repository=Steam\n" +
|
||||
"installed=true\n" +
|
||||
$"gameName={GameName}\n" +
|
||||
$"steamID={_steamGame.AppId}\n" +
|
||||
$"itemID={item.ItemID}\n" +
|
||||
$"itemSize={item.Size}\n";
|
||||
|
||||
var filePath = Path.Combine(DownloadsFolder, $"steamWorkshopItem_{item.ItemID}.meta");
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
Utils.Log($"File {filePath} already exists, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(filePath, metaString);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.LogToFile($"Exception while writing to disk at {filePath}\n{e}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override IEnumerable<ICompilationStep> GetStack()
|
||||
@ -333,10 +378,12 @@ namespace Wabbajack.Lib
|
||||
return new List<ICompilationStep>
|
||||
{
|
||||
new IncludePropertyFiles(this),
|
||||
new IncludeSteamWorkshopItems(this, _steamGame),
|
||||
_hasSteamWorkshopItems ? new IncludeRegex(this, "^steamWorkshopItem_\\d*\\.meta$") : null,
|
||||
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 +443,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
|
||||
|
@ -1,4 +1,6 @@
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Directory = Alphaleonis.Win32.Filesystem.Directory;
|
||||
using File = Alphaleonis.Win32.Filesystem.File;
|
||||
@ -10,20 +12,31 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
public GameMetaData GameInfo { get; internal set; }
|
||||
|
||||
public VortexInstaller(string archive, ModList modList)
|
||||
{
|
||||
ModManager = ModManager.Vortex;
|
||||
ModListArchive = archive;
|
||||
ModList = modList;
|
||||
public override ModManager ModManager => ModManager.Vortex;
|
||||
|
||||
public VortexInstaller(string archive, ModList modList, string outputFolder, string downloadFolder)
|
||||
: base(
|
||||
archive: archive,
|
||||
modList: modList,
|
||||
outputFolder: outputFolder,
|
||||
downloadFolder: downloadFolder)
|
||||
{
|
||||
#if DEBUG
|
||||
// TODO: only for testing
|
||||
IgnoreMissingFiles = true;
|
||||
#endif
|
||||
|
||||
GameInfo = GameRegistry.Games[ModList.GameType];
|
||||
}
|
||||
|
||||
protected override bool _Begin()
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Vortex Support is still experimental and may produce unexpected results. " +
|
||||
"If anything fails go to the special vortex support channels on the discord. @erri120#2285 " +
|
||||
"for support.", "Warning",
|
||||
MessageBoxButton.OK);
|
||||
|
||||
ConfigureProcessor(10, RecommendQueueSize());
|
||||
Directory.CreateDirectory(DownloadFolder);
|
||||
|
||||
@ -47,12 +60,58 @@ namespace Wabbajack.Lib
|
||||
BuildFolderStructure();
|
||||
InstallArchives();
|
||||
InstallIncludedFiles();
|
||||
InstallSteamWorkshopItems();
|
||||
//InstallIncludedDownloadMetas();
|
||||
|
||||
Info("Installation complete! You may exit the program.");
|
||||
return true;
|
||||
}
|
||||
|
||||
private void InstallSteamWorkshopItems()
|
||||
{
|
||||
//var currentLib = "";
|
||||
SteamGame currentSteamGame = null;
|
||||
SteamHandler.Instance.Games.Where(g => g.Game == GameInfo.Game).Do(s => currentSteamGame = s);
|
||||
/*SteamHandler.Instance.InstallFolders.Where(f => f.Contains(currentSteamGame.InstallDir)).Do(s => currentLib = s);
|
||||
|
||||
var downloadFolder = Path.Combine(currentLib, "workshop", "downloads", currentSteamGame.AppId.ToString());
|
||||
var contentFolder = Path.Combine(currentLib, "workshop", "content", currentSteamGame.AppId.ToString());
|
||||
*/
|
||||
if (!ModList.Directives.Any(s => s is SteamMeta))
|
||||
return;
|
||||
|
||||
var result = MessageBox.Show("The ModList you are installing requires Steam Workshop Items to exist. " +
|
||||
"You can check the Workshop Items in the manifest of this ModList. Wabbajack can start Steam for you " +
|
||||
"and download the Items automatically. Do you want to proceed with this step?",
|
||||
"Warning", MessageBoxButton.YesNo);
|
||||
|
||||
if (result != MessageBoxResult.Yes)
|
||||
return;
|
||||
|
||||
ModList.Directives.OfType<SteamMeta>()
|
||||
.PMap(Queue, item =>
|
||||
{
|
||||
Status("Extracting Steam meta file to temp folder");
|
||||
var path = Path.Combine(DownloadFolder, $"steamWorkshopItem_{item.ItemID}.meta");
|
||||
if (!File.Exists(path))
|
||||
File.WriteAllBytes(path, LoadBytesFromPath(item.SourceDataID));
|
||||
|
||||
Status("Downloading Steam Workshop Item through steam cmd");
|
||||
|
||||
var p = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = System.IO.Path.Combine(SteamHandler.Instance.SteamPath, "steam.exe"),
|
||||
CreateNoWindow = true,
|
||||
Arguments = $"console +workshop_download_item {currentSteamGame.AppId} {item.ItemID}"
|
||||
}
|
||||
};
|
||||
|
||||
p.Start();
|
||||
});
|
||||
}
|
||||
|
||||
private void InstallIncludedFiles()
|
||||
{
|
||||
Info("Writing inline files");
|
||||
|
@ -103,6 +103,7 @@
|
||||
<Compile Include="CompilationSteps\IncludePatches.cs" />
|
||||
<Compile Include="CompilationSteps\IncludePropertyFiles.cs" />
|
||||
<Compile Include="CompilationSteps\IncludeRegex.cs" />
|
||||
<Compile Include="CompilationSteps\IncludeSteamWorkshopItems.cs" />
|
||||
<Compile Include="CompilationSteps\IncludeStubbedConfigFiles.cs" />
|
||||
<Compile Include="CompilationSteps\IncludeTaggedMods.cs" />
|
||||
<Compile Include="CompilationSteps\IncludeThisProfile.cs" />
|
||||
@ -110,6 +111,7 @@
|
||||
<Compile Include="CompilationSteps\IStackStep.cs" />
|
||||
<Compile Include="CompilationSteps\PatchStockESMs.cs" />
|
||||
<Compile Include="CompilationSteps\Serialization.cs" />
|
||||
<Compile Include="Downloaders\SteamWorkshopDownloader.cs" />
|
||||
<Compile Include="MO2Compiler.cs" />
|
||||
<Compile Include="Data.cs" />
|
||||
<Compile Include="Downloaders\AbstractDownloadState.cs" />
|
||||
|
@ -49,9 +49,12 @@ namespace Wabbajack.Test
|
||||
protected void Install(MO2Compiler compiler)
|
||||
{
|
||||
var modlist = AInstaller.LoadFromFile(compiler.ModListOutputFile);
|
||||
var installer = new MO2Installer(compiler.ModListOutputFile, modlist, utils.InstallFolder);
|
||||
var installer = new MO2Installer(
|
||||
archive: compiler.ModListOutputFile,
|
||||
modList: modlist,
|
||||
outputFolder: utils.InstallFolder,
|
||||
downloadFolder: utils.DownloadsFolder);
|
||||
installer.WarnOnOverwrite = false;
|
||||
installer.DownloadFolder = utils.DownloadsFolder;
|
||||
installer.GameFolder = utils.GameFolder;
|
||||
installer.Begin().Wait();
|
||||
}
|
||||
|
@ -62,9 +62,12 @@ namespace Wabbajack.Test
|
||||
protected void Install(VortexCompiler vortexCompiler)
|
||||
{
|
||||
var modList = AInstaller.LoadFromFile(vortexCompiler.ModListOutputFile);
|
||||
var installer = new MO2Installer(vortexCompiler.ModListOutputFile, modList, utils.InstallFolder)
|
||||
var installer = new MO2Installer(
|
||||
archive: vortexCompiler.ModListOutputFile,
|
||||
modList: modList,
|
||||
outputFolder: utils.InstallFolder,
|
||||
downloadFolder: utils.DownloadsFolder)
|
||||
{
|
||||
DownloadFolder = utils.DownloadsFolder,
|
||||
GameFolder = utils.GameFolder,
|
||||
};
|
||||
installer.Begin().Wait();
|
||||
|
@ -147,8 +147,11 @@ namespace Wabbajack.Test
|
||||
private void Install(MO2Compiler compiler)
|
||||
{
|
||||
var modlist = AInstaller.LoadFromFile(compiler.ModListOutputFile);
|
||||
var installer = new MO2Installer(compiler.ModListOutputFile, modlist, utils.InstallFolder);
|
||||
installer.DownloadFolder = utils.DownloadsFolder;
|
||||
var installer = new MO2Installer(
|
||||
archive: compiler.ModListOutputFile,
|
||||
modList: modlist,
|
||||
outputFolder: utils.InstallFolder,
|
||||
downloadFolder: utils.DownloadsFolder);
|
||||
installer.GameFolder = utils.GameFolder;
|
||||
installer.Begin().Wait();
|
||||
}
|
||||
|
@ -14,19 +14,7 @@ namespace Wabbajack
|
||||
{
|
||||
public App()
|
||||
{
|
||||
// Wire any unhandled crashing exceptions to log before exiting
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
|
||||
{
|
||||
// Don't do any special logging side effects
|
||||
Utils.Log("Uncaught error:");
|
||||
Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
|
||||
};
|
||||
|
||||
var appPath = Assembly.GetExecutingAssembly().Location;
|
||||
if (!ExtensionManager.IsAssociated() || ExtensionManager.NeedsUpdating(appPath))
|
||||
{
|
||||
ExtensionManager.Associate(appPath);
|
||||
}
|
||||
// Initialization in MainWindow ctor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
Wabbajack/Resources/Wabba_Ded.png
Normal file
BIN
Wabbajack/Resources/Wabba_Ded.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
@ -24,11 +24,15 @@ namespace Wabbajack
|
||||
private Subject<Unit> _saveSignal = new Subject<Unit>();
|
||||
public IObservable<Unit> SaveSignal => _saveSignal;
|
||||
|
||||
public static MainSettings LoadSettings()
|
||||
public static bool TryLoadTypicalSettings(out MainSettings settings)
|
||||
{
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
if (!File.Exists(_filename) || args.Length > 1 && args[1] == "nosettings") return new MainSettings();
|
||||
return JsonConvert.DeserializeObject<MainSettings>(File.ReadAllText(_filename));
|
||||
if (!File.Exists(_filename))
|
||||
{
|
||||
settings = default;
|
||||
return false;
|
||||
}
|
||||
settings = JsonConvert.DeserializeObject<MainSettings>(File.ReadAllText(_filename));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void SaveSettings(MainSettings settings)
|
||||
@ -47,10 +51,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; }
|
||||
|
@ -28,9 +28,6 @@ namespace Wabbajack
|
||||
private readonly ObservableAsPropertyHelper<ModlistSettingsEditorVM> _currentModlistSettings;
|
||||
public ModlistSettingsEditorVM CurrentModlistSettings => _currentModlistSettings.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<StatusUpdateTracker> _currentStatusTracker;
|
||||
public StatusUpdateTracker CurrentStatusTracker => _currentStatusTracker.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<bool> _compiling;
|
||||
public bool Compiling => _compiling.Value;
|
||||
|
||||
@ -86,10 +83,6 @@ namespace Wabbajack
|
||||
_currentModlistSettings = this.WhenAny(x => x.Compiler.ModlistSettings)
|
||||
.ToProperty(this, nameof(CurrentModlistSettings));
|
||||
|
||||
// Let sub VM determine what progress we're seeing
|
||||
_currentStatusTracker = this.WhenAny(x => x.Compiler.StatusTracker)
|
||||
.ToProperty(this, nameof(CurrentStatusTracker));
|
||||
|
||||
_image = this.WhenAny(x => x.CurrentModlistSettings.ImagePath.TargetPath)
|
||||
// Throttle so that it only loads image after any sets of swaps have completed
|
||||
.Throttle(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
|
||||
|
@ -10,7 +10,6 @@ namespace Wabbajack
|
||||
ACompiler ActiveCompilation { get; }
|
||||
|
||||
ModlistSettingsEditorVM ModlistSettings { get; }
|
||||
StatusUpdateTracker StatusTracker { get;}
|
||||
void Unload();
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
@ -190,10 +190,10 @@ namespace Wabbajack
|
||||
{
|
||||
Title = PromptTitle,
|
||||
IsFolderPicker = PathType == PathTypeOptions.Folder,
|
||||
InitialDirectory = TargetPath,
|
||||
InitialDirectory = dirPath,
|
||||
AddToMostRecentlyUsedList = false,
|
||||
AllowNonFileSystemItems = false,
|
||||
DefaultDirectory = TargetPath,
|
||||
DefaultDirectory = dirPath,
|
||||
EnsureFileExists = true,
|
||||
EnsurePathExists = true,
|
||||
EnsureReadOnly = false,
|
||||
|
18
Wabbajack/View Models/Installers/ISubInstallerVM.cs
Normal file
18
Wabbajack/View Models/Installers/ISubInstallerVM.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ReactiveUI;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public interface ISubInstallerVM
|
||||
{
|
||||
IReactiveCommand BeginCommand { get; }
|
||||
AInstaller ActiveInstallation { get; }
|
||||
void Unload();
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ using ReactiveUI.Fody.Helpers;
|
||||
using System.Windows.Media;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using System.Reactive;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -27,21 +28,19 @@ namespace Wabbajack
|
||||
public MainWindowVM MWVM { get; }
|
||||
|
||||
public BitmapImage WabbajackLogo { get; } = UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Wabbajack;component/Resources/Wabba_Mouth_No_Text.png")).Stream);
|
||||
public BitmapImage WabbajackErrLogo { get; } = UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Wabbajack;component/Resources/Wabba_Ded.png")).Stream);
|
||||
|
||||
private readonly ObservableAsPropertyHelper<ModListVM> _modList;
|
||||
public ModListVM ModList => _modList.Value;
|
||||
|
||||
public FilePickerVM ModListPath { get; }
|
||||
public FilePickerVM ModListLocation { get; }
|
||||
|
||||
[Reactive]
|
||||
public bool UIReady { get; set; }
|
||||
private readonly ObservableAsPropertyHelper<ISubInstallerVM> _installer;
|
||||
public ISubInstallerVM Installer => _installer.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<string> _htmlReport;
|
||||
public string HTMLReport => _htmlReport.Value;
|
||||
|
||||
[Reactive]
|
||||
public AInstaller ActiveInstallation { get; private set; }
|
||||
|
||||
private readonly ObservableAsPropertyHelper<bool> _installing;
|
||||
public bool Installing => _installing.Value;
|
||||
|
||||
@ -51,10 +50,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;
|
||||
|
||||
@ -79,11 +74,10 @@ 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;
|
||||
|
||||
// Command properties
|
||||
public IReactiveCommand BeginCommand { get; }
|
||||
public IReactiveCommand ShowReportCommand { get; }
|
||||
public IReactiveCommand OpenReadmeCommand { get; }
|
||||
public IReactiveCommand VisitWebsiteCommand { get; }
|
||||
@ -104,56 +98,53 @@ 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()
|
||||
ModListLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.File,
|
||||
PromptTitle = "Select a modlist to install"
|
||||
};
|
||||
|
||||
// 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 =>
|
||||
// Swap to proper sub VM based on selected type
|
||||
_installer = this.WhenAny(x => x.TargetManager)
|
||||
// Delay so the initial VM swap comes in immediately, subVM comes right after
|
||||
.DelayInitial(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler)
|
||||
.Select<ModManager?, ISubInstallerVM>(type =>
|
||||
{
|
||||
SaveSettings(settingsPair.Previous);
|
||||
if (settingsPair.Current == null) return;
|
||||
Location.TargetPath = settingsPair.Current.InstallationLocation;
|
||||
DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation;
|
||||
switch (type)
|
||||
{
|
||||
case ModManager.MO2:
|
||||
return new MO2InstallerVM(this);
|
||||
case ModManager.Vortex:
|
||||
return new VortexInstallerVM(this);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
})
|
||||
// Unload old VM
|
||||
.Pairwise()
|
||||
.Do(pair =>
|
||||
{
|
||||
pair.Previous?.Unload();
|
||||
})
|
||||
.Select(p => p.Current)
|
||||
.ToProperty(this, nameof(Installer));
|
||||
|
||||
// Load settings
|
||||
MWVM.Settings.SaveSignal
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
MWVM.Settings.Installer.LastInstalledListLocation = ModListLocation.TargetPath;
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
MWVM.Settings.SaveSignal
|
||||
.Subscribe(_ => SaveSettings(CurrentSettings))
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
_modList = this.WhenAny(x => x.ModListPath.TargetPath)
|
||||
_modList = this.WhenAny(x => x.ModListLocation.TargetPath)
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.Select(modListPath =>
|
||||
{
|
||||
if (modListPath == null) return default(ModListVM);
|
||||
if (!File.Exists(modListPath)) return default(ModListVM);
|
||||
var modList = AInstaller.LoadFromFile(modListPath);
|
||||
if (modList == null) return default(ModListVM);
|
||||
return new ModListVM(modList, modListPath);
|
||||
return new ModListVM(modListPath);
|
||||
})
|
||||
.ObserveOnGuiThread()
|
||||
.StartWith(default(ModListVM))
|
||||
@ -161,17 +152,29 @@ namespace Wabbajack
|
||||
_htmlReport = this.WhenAny(x => x.ModList)
|
||||
.Select(modList => modList?.ReportHTML)
|
||||
.ToProperty(this, nameof(HTMLReport));
|
||||
_installing = this.WhenAny(x => x.ActiveInstallation)
|
||||
_installing = this.WhenAny(x => x.Installer.ActiveInstallation)
|
||||
.Select(compilation => compilation != null)
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(Installing));
|
||||
_TargetManager = this.WhenAny(x => x.ModList)
|
||||
.Select(modList => modList?.ModManager)
|
||||
.ToProperty(this, nameof(TargetManager));
|
||||
|
||||
// Add additional error check on modlist
|
||||
ModListLocation.AdditionalError = this.WhenAny(x => x.ModList)
|
||||
.Select<ModListVM, IErrorResponse>(modList =>
|
||||
{
|
||||
if (modList == null) return ErrorResponse.Fail("Modlist path resulted in a null object.");
|
||||
if (modList.Error != null) return ErrorResponse.Fail("Modlist is corrupt", modList.Error);
|
||||
return ErrorResponse.Success;
|
||||
});
|
||||
|
||||
BackCommand = ReactiveCommand.Create(
|
||||
execute: () => mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM,
|
||||
canExecute: this.WhenAny(x => x.Installing)
|
||||
.Select(x => !x));
|
||||
|
||||
_percentCompleted = this.WhenAny(x => x.ActiveInstallation)
|
||||
_percentCompleted = this.WhenAny(x => x.Installer.ActiveInstallation)
|
||||
.StartWith(default(AInstaller))
|
||||
.Pairwise()
|
||||
.Select(c =>
|
||||
@ -191,6 +194,7 @@ namespace Wabbajack
|
||||
// Set display items to modlist if configuring or complete,
|
||||
// or to the current slideshow data if installing
|
||||
_image = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList.Error),
|
||||
this.WhenAny(x => x.ModList)
|
||||
.SelectMany(x => x?.ImageObservable ?? Observable.Empty<BitmapImage>())
|
||||
.NotNull()
|
||||
@ -198,7 +202,14 @@ namespace Wabbajack
|
||||
this.WhenAny(x => x.Slideshow.Image)
|
||||
.StartWith(default(BitmapImage)),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, slideshow, installing) => installing ? slideshow : modList)
|
||||
resultSelector: (err, modList, slideshow, installing) =>
|
||||
{
|
||||
if (err != null)
|
||||
{
|
||||
return WabbajackErrLogo;
|
||||
}
|
||||
return installing ? slideshow : modList;
|
||||
})
|
||||
.Select<BitmapImage, ImageSource>(x => x)
|
||||
.ToProperty(this, nameof(Image));
|
||||
_titleText = Observable.CombineLatest(
|
||||
@ -222,8 +233,16 @@ namespace Wabbajack
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
.ToProperty(this, nameof(Description));
|
||||
_modListName = this.WhenAny(x => x.ModList)
|
||||
.Select(x => x?.Name)
|
||||
_modListName = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList.Error)
|
||||
.Select(x => x != null),
|
||||
this.WhenAny(x => x.ModList)
|
||||
.Select(x => x?.Name),
|
||||
resultSelector: (err, name) =>
|
||||
{
|
||||
if (err) return "Corrupted Modlist";
|
||||
return name;
|
||||
})
|
||||
.ToProperty(this, nameof(ModListName));
|
||||
|
||||
// Define commands
|
||||
@ -233,36 +252,12 @@ namespace Wabbajack
|
||||
canExecute: this.WhenAny(x => x.ModList)
|
||||
.Select(modList => !string.IsNullOrEmpty(modList?.Readme))
|
||||
.ObserveOnGuiThread());
|
||||
BeginCommand = ReactiveCommand.CreateFromTask(
|
||||
execute: ExecuteBegin,
|
||||
canExecute: Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Installing),
|
||||
this.WhenAny(x => x.Location.InError),
|
||||
this.WhenAny(x => x.DownloadLocation.InError),
|
||||
resultSelector: (installing, loc, download) =>
|
||||
{
|
||||
if (installing) return false;
|
||||
return !loc && !download;
|
||||
})
|
||||
.ObserveOnGuiThread());
|
||||
VisitWebsiteCommand = ReactiveCommand.Create(
|
||||
execute: () => Process.Start(ModList.Website),
|
||||
canExecute: this.WhenAny(x => x.ModList.Website)
|
||||
.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),
|
||||
@ -274,7 +269,7 @@ namespace Wabbajack
|
||||
.ToProperty(this, nameof(ProgressTitle));
|
||||
|
||||
// Compile progress updates and populate ObservableCollection
|
||||
this.WhenAny(x => x.ActiveInstallation)
|
||||
this.WhenAny(x => x.Installer.ActiveInstallation)
|
||||
.SelectMany(c => c?.QueueStatus ?? Observable.Empty<CPUStatus>())
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.ToObservableChangeSet(x => x.ID)
|
||||
@ -286,6 +281,16 @@ namespace Wabbajack
|
||||
.Bind(StatusList)
|
||||
.Subscribe()
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// When sub installer begins an install, mark state variable
|
||||
this.WhenAny(x => x.Installer.BeginCommand)
|
||||
.Select(x => x?.StartingExecution() ?? Observable.Empty<Unit>())
|
||||
.Switch()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
InstallingMode = true;
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
}
|
||||
|
||||
private void ShowReport()
|
||||
@ -298,7 +303,7 @@ namespace Wabbajack
|
||||
private void OpenReadmeWindow()
|
||||
{
|
||||
if (string.IsNullOrEmpty(ModList.Readme)) return;
|
||||
using (var fs = new FileStream(ModListPath.TargetPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var fs = new FileStream(ModListLocation.TargetPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
@ -320,60 +325,5 @@ namespace Wabbajack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExecuteBegin()
|
||||
{
|
||||
InstallingMode = true;
|
||||
AInstaller installer;
|
||||
|
||||
try
|
||||
{
|
||||
installer = new MO2Installer(ModListPath.TargetPath, ModList.SourceModList, Location.TargetPath)
|
||||
{
|
||||
DownloadFolder = DownloadLocation.TargetPath
|
||||
};
|
||||
}
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void SaveSettings(ModlistInstallationSettings settings)
|
||||
{
|
||||
MWVM.Settings.Installer.LastInstalledListLocation = ModListPath.TargetPath;
|
||||
if (settings == null) return;
|
||||
settings.InstallationLocation = Location.TargetPath;
|
||||
settings.DownloadLocation = DownloadLocation.TargetPath;
|
||||
}
|
||||
}
|
||||
}
|
154
Wabbajack/View Models/Installers/MO2InstallerVM.cs
Normal file
154
Wabbajack/View Models/Installers/MO2InstallerVM.cs
Normal file
@ -0,0 +1,154 @@
|
||||
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;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
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(
|
||||
this.WhenAny(x => x.Location.InError),
|
||||
this.WhenAny(x => x.DownloadLocation.InError),
|
||||
installerVM.WhenAny(x => x.ModListLocation.InError),
|
||||
resultSelector: (loc, modlist, download) =>
|
||||
{
|
||||
return !loc && !download && !modlist;
|
||||
})
|
||||
.ObserveOnGuiThread(),
|
||||
execute: async () =>
|
||||
{
|
||||
AInstaller installer;
|
||||
|
||||
try
|
||||
{
|
||||
installer = new MO2Installer(
|
||||
archive: installerVM.ModListLocation.TargetPath,
|
||||
modList: installerVM.ModList.SourceModList,
|
||||
outputFolder: Location.TargetPath,
|
||||
downloadFolder: DownloadLocation.TargetPath);
|
||||
}
|
||||
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;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 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.ModListLocation.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.ModListLocation.TargetPath;
|
||||
if (settings == null) return;
|
||||
settings.InstallationLocation = Location.TargetPath;
|
||||
settings.DownloadLocation = DownloadLocation.TargetPath;
|
||||
}
|
||||
}
|
||||
}
|
95
Wabbajack/View Models/Installers/VortexInstallerVM.cs
Normal file
95
Wabbajack/View Models/Installers/VortexInstallerVM.cs
Normal file
@ -0,0 +1,95 @@
|
||||
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: Observable.CombineLatest(
|
||||
this.WhenAny(x => x.TargetGame)
|
||||
.Select(game => VortexCompiler.IsActiveVortexGame(game)),
|
||||
installerVM.WhenAny(x => x.ModListLocation.InError),
|
||||
resultSelector: (isVortexGame, modListErr) => isVortexGame && !modListErr),
|
||||
execute: async () =>
|
||||
{
|
||||
AInstaller installer;
|
||||
|
||||
try
|
||||
{
|
||||
var download = VortexCompiler.RetrieveDownloadLocation(TargetGame);
|
||||
var staging = VortexCompiler.RetrieveStagingLocation(TargetGame);
|
||||
installer = new VortexInstaller(
|
||||
archive: installerVM.ModListLocation.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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -54,7 +54,7 @@ namespace Wabbajack
|
||||
|
||||
if (IsStartingFromModlist(out var path))
|
||||
{
|
||||
Installer.Value.ModListPath.TargetPath = path;
|
||||
Installer.Value.ModListLocation.TargetPath = path;
|
||||
ActivePane = Installer.Value;
|
||||
}
|
||||
else
|
||||
@ -83,7 +83,7 @@ namespace Wabbajack
|
||||
var installer = Installer.Value;
|
||||
Settings.Installer.LastInstalledListLocation = path;
|
||||
ActivePane = installer;
|
||||
installer.ModListPath.TargetPath = path;
|
||||
installer.ModListLocation.TargetPath = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,24 +13,32 @@ namespace Wabbajack
|
||||
public class ModListVM : ViewModel
|
||||
{
|
||||
public ModList SourceModList { get; }
|
||||
public Exception Error { get; }
|
||||
public string ModListPath { get; }
|
||||
public string Name => SourceModList.Name;
|
||||
public string ReportHTML => SourceModList.ReportHTML;
|
||||
public string Readme => SourceModList.Readme;
|
||||
public string Author => SourceModList.Author;
|
||||
public string Description => SourceModList.Description;
|
||||
public string Website => SourceModList.Website;
|
||||
public ModManager ModManager => SourceModList.ModManager;
|
||||
public string Name => SourceModList?.Name;
|
||||
public string ReportHTML => SourceModList?.ReportHTML;
|
||||
public string Readme => SourceModList?.Readme;
|
||||
public string Author => SourceModList?.Author;
|
||||
public string Description => SourceModList?.Description;
|
||||
public string Website => SourceModList?.Website;
|
||||
public ModManager ModManager => SourceModList?.ModManager ?? ModManager.MO2;
|
||||
|
||||
// Image isn't exposed as a direct property, but as an observable.
|
||||
// This acts as a caching mechanism, as interested parties will trigger it to be created,
|
||||
// and the cached image will automatically be released when the last interested party is gone.
|
||||
public IObservable<BitmapImage> ImageObservable { get; }
|
||||
|
||||
public ModListVM(ModList sourceModList, string modListPath)
|
||||
public ModListVM(string modListPath)
|
||||
{
|
||||
ModListPath = modListPath;
|
||||
SourceModList = sourceModList;
|
||||
try
|
||||
{
|
||||
SourceModList = AInstaller.LoadFromFile(modListPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = ex;
|
||||
}
|
||||
|
||||
ImageObservable = Observable.Return(Unit.Default)
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
|
@ -1,4 +1,4 @@
|
||||
using DynamicData;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
@ -74,7 +74,7 @@ namespace Wabbajack
|
||||
// Whenever modlist changes, grab the list of its slides
|
||||
.Select(modList =>
|
||||
{
|
||||
if (modList == null)
|
||||
if (modList?.SourceModList?.Archives == null)
|
||||
{
|
||||
return Observable.Empty<ModVM>()
|
||||
.ToObservableChangeSet(x => x.ModID);
|
||||
|
@ -65,7 +65,7 @@
|
||||
x:Name="LargeProgressBar"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="4"
|
||||
Background="Transparent"
|
||||
Background="#88121212"
|
||||
BorderThickness="0"
|
||||
Maximum="1"
|
||||
Opacity="{Binding ProgressOpacityPercent, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
|
@ -38,8 +38,8 @@
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<local:HeatedBackgroundView
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
PercentCompleted="{Binding PercentCompleted}" />
|
||||
<Grid
|
||||
x:Name="Slideshow"
|
||||
@ -276,24 +276,27 @@
|
||||
x:Name="InstallationConfigurationView"
|
||||
Grid.Column="2"
|
||||
Background="{StaticResource WindowBackgroundBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer
|
||||
Grid.Column="0"
|
||||
Margin="5"
|
||||
Background="Transparent"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
|
||||
<Grid Margin="8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" MinWidth="120" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="80" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
@ -309,47 +312,31 @@
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding ModListPath}"
|
||||
DataContext="{Binding ModListLocation}"
|
||||
FontSize="14" />
|
||||
<TextBlock
|
||||
<ContentPresenter
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Installation Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding Location}"
|
||||
FontSize="14" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Download Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding DownloadLocation}"
|
||||
FontSize="14" />
|
||||
<local:BeginButton
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="4"
|
||||
Margin="0,0,25,0"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding BeginCommand, Mode=OneWay}" />
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="0"
|
||||
Content="{Binding Installer}">
|
||||
<ContentPresenter.Resources>
|
||||
<DataTemplate DataType="{x:Type local:MO2InstallerVM}">
|
||||
<local:MO2InstallerConfigView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type local:VortexInstallerVM}">
|
||||
<local:VortexInstallerConfigView />
|
||||
</DataTemplate>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
<local:BeginButton
|
||||
Grid.Column="2"
|
||||
Margin="0,0,25,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding Installer.BeginCommand, Mode=OneWay}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
52
Wabbajack/Views/Installers/MO2InstallerConfigView.xaml
Normal file
52
Wabbajack/Views/Installers/MO2InstallerConfigView.xaml
Normal file
@ -0,0 +1,52 @@
|
||||
<UserControl
|
||||
x:Class="Wabbajack.MO2InstallerConfigView"
|
||||
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>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="120" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Installation Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding Location}"
|
||||
FontSize="14" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Download Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding DownloadLocation}"
|
||||
FontSize="14" />
|
||||
</Grid>
|
||||
</UserControl>
|
28
Wabbajack/Views/Installers/MO2InstallerConfigView.xaml.cs
Normal file
28
Wabbajack/Views/Installers/MO2InstallerConfigView.xaml.cs
Normal 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 MO2InstallerConfigView.xaml
|
||||
/// </summary>
|
||||
public partial class MO2InstallerConfigView : UserControl
|
||||
{
|
||||
public MO2InstallerConfigView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
14
Wabbajack/Views/Installers/VortexInstallerConfigView.xaml
Normal file
14
Wabbajack/Views/Installers/VortexInstallerConfigView.xaml
Normal 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>
|
28
Wabbajack/Views/Installers/VortexInstallerConfigView.xaml.cs
Normal file
28
Wabbajack/Views/Installers/VortexInstallerConfigView.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -15,23 +15,82 @@ namespace Wabbajack
|
||||
private MainWindowVM _mwvm;
|
||||
private MainSettings _settings;
|
||||
|
||||
internal bool ExitWhenClosing = true;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
_settings = MainSettings.LoadSettings();
|
||||
Left = _settings.PosX;
|
||||
Top = _settings.PosY;
|
||||
_mwvm = new MainWindowVM(this, _settings);
|
||||
DataContext = _mwvm;
|
||||
// Wire any unhandled crashing exceptions to log before exiting
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
|
||||
{
|
||||
// Don't do any special logging side effects
|
||||
Wabbajack.Common.Utils.Log("Uncaught error:");
|
||||
Wabbajack.Common.Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
|
||||
};
|
||||
|
||||
var appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
if (!ExtensionManager.IsAssociated() || ExtensionManager.NeedsUpdating(appPath))
|
||||
{
|
||||
ExtensionManager.Associate(appPath);
|
||||
}
|
||||
|
||||
Wabbajack.Common.Utils.Log($"Wabbajack Build - {ThisAssembly.Git.Sha}");
|
||||
|
||||
this.Loaded += (sender, e) =>
|
||||
// Load settings
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
if ((args.Length > 1 && args[1] == "nosettings")
|
||||
|| !MainSettings.TryLoadTypicalSettings(out var settings))
|
||||
{
|
||||
Width = _settings.Width;
|
||||
Height = _settings.Height;
|
||||
};
|
||||
_settings = new MainSettings();
|
||||
RunWhenLoaded(DefaultSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
_settings = settings;
|
||||
RunWhenLoaded(LoadSettings);
|
||||
}
|
||||
|
||||
// Set datacontext
|
||||
_mwvm = new MainWindowVM(this, _settings);
|
||||
DataContext = _mwvm;
|
||||
}
|
||||
|
||||
internal bool ExitWhenClosing = true;
|
||||
public void Init(MainWindowVM vm, MainSettings settings)
|
||||
{
|
||||
DataContext = vm;
|
||||
_mwvm = vm;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
private void RunWhenLoaded(Action a)
|
||||
{
|
||||
if (IsLoaded)
|
||||
{
|
||||
a();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Loaded += (sender, e) =>
|
||||
{
|
||||
a();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
Width = _settings.Width;
|
||||
Height = _settings.Height;
|
||||
Left = _settings.PosX;
|
||||
Top = _settings.PosY;
|
||||
}
|
||||
|
||||
private void DefaultSettings()
|
||||
{
|
||||
Width = 1300;
|
||||
Height = 960;
|
||||
Left = 15;
|
||||
Top = 15;
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
|
@ -169,6 +169,12 @@
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Converters\EqualsToBoolConverter.cs" />
|
||||
<Compile Include="Views\Installers\MO2InstallerConfigView.xaml.cs">
|
||||
<DependentUpon>MO2InstallerConfigView.xaml</DependentUpon>
|
||||
</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">
|
||||
@ -220,7 +226,7 @@
|
||||
<Compile Include="Views\Common\FilePicker.xaml.cs">
|
||||
<DependentUpon>FilePicker.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\InstallationView.xaml.cs">
|
||||
<Compile Include="Views\Installers\InstallationView.xaml.cs">
|
||||
<DependentUpon>InstallationView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="View Models\Compilers\CompilerVM.cs" />
|
||||
@ -241,6 +247,13 @@
|
||||
<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>
|
||||
</Page>
|
||||
<Page Include="Views\Common\HeatedBackgroundView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@ -285,7 +298,7 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Views\InstallationView.xaml">
|
||||
<Page Include="Views\Installers\InstallationView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@ -301,7 +314,7 @@
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="View Models\InstallerVM.cs" />
|
||||
<Compile Include="View Models\Installers\InstallerVM.cs" />
|
||||
<Compile Include="Util\AutoScrollBehavior.cs" />
|
||||
<Compile Include="Views\MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
@ -323,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">
|
||||
@ -493,5 +510,8 @@
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Wabba_Mouth_No_Text.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Wabba_Ded.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user