Remove vortex support

This commit is contained in:
Timothy Baldridge 2020-04-21 06:14:52 -06:00
parent ad27e071c4
commit 0e0b0d8883
24 changed files with 0 additions and 1471 deletions

View File

@ -22,21 +22,6 @@ Wabbajack is an automated ModList installer that can recreate contents of a fold
| Skyrim Special Edition | Steam | MO2 | |
| Fallout 4 | Steam | MO2 | |
| Skyrim VR | Steam | MO2 | |
| Darkest Dungeon | Steam, GOG| Vortex | |
| Divinity Original Sin 2 | Steam, GOG| Vortex | Normal and Definitive Edition |
| Starbound | Steam, GOG| Vortex | |
| Stardew Valley | Steam, GOG| Vortex | |
| SW: KotOR | Steam, GOG| Vortex | |
| SW: KotOR 2 | Steam, GOG| Vortex | |
| The Witcher | Steam, GOG| Vortex | Enhanced Edition |
| The Witcher 2 | Steam, GOG| Vortex | |
| The Witcher 3 | Steam, GOG| Vortex | Normal and GotY Edition |
### Note about Vortex Support
As you can probably guess from the table above: You will not be able to create ModLists from a Vortex installation for TES/Fallout games. The Vortex Support we're offering is designed for smaller games like Darkest Dungeon where you simply install mods, rearrange load order and be done. You do not need external tools like xEdit, DynDOLOD, CAO, FNIS and what not to mod these smaller games.
It is also important to note that Vortex Support is still in **early beta** meaning that stuff can go wrong, very fast. If you encounter such problems be sure to join our [Discord](https://discord.gg/zgbrkmA) and message `erri120#2285` about the error.
## Installing a ModList
@ -44,8 +29,6 @@ Every ModList comes with its own set of instructions which you **should** read b
A ModList comes as a `.wabbajack` file. You might have a `.zip`, `.7z` or `.rar` file which contains the ModList so extract the archive using [7zip](https://www.7-zip.org/) before starting Wabbajack. Once extracted, start Wabbajack and click on the _Install a ModList from Disk_ button and select the extracted `.wabbajack` file.
Wabbajack will know if this ModList was compiled from an MO2 profile or a Vortex installation. For the former it downloads MO2 for you but for the latter you need an existing Vortex installation.
On the installation screen, configure the installation/staging and downloads folder before clicking the begin button. Once everything is correctly setup, the button will be clickable and you can proceed with the installation.
The installation can take everything from a few minutes to hours depending on the size of the ModList, your Internet speed and your hardware so just be patient and wait for _Installation complete! You may exit the program._ to appear in the log.
@ -100,18 +83,6 @@ When everything is correctly set up, click the begin button and wait for Wabbaja
Wabbajack is finished when you see _Done Building ModList_ in the log. At that point you can close Wabbajack and the `.wabbajack` file will be located in the same folder as `Wabbajack.exe`.
### Creating a ModList from an Vortex installation
**THIS IS STILL IN BETA** for more info see [this](#note-about-vortex-support) section.
Before you start compiling a ModList, make sure that the Vortex download folder for your game of choice only contains mods downloaded from the Nexus. The `VortexCompiler` will create an MD5 hash for the archive and search the Nexus using said hash.
Open Wabbajack and click on _Create a ModList_. Select Vortex and your game of choice. The _Staging_ and _Downloads_ folder will be filled automatically if they are at the default location. If you have changed these folders, be sure to change the paths in Wabbajack.
When everything is correctly set up, click the begin button and wait for Wabbajack to finish. Depeding on your hardware, size of your Vortex staging folder and game of choice, this can take up anything from a few minutes to hours. Do note that whenever Wabbajack has an error you can restart the compilation and Wabbajack will resume at the exact position.
Wabbajack is finished when you see _Done Building ModList_ in the log. At that point you can close Wabbajack and the `.wabbajack` file will be located in the same folder as `Wabbajack.exe`.
## FAQ
**How can I get Wabbajack to handle mods from `X`?**

View File

@ -3,6 +3,5 @@
public enum ModManager
{
MO2,
Vortex
}
}

View File

@ -386,7 +386,6 @@ namespace Wabbajack.Common
{
Game.DarkestDungeon, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.DarkestDungeon,
NexusName = "darkestdungeon",
NexusGameId = 804,
@ -401,7 +400,6 @@ namespace Wabbajack.Common
{
Game.DivinityOriginalSin2DE, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.DivinityOriginalSin2DE,
NexusName = "divinityoriginalsin2definitiveedition",
NexusGameId = 2569,
@ -420,7 +418,6 @@ namespace Wabbajack.Common
{
Game.DivinityOriginalSin2, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.DivinityOriginalSin2,
NexusName = "divinityoriginalsin2",
NexusGameId = 1661,
@ -439,7 +436,6 @@ namespace Wabbajack.Common
{
Game.Starbound, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.Starbound,
NexusName = "starbound",
NexusGameId = 242,
@ -454,7 +450,6 @@ namespace Wabbajack.Common
{
Game.SWKOTOR, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.SWKOTOR,
NexusName = "kotor",
NexusGameId = 234,
@ -469,7 +464,6 @@ namespace Wabbajack.Common
{
Game.SWKOTOR2, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.SWKOTOR2,
NexusName = "kotor2",
NexusGameId = 198,
@ -484,7 +478,6 @@ namespace Wabbajack.Common
{
Game.Witcher, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.Witcher,
NexusName = "witcher",
NexusGameId = 150,
@ -499,7 +492,6 @@ namespace Wabbajack.Common
{
Game.Witcher2, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.Witcher2,
NexusName = "witcher2",
NexusGameId = 153,
@ -515,7 +507,6 @@ namespace Wabbajack.Common
{
Game.Witcher3, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.Witcher3,
NexusName = "witcher3",
NexusGameId = 952,
@ -530,7 +521,6 @@ namespace Wabbajack.Common
{
Game.StardewValley, new GameMetaData
{
SupportedModManager = ModManager.Vortex,
Game = Game.StardewValley,
NexusName = "stardewvalley",
NexusGameId = 1303,

View File

@ -1,41 +0,0 @@
using System.Threading.Tasks;
using Wabbajack.Common;
namespace Wabbajack.Lib.CompilationSteps
{
public class IgnoreDisabledVortexMods : ACompilationStep
{
private readonly VortexCompiler _vortexCompiler;
public IgnoreDisabledVortexMods(ACompiler compiler) : base(compiler)
{
_vortexCompiler = (VortexCompiler) compiler;
}
public override async ValueTask<Directive> Run(RawSourceFile source)
{
var b = false;
_vortexCompiler.ActiveArchives.Do(a =>
{
if (((string)source.Path).Contains(a)) b = true;
});
if (b) return null;
var r = source.EvolveTo<IgnoredDirectly>();
r.Reason = "Disabled Archive";
return r;
}
public override IState GetState()
{
return new State();
}
public class State : IState
{
public ICompilationStep CreateStep(ACompiler compiler)
{
return new IgnoreDisabledVortexMods(compiler);
}
}
}
}

View File

@ -1,39 +0,0 @@
using System.IO;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Wabbajack.Lib.CompilationSteps
{
public class IgnoreVortex : ACompilationStep
{
private readonly VortexCompiler _vortex;
public IgnoreVortex(ACompiler compiler) : base(compiler)
{
_vortex = (VortexCompiler) compiler;
}
public override async ValueTask<Directive> Run(RawSourceFile source)
{
if (source.AbsolutePath.Parent != _vortex.DownloadsFolder) return null;
var result = source.EvolveTo<IgnoredDirectly>();
result.Reason = "Ignored because it is a Vortex file";
return result;
}
public override IState GetState()
{
return new State();
}
[JsonObject("IgnoreVortex")]
public class State : IState
{
public ICompilationStep CreateStep(ACompiler compiler)
{
return new IgnoreVortex(compiler);
}
}
}
}

View File

@ -1,50 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Wabbajack.Common;
namespace Wabbajack.Lib.CompilationSteps
{
public class IncludeVortexDeployment : ACompilationStep
{
public IncludeVortexDeployment(ACompiler compiler) : base(compiler)
{
}
public override async ValueTask<Directive?> Run(RawSourceFile source)
{
// * TODO I don't know what this does
/*
var l = new List<string> {"vortex.deployment.msgpack", "vortex.deployment.json"};
if (!l.Any(a => ((string)source.Path).Contains(a))) return null;
var inline = source.EvolveTo<InlineFile>();
inline.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
if (!((string)source.Path).Contains("vortex.deployment.json"))
return inline;
var path = source.Path;
if (!path.StartsWith(Consts.GameFolderFilesDir))
return inline;
*/
//path = ((string)path).Substring(Consts.GameFolderFilesDir.Length + 1);
//path = $"{Consts.ManualGameFilesDir}\\{path}";
//inline.To = path;
return null;
}
public override IState GetState()
{
return new State();
}
public class State : IState
{
public ICompilationStep CreateStep(ACompiler compiler)
{
return new IncludeVortexDeployment(compiler);
}
}
}
}

View File

@ -1,555 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Newtonsoft.Json;
using Wabbajack.Common;
using Wabbajack.Common.IO;
using Wabbajack.Common.StoreHandlers;
using Wabbajack.Lib.CompilationSteps;
using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.Validation;
using File = Alphaleonis.Win32.Filesystem.File;
using Game = Wabbajack.Common.Game;
namespace Wabbajack.Lib
{
public class VortexCompiler : ACompiler
{
/* vortex creates a vortex.deployment.json file that contains information
about all deployed files, parsing that file, we can get a list of all 'active'
archives so we don't force the user to install all archives found in the downloads folder.
Similar to how IgnoreDisabledMods for MO2 works
*/
public VortexDeployment VortexDeployment;
public List<string> ActiveArchives;
public Game Game { get; }
public string GameName { get; }
public AbsolutePath VortexFolder { get; set; }
public AbsolutePath StagingFolder { get; set; }
public AbsolutePath DownloadsFolder { get; set; }
public override ModManager ModManager => ModManager.Vortex;
public override AbsolutePath GamePath { get; }
public override AbsolutePath ModListOutputFolder => ((RelativePath)"output_folder").RelativeToEntryPoint();
public override AbsolutePath ModListOutputFile { get; }
public const string StagingMarkerName = "__vortex_staging_folder";
public const string DownloadMarkerName = "__vortex_downloads_folder";
//private bool _isSteamGame = true;
private SteamGame _steamGame;
private bool _hasSteamWorkshopItems;
public override AbsolutePath VFSCacheName => Consts.LocalAppDataPath.Combine($"vfs_compile_cache-{((string)StagingFolder)?.StringSha256Hex() ?? "Unknown"}.bin");
public VortexCompiler(Game game, AbsolutePath gamePath, AbsolutePath vortexFolder, AbsolutePath downloadsFolder, AbsolutePath stagingFolder, AbsolutePath outputFile)
{
Game = game;
GamePath = gamePath;
GameName = game.MetaData().NexusName;
VortexFolder = vortexFolder;
DownloadsFolder = downloadsFolder;
StagingFolder = stagingFolder;
ModListOutputFile = outputFile;
if (string.IsNullOrEmpty(ModListName))
{
ModListName = $"Vortex ModList for {Game.ToString()}";
ModListOutputFile = ((RelativePath)ModListName).RelativeToEntryPoint().WithExtension(Consts.ModListExtension);
}
GameName = Game.MetaData().NexusName;
ActiveArchives = new List<string>();
// there can be max one game after filtering
/*
StoreHandler.Instance.StoreGames.Where(g => g.Game == game && g.Type == StoreType.STEAM).Do(g =>
{
_isSteamGame = true;
_steamGame = (SteamGame)g;
_hasSteamWorkshopItems = _steamGame.WorkshopItems.Count > 0;
});
*/
}
protected override async Task<bool> _Begin(CancellationToken cancel)
{
if (cancel.IsCancellationRequested) return false;
Info($"Starting Vortex compilation for {GameName} at {GamePath} with staging folder at {StagingFolder} and downloads folder at {DownloadsFolder}.");
ConfigureProcessor(12, ConstructDynamicNumThreads(await RecommendQueueSize()));
UpdateTracker.Reset();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Parsing deployment file");
ParseDeploymentFile();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Creating metas for archives");
await CreateMetaFiles();
Utils.Log($"VFS File Location: {VFSCacheName}");
if (cancel.IsCancellationRequested) return false;
await VFS.IntegrateFromFile(VFSCacheName);
var roots = new List<AbsolutePath> {StagingFolder, GamePath, DownloadsFolder};
AddExternalFolder(ref roots);
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Indexing folders");
await VFS.AddRoots(roots);
await VFS.WriteToFile(VFSCacheName);
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Cleaning output folder");
await ModListOutputFolder.DeleteDirectory();
ModListOutputFolder.CreateDirectory();
UpdateTracker.NextStep("Finding Install Files");
/* TODO
var vortexStagingFiles = Directory.EnumerateFiles(StagingFolder, "*", SearchOption.AllDirectories)
.Where(p => p.FileExists() && p != StagingMarkerName && !p.Contains(Consts.ManualGameFilesDir))
.Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(StagingFolder)));
var vortexDownloads = Directory.EnumerateFiles(DownloadsFolder, "*", SearchOption.AllDirectories)
.Where(p => p.FileExists() && p != DownloadMarkerName)
.Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(DownloadsFolder)));
var gameFiles = Directory.EnumerateFiles(GamePath, "*", SearchOption.AllDirectories)
.Where(p => p.FileExists())
.Select(p => new RawSourceFile(VFS.Index.ByRootPath[p], Path.Combine(Consts.GameFolderFilesDir, p.RelativeTo(GamePath))));
Info("Indexing Archives");
IndexedArchives = Directory.EnumerateFiles(DownloadsFolder)
.Where(f => File.Exists(f + Consts.MetaFileExtension))
.Select(f => new IndexedArchive
{
File = VFS.Index.ByRootPath[f],
Name = Path.GetFileName(f),
IniData = (f + Consts.MetaFileExtension).LoadIniFile(),
Meta = File.ReadAllText(f + Consts.MetaFileExtension)
})
.ToList();
Info("Indexing Files");
IndexedFiles = IndexedArchives.SelectMany(f => f.File.ThisAndAllChildren)
.OrderBy(f => f.NestingFactor)
.GroupBy(f => f.Hash)
.ToDictionary(f => f.Key, f => f.AsEnumerable());
AllFiles = vortexStagingFiles.Concat(vortexDownloads)
.Concat(gameFiles)
.DistinctBy(f => f.Path)
.ToList();
Info($"Found {AllFiles.Count} files to build into mod list");
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Verifying destinations");
var duplicates = AllFiles.GroupBy(f => f.Path)
.Where(fs => fs.Count() > 1)
.Select(fs =>
{
Utils.Log($"Duplicate files installed to {fs.Key} from : {string.Join(", ", fs.Select(f => f.AbsolutePath))}");
return fs;
}).ToList();
if (duplicates.Count > 0)
{
Error($"Found {duplicates.Count} duplicates, exiting");
}
for (var i = 0; i < AllFiles.Count; i++)
{
var f = AllFiles[i];
if (!f.Path.StartsWith(Consts.GameFolderFilesDir) || !IndexedFiles.ContainsKey(f.Hash))
continue;
if (!IndexedFiles.TryGetValue(f.Hash, out var value))
continue;
var element = value.ElementAt(0);
if (!f.Path.Contains(element.Name))
continue;
IndexedArchive targetArchive = null;
IndexedArchives.Where(a => a.File.ThisAndAllChildren.Contains(element)).Do(a => targetArchive = a);
if (targetArchive == null)
continue;
if(targetArchive.IniData?.General?.tag == null || targetArchive.IniData?.General?.tag != Consts.WABBAJACK_VORTEX_MANUAL)
continue;
#if DEBUG
Utils.Log($"Double hash for: {f.AbsolutePath}");
#endif
var replace = f;
var name = replace.File.Name;
var archiveName = targetArchive.Name;
var elementPath = element.FullPath.Substring(element.FullPath.LastIndexOf('|')+1);
var gameToFile = name.Substring(GamePath.Length + 1).Replace(elementPath, "");
if (gameToFile.EndsWith("\\"))
gameToFile = gameToFile.Substring(0, gameToFile.Length - 1);
//replace.Path = replace.Path.Replace(Consts.GameFolderFilesDir, Consts.ManualGameFilesDir);
replace.Path = Path.Combine(Consts.ManualGameFilesDir, archiveName, gameToFile, elementPath);
//replace.Path = Path.Combine(Consts.ManualGameFilesDir, element.FullPath.Substring(DownloadsFolder.Length + 1).Replace('|', '\\'));
AllFiles.RemoveAt(i);
AllFiles.Insert(i, replace);
//AllFiles.Replace(f, replace);
}
var stack = MakeStack();
Info("Running Compilation Stack");
var results = await AllFiles.PMap(Queue, f => RunStack(stack.Where(s => s != null), f));
var noMatch = results.OfType<NoMatch>().ToList();
PrintNoMatches(noMatch);
if (CheckForNoMatchExit(noMatch)) return false;
InstallDirectives = results.Where(i => !(i is IgnoredDirectly)).ToList();
Info("Getting Nexus api_key, please click authorize if a browser window appears");
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Gathering Archives");
await GatherArchives();
ModList = new ModList
{
Name = ModListName ?? "",
Author = ModListAuthor ?? "",
Description = ModListDescription ?? "",
Readme = ModListReadme ?? "",
Image = ModListImage ?? "",
Website = ModListWebsite != null ? new Uri(ModListWebsite) : null,
Archives = SelectedArchives.ToList(),
ModManager = ModManager.Vortex,
Directives = InstallDirectives,
GameType = Game
};
UpdateTracker.NextStep("Running Validation");
await ValidateModlist.RunValidation(ModList);
UpdateTracker.NextStep("Generating Report");
GenerateManifest();
UpdateTracker.NextStep("Exporting ModList");
ExportModList();
ResetMembers();
UpdateTracker.NextStep("Done Building ModList");
*/
return true;
}
/// <summary>
/// Clear references to lists that hold a lot of data.
/// </summary>
private void ResetMembers()
{
AllFiles = null;
InstallDirectives = null;
SelectedArchives = null;
}
private void AddExternalFolder(ref List<AbsolutePath> roots)
{
var currentGame = Game.MetaData();
if (currentGame.AdditionalFolders == null || currentGame.AdditionalFolders.Count == 0) return;
foreach (var path in currentGame.AdditionalFolders.Select(f => f.Replace("%documents%", KnownFolders.Documents.Path)))
{
if (!Directory.Exists(path)) return;
roots.Add((AbsolutePath)path);
}
}
private void ParseDeploymentFile()
{
/* TODO
Info("Searching for vortex.deployment.json...");
var deploymentFile = "";
Directory.EnumerateFiles(GamePath, "vortex.deployment.json", SearchOption.AllDirectories)
.Where(File.Exists)
.Do(f => deploymentFile = f);
var currentGame = Game.MetaData();
if (currentGame.AdditionalFolders != null && currentGame.AdditionalFolders.Count != 0)
currentGame.AdditionalFolders.Do(f => Directory.EnumerateFiles(f, "vortex.deployment.json", SearchOption.AllDirectories)
.Where(File.Exists)
.Do(d => deploymentFile = d));
if (string.IsNullOrEmpty(deploymentFile))
{
Error("vortex.deployment.json not found!");
return;
}
Info($"vortex.deployment.json found at {deploymentFile}");
Info("Parsing vortex.deployment.json...");
try
{
VortexDeployment = deploymentFile.FromJSON<VortexDeployment>();
}
catch (JsonSerializationException e)
{
Utils.Error(e, "Failed to parse vortex.deployment.json!");
}
VortexDeployment.files.Do(f =>
{
var archive = f.source;
if (ActiveArchives.Contains(archive))
return;
Utils.Log($"Adding archive {archive} to ActiveArchives");
ActiveArchives.Add(archive);
});
*/
}
private async Task CreateMetaFiles()
{
/*
Utils.Log("Getting Nexus API key, please click authorize if a browser window appears");
var nexusClient = await NexusApiClient.Get();
var archives = Directory.EnumerateFiles(DownloadsFolder, "*", SearchOption.TopDirectoryOnly).Where(f =>
File.Exists(f) && Path.GetExtension(f) != Consts.MetaFileExtension && Path.GetExtension(f) != Consts.HashFileExtension &&
!File.Exists($"{f}.meta") && ActiveArchives.Contains(Path.GetFileNameWithoutExtension(f)));
await archives.PMap(Queue, async f =>
{
Info($"Creating meta file for {Path.GetFileName(f)}");
var metaString = "[General]\n" +
"repository=Nexus\n" +
$"gameName={GameName}\n";
string hash;
using (var md5 = MD5.Create())
using (var stream = File.OpenRead(f))
{
Utils.Log($"Calculating hash for {Path.GetFileName(f)}");
var cH = md5.ComputeHash(stream);
hash = BitConverter.ToString(cH).Replace("-", "").ToLowerInvariant();
Utils.Log($"Hash is {hash}");
}
var md5Response = await nexusClient.GetModInfoFromMD5(Game, hash);
if (md5Response.Count >= 1)
{
var modInfo = md5Response[0].mod;
metaString += $"modID={modInfo.mod_id}\n" +
$"modName={modInfo.name}\n" +
$"fileID={md5Response[0].file_details.file_id}\n" +
$"version={md5Response[0].file_details.version}\n" +
$"hash={hash}\n";
File.WriteAllText(f + Consts.MetaFileExtension, metaString, Encoding.UTF8);
}
else
{
Error("Error while getting information from NexusMods via MD5 hash!");
}
});
var otherFiles = Directory.EnumerateFiles(DownloadsFolder, "*", SearchOption.TopDirectoryOnly).Where(f =>
Path.GetExtension(f) == Consts.MetaFileExtension && !ActiveArchives.Contains(Path.GetFileNameWithoutExtension(f)));
await otherFiles.PMap(Queue, async f =>
{
Info($"File {f} is not in ActiveArchives");
var lines = File.ReadAllLines(f);
if (lines.Length == 0 || !lines.Any(line => lines.Contains("directURL=")))
{
if (lines.Length == 0)
return;
lines.Do(line =>
{
var tag = "";
if (line.Contains("tag="))
tag = line.Substring("tag=".Length);
if (tag != Consts.WABBAJACK_VORTEX_MANUAL)
return;
Info($"File {f} contains the {Consts.WABBAJACK_VORTEX_MANUAL} tag, adding to ActiveArchives");
ActiveArchives.Add(Path.GetFileNameWithoutExtension(f));
});
}
else
{
Info($"File {f} appears to not be from the Nexus, adding to ActiveArchives");
ActiveArchives.Add(Path.GetFileNameWithoutExtension(f));
}
});
Info("Checking for Steam Workshop Items...");
if (!_isSteamGame || _steamGame == null || !_hasSteamWorkshopItems)
return;
_steamGame.WorkshopItems.Do(item =>
{
var filePath = Path.Combine(DownloadsFolder, $"steamWorkshopItem_{item.ItemID}.meta");
if (File.Exists(filePath))
{
Utils.Log($"File {filePath} already exists, skipping");
return;
}
Utils.Log($"Creating meta file for {item.ItemID}");
var metaString = "[General]\n" +
"repository=Steam\n" +
$"gameName={GameName}\n" +
$"steamID={_steamGame.ID}\n" +
$"itemID={item.ItemID}\n" +
$"itemSize={item.Size}\n";
try
{
File.WriteAllText(filePath, metaString);
}
catch (Exception e)
{
Utils.Error(e, $"Exception while writing to disk at {filePath}");
}
});
*/
}
public override IEnumerable<ICompilationStep> GetStack()
{
/*
var s = Consts.TestMode ? DownloadsFolder : VortexFolder;
var userConfig = Path.Combine(s, "compilation_stack.yml");
if (File.Exists(userConfig))
return Serialization.Deserialize(File.ReadAllText(userConfig), this);
var stack = MakeStack();
var compilationSteps = stack.ToList();
File.WriteAllText(Path.Combine(s, "_current_compilation_stack.yml"),
Serialization.Serialize(compilationSteps));
return compilationSteps;
*/
return null;
}
public override IEnumerable<ICompilationStep> MakeStack()
{
Info("Generating compilation stack");
return new List<ICompilationStep>
{
new IncludePropertyFiles(this),
new IncludeVortexDeployment(this),
new IncludeSteamWorkshopItems(this, _steamGame),
_hasSteamWorkshopItems ? new IncludeRegex(this, "^steamWorkshopItem_\\d*\\.meta$") : null,
new IgnoreDisabledVortexMods(this),
new IgnoreVortex(this),
new IgnoreRegex(this, $"^*{StagingMarkerName}$"),
Game == Game.DarkestDungeon ? new IncludeRegex(this, "project\\.xml$") : null,
/*
new IgnoreStartsWith(this, StagingFolder),
new IgnoreEndsWith(this, StagingFolder),
*/
new IgnoreGameFiles(this),
new DirectMatch(this),
// new IncludeTaggedMods(this, Consts.WABBAJACK_INCLUDE), disabled until further refactoring
new IgnoreGameFiles(this),
new IgnoreWabbajackInstallCruft(this),
new DropAll(this)
};
}
public static string TypicalVortexFolder()
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Vortex");
}
public static string RetrieveDownloadLocation(Game game, string vortexFolderPath = null)
{
vortexFolderPath = vortexFolderPath ?? TypicalVortexFolder();
return Path.Combine(vortexFolderPath, "downloads", game.MetaData().NexusName);
}
public static string RetrieveStagingLocation(Game game, string vortexFolderPath = null)
{
/*
vortexFolderPath = vortexFolderPath ?? TypicalVortexFolder();
var gameName = game.MetaData().NexusName;
return Path.Combine(vortexFolderPath, gameName, Consts.MO2ModFolderName);
*/
return null;
}
public static IErrorResponse IsValidBaseDownloadsFolder(string path)
{
if (!Directory.Exists(path)) return ErrorResponse.Fail($"Path does not exist: {path}");
if (Directory.EnumerateFiles(path, DownloadMarkerName, SearchOption.TopDirectoryOnly).Any()) return ErrorResponse.Success;
return ErrorResponse.Fail($"Folder must contain {DownloadMarkerName} file");
}
public static IErrorResponse IsValidDownloadsFolder(string path)
{
return IsValidBaseDownloadsFolder(Path.GetDirectoryName(path));
}
public static IErrorResponse IsValidBaseStagingFolder(string path)
{
if (!Directory.Exists(path)) return ErrorResponse.Fail($"Path does not exist: {path}");
if (Directory.EnumerateFiles(path, StagingMarkerName, SearchOption.TopDirectoryOnly).Any()) return ErrorResponse.Success;
return ErrorResponse.Fail($"Folder must contain {StagingMarkerName} file");
}
public static IErrorResponse IsValidStagingFolder(string path)
{
return IsValidBaseStagingFolder(Path.GetDirectoryName(path));
}
public static bool IsActiveVortexGame(Game g)
{
return g.MetaData().SupportedModManager == ModManager.Vortex && !GameRegistry.Games[g].Disabled;
}
}
public class VortexDeployment
{
public string instance;
public int version;
public string deploymentMethod;
public List<VortexFile> files;
}
public class VortexFile
{
public string relPath;
public string source;
public string target;
}
}

View File

@ -1,228 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using System.Windows;
using Wabbajack.Common;
using Wabbajack.Common.StoreHandlers;
using Directory = Alphaleonis.Win32.Filesystem.Directory;
using DirectoryInfo = Alphaleonis.Win32.Filesystem.DirectoryInfo;
using File = Alphaleonis.Win32.Filesystem.File;
using Path = Alphaleonis.Win32.Filesystem.Path;
#nullable disable
namespace Wabbajack.Lib
{
public class VortexInstaller : AInstaller
{
public GameMetaData GameInfo { get; internal set; }
public override ModManager ModManager => ModManager.Vortex;
public VortexInstaller(AbsolutePath archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters)
: base(
archive: archive,
modList: modList,
outputFolder: outputFolder,
downloadFolder: downloadFolder,
parameters: parameters,
steps: 10)
{
#if DEBUG
// TODO: only for testing
IgnoreMissingFiles = true;
#endif
GameInfo = ModList.GameType.MetaData();
}
protected override async Task<bool> _Begin(CancellationToken cancel)
{
if (cancel.IsCancellationRequested) return false;
var metric = Metrics.Send(Metrics.BeginInstall, ModList.Name);
var result = await Utils.Log(new YesNoIntervention(
"Vortex Support is still experimental and may produce unexpected results. " +
"If anything fails please go to the special Vortex support channels on the Wabbajack Discord and contact @erri120#2285 " +
"for support.", "Continue with experimental feature?")).Task;
if (result == ConfirmationIntervention.Choice.Abort)
{
Utils.Log("Exiting at request of user");
return false;
}
if (cancel.IsCancellationRequested) return false;
Queue.SetActiveThreadsObservable(ConstructDynamicNumThreads(await RecommendQueueSize()));
DownloadFolder.CreateDirectory();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Hashing Archives");
await HashArchives();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Downloading Missing Archives");
await DownloadArchives();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Hashing Remaining Archives");
await HashArchives();
if (cancel.IsCancellationRequested) return false;
var missing = ModList.Archives.Where(a => !HashedArchives.ContainsKey(a.Hash)).ToList();
if (missing.Count > 0)
{
foreach (var a in missing)
Info($"Unable to download {a.Name}");
if (IgnoreMissingFiles)
Info("Missing some archives, but continuing anyways at the request of the user");
else
Error("Cannot continue, was unable to download one or more archives");
}
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Priming VFS");
await PrimeVFS();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Building Folder Structure");
BuildFolderStructure();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Installing Archives");
await InstallArchives();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Installing Included files");
await InstallIncludedFiles();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Installing Manual files");
await InstallManualGameFiles();
if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Installing SteamWorkshopItems");
await InstallSteamWorkshopItems();
//InstallIncludedDownloadMetas();
var metric2 = Metrics.Send(Metrics.FinishInstall, ModList.Name);
UpdateTracker.NextStep("Installation complete! You may exit the program.");
return true;
}
private async Task InstallManualGameFiles()
{
if (!ModList.Directives.Any(d => d.To.StartsWith(Consts.ManualGameFilesDir)))
return;
var result = await Utils.Log(new YesNoIntervention("Some mods from this ModList must be installed directly into " +
"the game folder. Do you want to do this manually or do you want Wabbajack " +
"to do this for you?", "Move mods into game folder?")).Task;
if (result != ConfirmationIntervention.Choice.Continue)
return;
var manualFilesDir = OutputFolder.Combine(Consts.ManualGameFilesDir);
var gameFolder = GameInfo.TryGetGameLocation();
Info($"Copying files from {manualFilesDir} " +
$"to the game folder at {gameFolder}");
if (!manualFilesDir.Exists)
{
Info($"{manualFilesDir} does not exist!");
return;
}
/* TODO FIX THIS
await manualFilesDir.EnumerateFiles().PMap(Queue, dir =>
{
dirInfo.GetDirectories("*", SearchOption.AllDirectories).Do(d =>
{
var destPath = d.FullName.Replace(manualFilesDir, gameFolder);
Status($"Creating directory {destPath}");
Directory.CreateDirectory(destPath);
});
dirInfo.GetFiles("*", SearchOption.AllDirectories).Do(f =>
{
var destPath = f.FullName.Replace(manualFilesDir, gameFolder);
Status($"Copying file {f.FullName} to {destPath}");
try
{
File.Copy(f.FullName, destPath);
}
catch (Exception)
{
Info($"Could not copy file {f.FullName} to {destPath}. The file may already exist, skipping...");
}
});
});
*/
}
private async Task InstallSteamWorkshopItems()
{
//var currentLib = "";
SteamGame currentSteamGame = null;
StoreHandler.Instance.SteamHandler.Games.Where(g => g.Game == GameInfo.Game).Do(s => currentSteamGame = (SteamGame)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 = await Utils.Log(new YesNoIntervention(
"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?",
"Download Steam Workshop Items?")).Task;
if (result != ConfirmationIntervention.Choice.Continue)
return;
await ModList.Directives.OfType<SteamMeta>()
.PMap(Queue, async item =>
{
Status("Extracting Steam meta file to temp folder");
var path = DownloadFolder.Combine($"steamWorkshopItem_{item.ItemID}.meta");
if (!path.Exists)
await path.WriteAllBytesAsync(await LoadBytesFromPath(item.SourceDataID));
Status("Downloading Steam Workshop Item through steam cmd");
var p = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = Path.Combine(StoreHandler.Instance.SteamHandler.SteamPath, "steam.exe"),
CreateNoWindow = true,
Arguments = $"console +workshop_download_item {currentSteamGame.ID} {currentSteamGame.ID}"
}
};
p.Start();
});
}
private async Task InstallIncludedFiles()
{
Info("Writing inline files");
await ModList.Directives.OfType<InlineFile>()
.PMap(Queue,async directive =>
{
if (directive.To.Extension == Consts.MetaFileExtension)
return;
Info($"Writing included file {directive.To}");
var outPath = OutputFolder.Combine(directive.To);
outPath.Delete();
await outPath.WriteAllBytesAsync(await LoadBytesFromPath(directive.SourceDataID));
});
}
}
}

View File

@ -96,12 +96,6 @@
<None Update="concrt140.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Compile Remove="VortexCompiler.cs" />
<None Include="VortexCompiler.cs" />
<Compile Remove="CompilationSteps\IgnoreDisabledVortexMods.cs" />
<None Include="CompilationSteps\IgnoreDisabledVortexMods.cs" />
<Compile Remove="CompilationSteps\IgnoreVortex.cs" />
<None Include="CompilationSteps\IgnoreVortex.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Downloaders\BethesdaNet" />

View File

@ -1,78 +0,0 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common;
using Wabbajack.Lib;
namespace Wabbajack.Test
{
public abstract class AVortexCompilerTest
{
public TestContext TestContext { get; set; }
protected TestUtils utils { get; set; }
[TestInitialize]
public void TestInitialize()
{
Consts.TestMode = true;
utils = new TestUtils
{
Game = Game.DarkestDungeon
};
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription));
}
[TestCleanup]
public void TestCleanup()
{
utils.Dispose();
}
protected async Task<VortexCompiler> ConfigureAndRunCompiler()
{
var vortexCompiler = MakeCompiler();
vortexCompiler.DownloadsFolder = utils.DownloadsFolder;
vortexCompiler.StagingFolder = utils.InstallFolder;
Directory.CreateDirectory(utils.InstallFolder);
Assert.IsTrue(await vortexCompiler.Begin());
return vortexCompiler;
}
protected VortexCompiler MakeCompiler()
{
return new VortexCompiler(
game: utils.Game,
gamePath: utils.GameFolder,
vortexFolder: VortexCompiler.TypicalVortexFolder(),
downloadsFolder: VortexCompiler.RetrieveDownloadLocation(utils.Game),
stagingFolder: VortexCompiler.RetrieveStagingLocation(utils.Game),
outputFile: $"test{Consts.ModListExtension}");
}
protected async Task<ModList> CompileAndInstall()
{
var vortexCompiler = await ConfigureAndRunCompiler();
await Install(vortexCompiler);
return vortexCompiler.ModList;
}
protected async Task Install(VortexCompiler vortexCompiler)
{
var modList = AInstaller.LoadFromFile(vortexCompiler.ModListOutputFile);
var installer = new MO2Installer(
archive: vortexCompiler.ModListOutputFile,
modList: modList,
outputFolder: utils.InstallFolder,
downloadFolder: utils.DownloadsFolder,
parameters: SystemParametersConstructor.Create())
{
GameFolder = utils.GameFolder,
};
await installer.Begin();
}
}
}

View File

@ -1,29 +0,0 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Wabbajack.Test
{
[TestClass]
public class VortexTests : AVortexCompilerTest
{
// TODO: figure out what games we want installed on the test server for this
/*
[TestMethod]
public void TestVortexStackSerialization()
{
utils.AddMod("test");
utils.Configure();
var vortexCompiler = ConfigureAndRunCompiler();
vortexCompiler.StagingFolder = "vortex_staging";
var stack = vortexCompiler.MakeStack();
var serialized = Serialization.Serialize(stack);
var rounded = Serialization.Serialize(Serialization.Deserialize(serialized, vortexCompiler));
Assert.AreEqual(serialized, rounded);
Assert.IsNotNull(vortexCompiler.GetStack());
}
*/
}
}

View File

@ -13,9 +13,7 @@
<ItemGroup>
<None Remove="Readme.md" />
<Compile Remove="AVortexCompilerTest.cs" />
<None Include="AVortexCompilerTest.cs" />
<Compile Remove="VortexTests.cs" />
<None Include="VortexTests.cs" />
<Compile Remove="WebAutomationTests.cs" />
<Compile Remove="ZEditIntegrationTests.cs" />
<None Include="ZEditIntegrationTests.cs" />

View File

@ -14,8 +14,6 @@ namespace Wabbajack
UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/Wabba_Ded.png")).Stream));
public static Lazy<BitmapImage> MO2Button { get; } = new Lazy<BitmapImage>(() =>
UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/MO2Button.png")).Stream));
public static Lazy<BitmapImage> VortexButton { get; } = new Lazy<BitmapImage>(() =>
UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/VortexButton.png")).Stream));
public static Lazy<BitmapImage> MiddleMouseButton { get; } = new Lazy<BitmapImage>(() =>
UIUtils.BitmapImageFromStream(Application.GetResourceStream(new Uri("pack://application:,,,/Resources/middle_mouse_button.png")).Stream));
}

View File

@ -87,7 +87,6 @@ namespace Wabbajack
public ModManager LastCompiledModManager { get; set; }
public AbsolutePath OutputLocation { get; set; }
public MO2CompilationSettings MO2Compilation { get; } = new MO2CompilationSettings();
public VortexCompilationSettings VortexCompilation { get; } = new VortexCompilationSettings();
}
[JsonObject(MemberSerialization.OptOut)]
@ -134,17 +133,4 @@ namespace Wabbajack
public Dictionary<AbsolutePath, CompilationModlistSettings> ModlistSettings { get; } = new Dictionary<AbsolutePath, CompilationModlistSettings>();
}
public class VortexCompilationSettings
{
public Game LastCompiledGame { get; set; }
public Dictionary<Game, VortexGameSettings> ModlistSettings { get; } = new Dictionary<Game, VortexGameSettings>();
}
public class VortexGameSettings
{
public string GameLocation { get; set; }
public string DownloadLocation { get; set; }
public string StagingLocation { get; set; }
public CompilationModlistSettings ModlistSettings { get; } = new CompilationModlistSettings();
}
}

View File

@ -102,10 +102,6 @@ namespace Wabbajack
{
case ModManager.MO2:
return new MO2CompilerVM(this);
/*
case ModManager.Vortex:
return new VortexCompilerVM(this);
*/
default:
return null;
}

View File

@ -1,219 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.Common.StoreHandlers;
using Wabbajack.Lib;
namespace Wabbajack
{
public class VortexCompilerVM : ViewModel, ISubCompilerVM
{
public CompilerVM Parent { get; }
private readonly VortexCompilationSettings _settings;
private readonly ObservableAsPropertyHelper<ModlistSettingsEditorVM> _modListSettings;
public ModlistSettingsEditorVM ModlistSettings => _modListSettings.Value;
private static readonly ObservableCollectionExtended<GameVM> _gameOptions = new ObservableCollectionExtended<GameVM>(
EnumExt.GetValues<Game>()
.Where(g => VortexCompiler.IsActiveVortexGame(g))
.Select(g => new GameVM(g))
.OrderBy(g => g.DisplayName));
public ObservableCollectionExtended<GameVM> GameOptions => _gameOptions;
[Reactive]
public ACompiler ActiveCompilation { get; private set; }
[Reactive]
public GameVM SelectedGame { get; set; }
[Reactive]
public FilePickerVM GameLocation { get; set; }
[Reactive]
public FilePickerVM DownloadsLocation { get; set; }
[Reactive]
public FilePickerVM StagingLocation { get; set; }
public ICommand FindGameInSteamCommand { get; }
public ICommand FindGameInGogCommand { get; }
[Reactive]
public StatusUpdateTracker StatusTracker { get; private set; }
public IObservable<bool> CanCompile { get; }
public VortexCompilerVM(CompilerVM parent)
{
Parent = parent;
GameLocation = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.CheckOptions.On,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select Game Folder Location"
};
DownloadsLocation = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.CheckOptions.On,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select Downloads Folder"
};
StagingLocation = new FilePickerVM()
{
ExistCheckOption = FilePickerVM.CheckOptions.On,
PathType = FilePickerVM.PathTypeOptions.Folder,
PromptTitle = "Select Staging Folder"
};
// Load custom ModList settings when game type changes
_modListSettings = (this).WhenAny(x => x.SelectedGame)
.Select(game =>
{
if (game == null) return null;
var gameSettings = _settings.ModlistSettings.TryCreate(game.Game);
return new ModlistSettingsEditorVM(gameSettings.ModlistSettings);
})
// Interject and save old while loading new
.Pairwise()
.Do(pair =>
{
var (previous, current) = pair;
previous?.Save();
current?.Init();
})
.Select(x => x.Current)
.ToGuiProperty(this, nameof(ModlistSettings));
CanCompile = Observable.CombineLatest(
this.WhenAny(x => x.GameLocation.InError),
this.WhenAny(x => x.DownloadsLocation.InError),
this.WhenAny(x => x.StagingLocation.InError),
this.WhenAny(x => x.ModlistSettings)
.Select(x => x?.InError ?? Observable.Return(false))
.Switch(),
(g, d, s, ml) => !g && !d && !s && !ml)
.Publish()
.RefCount();
// Load settings
_settings = parent.MWVM.Settings.Compiler.VortexCompilation;
SelectedGame = _gameOptions.FirstOrDefault(x => x.Game == _settings.LastCompiledGame) ?? _gameOptions[0];
parent.MWVM.Settings.SaveSignal
.Subscribe(_ => Unload())
.DisposeWith(CompositeDisposable);
// Load custom game settings when game type changes
(this).WhenAny(x => x.SelectedGame)
.Select(game => _settings.ModlistSettings.TryCreate(game.Game))
.Pairwise()
.Subscribe(pair =>
{
// Save old
var (previous, current) = pair;
if (previous != null)
{
previous.GameLocation = GameLocation.TargetPath;
}
// Load new
GameLocation.TargetPath = current?.GameLocation;
if (string.IsNullOrWhiteSpace(GameLocation.TargetPath))
{
SetGameToSteamLocation();
}
if (string.IsNullOrWhiteSpace(GameLocation.TargetPath))
{
SetGameToGogLocation();
}
DownloadsLocation.TargetPath = current?.DownloadLocation;
if (string.IsNullOrWhiteSpace(DownloadsLocation.TargetPath))
{
DownloadsLocation.TargetPath = VortexCompiler.RetrieveDownloadLocation(SelectedGame.Game);
}
StagingLocation.TargetPath = current?.StagingLocation;
if (string.IsNullOrWhiteSpace(StagingLocation.TargetPath))
{
StagingLocation.TargetPath = VortexCompiler.RetrieveStagingLocation(SelectedGame.Game);
}
})
.DisposeWith(CompositeDisposable);
// Find game commands
FindGameInSteamCommand = ReactiveCommand.Create(SetGameToSteamLocation);
FindGameInGogCommand = ReactiveCommand.Create(SetGameToGogLocation);
// Add additional criteria to download/staging folders
DownloadsLocation.AdditionalError = this.WhenAny(x => x.DownloadsLocation.TargetPath)
.Select(path => path == null ? ErrorResponse.Success : VortexCompiler.IsValidDownloadsFolder(path));
StagingLocation.AdditionalError = this.WhenAny(x => x.StagingLocation.TargetPath)
.Select(path => path == null ? ErrorResponse.Success : VortexCompiler.IsValidBaseStagingFolder(path));
}
public void Unload()
{
_settings.LastCompiledGame = SelectedGame.Game;
ModlistSettings?.Save();
}
private void SetGameToSteamLocation()
{
GameLocation.TargetPath = StoreHandler.Instance.GetGamePath(SelectedGame.Game, StoreType.STEAM);
}
private void SetGameToGogLocation()
{
GameLocation.TargetPath = StoreHandler.Instance.GetGamePath(SelectedGame.Game, StoreType.GOG);
}
public async Task<GetResponse<ModList>> Compile()
{
string outputFile = $"{ModlistSettings.ModListName}{Consts.ModListExtension}";
if (!string.IsNullOrWhiteSpace(Parent.OutputLocation.TargetPath))
{
outputFile = Path.Combine(Parent.OutputLocation.TargetPath, outputFile);
}
try
{
using (ActiveCompilation = new VortexCompiler(
game: SelectedGame.Game,
gamePath: GameLocation.TargetPath,
vortexFolder: VortexCompiler.TypicalVortexFolder(),
downloadsFolder: DownloadsLocation.TargetPath,
stagingFolder: StagingLocation.TargetPath,
outputFile: outputFile)
{
ModListName = ModlistSettings.ModListName,
ModListAuthor = ModlistSettings.AuthorText,
ModListDescription = ModlistSettings.Description,
ModListImage = ModlistSettings.ImagePath.TargetPath,
ModListWebsite = ModlistSettings.Website,
ModListReadme = ModlistSettings.ReadmeIsWebsite ? ModlistSettings.Readme : ModlistSettings.ReadmeFilePath.TargetPath,
ReadmeIsWebsite = ModlistSettings.ReadmeIsWebsite,
})
{
Parent.MWVM.Settings.Performance.AttachToBatchProcessor(ActiveCompilation);
var success = await ActiveCompilation.Begin();
return GetResponse<ModList>.Create(success, ActiveCompilation.ModList);
}
}
finally
{
StatusTracker = null;
ActiveCompilation.Dispose();
ActiveCompilation = null;
}
}
}
}

View File

@ -128,8 +128,6 @@ namespace Wabbajack
{
case ModManager.MO2:
return new MO2InstallerVM(this);
/*case ModManager.Vortex:
return new VortexInstallerVM(this);*/
default:
return null;
}

View File

@ -1,93 +0,0 @@
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;
using Wabbajack.Util;
namespace Wabbajack
{
public class VortexInstallerVM : ViewModel, ISubInstallerVM
{
public InstallerVM Parent { 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 bool SupportsAfterInstallNavigation => false;
public int ConfigVisualVerticalOffset => 0;
public IObservable<bool> CanInstall { get; }
public VortexInstallerVM(InstallerVM installerVM)
{
Parent = installerVM;
_TargetGame = installerVM.WhenAny(x => x.ModList.SourceModList.GameType)
.ToGuiProperty(this, nameof(TargetGame));
CanInstall = Observable.CombineLatest(
this.WhenAny(x => x.TargetGame)
.Select(game => VortexCompiler.IsActiveVortexGame(game)),
installerVM.WhenAny(x => x.ModListLocation.InError),
resultSelector: (isVortexGame, modListErr) => isVortexGame && !modListErr);
}
public void Unload()
{
}
public void AfterInstallNavigation()
{
throw new NotImplementedException();
}
public async Task<bool> Install()
{
AInstaller installer;
var download = VortexCompiler.RetrieveDownloadLocation(TargetGame);
var staging = VortexCompiler.RetrieveStagingLocation(TargetGame);
using (installer = new VortexInstaller(
archive: Parent.ModListLocation.TargetPath,
modList: Parent.ModList.SourceModList,
outputFolder: staging,
downloadFolder: download,
parameters: SystemParametersConstructor.Create()))
{
Parent.MWVM.Settings.Performance.AttachToBatchProcessor(installer);
return await Task.Run(async () =>
{
try
{
var workTask = installer.Begin();
ActiveInstallation = installer;
return await workTask;
}
finally
{
ActiveInstallation = null;
}
});
}
}
public IUserIntervention InterventionConverter(IUserIntervention intervention) => intervention;
}
}

View File

@ -197,16 +197,6 @@
<BitmapImage UriSource="../../Resources/MO2Button.png" />
</local:ImageRadioButtonView.Image>
</local:ImageRadioButtonView>
<local:ImageRadioButtonView
x:Name="VortexCompilerButton"
Grid.Row="1"
Height="35"
Margin="4"
IsChecked="{Binding SelectedCompilerType, Converter={StaticResource EqualsToBoolConverter}, ConverterParameter={x:Static wabbacommon:ModManager.Vortex}}">
<local:ImageRadioButtonView.Image>
<BitmapImage UriSource="../../Resources/VortexButton.png" />
</local:ImageRadioButtonView.Image>
</local:ImageRadioButtonView>
</Grid>
<ContentPresenter
x:Name="CustomCompilerSettingsPresenter"
@ -216,11 +206,6 @@
<DataTemplate DataType="{x:Type local:MO2CompilerVM}">
<local:MO2CompilerConfigView />
</DataTemplate>
<!--
<DataTemplate DataType="{x:Type local:VortexCompilerVM}">
<local:VortexCompilerConfigView />
</DataTemplate>
-->
</ContentPresenter.Resources>
</ContentPresenter>
<local:BeginButton

View File

@ -82,13 +82,6 @@ namespace Wabbajack
.Select(started => started ? Visibility.Hidden : Visibility.Visible)
.BindToStrict(this, x => x.BottomCompilerSettingsGrid.Visibility)
.DisposeWith(dispose);
// Seems to go into an infinite loop between each other. Need to research a better radio button style pattern
//this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked,
// vmToViewConverter: type => type == ModManager.MO2,
// viewToVmConverter: isChecked => isChecked ? ModManager.MO2 : ModManager.Vortex);
//this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked,
// vmToViewConverter: type => type == ModManager.Vortex,
// viewToVmConverter: isChecked => isChecked ? ModManager.Vortex : ModManager.MO2);
this.WhenAny(x => x.ViewModel.Compiler)
.BindToStrict(this, x => x.CustomCompilerSettingsPresenter.Content)
.DisposeWith(dispose);

View File

@ -358,11 +358,6 @@
<DataTemplate DataType="{x:Type local:MO2InstallerVM}">
<local:MO2InstallerConfigView />
</DataTemplate>
<!--
<DataTemplate DataType="{x:Type local:VortexInstallerVM}">
<local:VortexInstallerConfigView />
</DataTemplate>
-->
</ContentPresenter.Resources>
<ContentPresenter.Style>
<Style TargetType="ContentPresenter">

View File

@ -1,13 +0,0 @@
<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>
</Grid>
</UserControl>

View File

@ -1,28 +0,0 @@
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

@ -51,7 +51,6 @@
<None Remove="Resources\Wabba_Mouth_No_Text.png" />
<None Remove="Resources\Wabba_Mouth_Small.png" />
<Compile Remove="View Models\Compilers\VortexCompilerVM.cs" />
<None Include="View Models\Compilers\VortexCompilerVM.cs" />
<Compile Remove="View Models\Installers\VortexInstallerVM.cs" />
<None Include="View Models\Installers\VortexInstallerVM.cs" />
</ItemGroup>