Added MatchAll support to mods

This commit is contained in:
Timothy Baldridge 2020-02-04 22:17:12 -07:00
parent d983bcc168
commit b030dd67ca
16 changed files with 206 additions and 68 deletions

View File

@ -99,5 +99,6 @@ namespace Wabbajack.Common
public static string WabbajackCacheHostname = "build.wabbajack.org"; public static string WabbajackCacheHostname = "build.wabbajack.org";
public static int WabbajackCachePort = 80; public static int WabbajackCachePort = 80;
public static int MaxHTTPRetries = 4; public static int MaxHTTPRetries = 4;
public const string MO2ModFolderName = "mods";
} }
} }

62
Wabbajack.Common/Paths.cs Normal file
View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using APath = Alphaleonis.Win32.Filesystem.Path;
using AFile = Alphaleonis.Win32.Filesystem.File;
using Directory = System.IO.Directory;
using FileInfo = Alphaleonis.Win32.Filesystem.FileInfo;
namespace Wabbajack.Common.Paths
{
public struct File
{
internal readonly string _path;
public Directory Parent
{
get
{
var parent = APath.GetDirectoryName(_path);
if (parent == "")
{
throw new NoParentDirectoryException(_path);
}
return new Directory(parent);
}
}
public bool Exists => AFile.Exists(_path);
public bool IsTopLevelFile => APath.GetDirectoryName(_path) == null;
public string Extension => APath.GetExtension(_path);
public long Length => new FileInfo(_path).Length;
private File(string path)
{
_path = path;
}
public FileStream Create()
{
return AFile.Create(_path);
}
}
public struct Directory
{
private string _path;
internal Directory(string path)
{
_path = path;
}
}
public class NoParentDirectoryException : Exception
{
private string _path;
public NoParentDirectoryException(string path) : base($"Cannot get the parent directory of a top level directory: {path}")
{
_path = path;
}
}
}

View File

@ -820,7 +820,7 @@ namespace Wabbajack.Common
return ToFileSizeString((long)byteCount); return ToFileSizeString((long)byteCount);
} }
public static void CreatePatch(byte[] a, byte[] b, Stream output) public static async Task CreatePatch(byte[] a, byte[] b, Stream output)
{ {
var dataA = a.xxHash().FromBase64().ToHex(); var dataA = a.xxHash().FromBase64().ToHex();
var dataB = b.xxHash().FromBase64().ToHex(); var dataB = b.xxHash().FromBase64().ToHex();
@ -834,20 +834,30 @@ namespace Wabbajack.Common
{ {
using (var f = File.OpenRead(cacheFile)) using (var f = File.OpenRead(cacheFile))
{ {
f.CopyTo(output); await f.CopyToAsync(output);
} }
} }
else else
{ {
var tmpName = Path.Combine("patch_cache", Guid.NewGuid() + ".tmp"); var tmpName = Path.Combine("patch_cache", Guid.NewGuid() + ".tmp");
using (var f = File.Open(tmpName, System.IO.FileMode.Create)) await using (var f = File.Open(tmpName, System.IO.FileMode.Create))
{ {
Status("Creating Patch"); Status("Creating Patch");
BSDiff.Create(a, b, f); BSDiff.Create(a, b, f);
} }
RETRY:
try
{
File.Move(tmpName, cacheFile, MoveOptions.ReplaceExisting); File.Move(tmpName, cacheFile, MoveOptions.ReplaceExisting);
}
catch (UnauthorizedAccessException)
{
await Task.Delay(1000);
goto RETRY;
}
continue; continue;
} }
@ -1224,5 +1234,12 @@ namespace Wabbajack.Common
random.NextBytes(bytes); random.NextBytes(bytes);
return bytes.ToHex(); return bytes.ToHex();
} }
public static async Task CopyFileAsync(string src, string dest)
{
await using var s = File.OpenRead(src);
await using var d = File.Create(dest);
await s.CopyToAsync(d);
}
} }
} }

View File

@ -7,14 +7,15 @@ using Compression.BSA;
using Newtonsoft.Json; using Newtonsoft.Json;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Common.StatusFeed.Errors; using Wabbajack.Common.StatusFeed.Errors;
using Wabbajack.VirtualFileSystem;
namespace Wabbajack.Lib.CompilationSteps namespace Wabbajack.Lib.CompilationSteps
{ {
public class DeconstructBSAs : ACompilationStep public class DeconstructBSAs : ACompilationStep
{ {
private readonly IEnumerable<string> _includeDirectly; private readonly IEnumerable<string> _includeDirectly;
private readonly List<ICompilationStep> _microstack; private readonly Func<VirtualFile, List<ICompilationStep>> _microstack;
private readonly List<ICompilationStep> _microstackWithInclude; private readonly Func<VirtualFile, List<ICompilationStep>> _microstackWithInclude;
private readonly MO2Compiler _mo2Compiler; private readonly MO2Compiler _mo2Compiler;
public DeconstructBSAs(ACompiler compiler) : base(compiler) public DeconstructBSAs(ACompiler compiler) : base(compiler)
@ -30,17 +31,17 @@ namespace Wabbajack.Lib.CompilationSteps
.Select(kv => $"mods\\{kv.Key}\\") .Select(kv => $"mods\\{kv.Key}\\")
.ToList(); .ToList();
_microstack = new List<ICompilationStep> _microstack = bsa => new List<ICompilationStep>
{ {
new DirectMatch(_mo2Compiler), new DirectMatch(_mo2Compiler),
new IncludePatches(_mo2Compiler), new IncludePatches(_mo2Compiler, bsa),
new DropAll(_mo2Compiler) new DropAll(_mo2Compiler)
}; };
_microstackWithInclude = new List<ICompilationStep> _microstackWithInclude = bsa => new List<ICompilationStep>
{ {
new DirectMatch(_mo2Compiler), new DirectMatch(_mo2Compiler),
new IncludePatches(_mo2Compiler), new IncludePatches(_mo2Compiler, bsa),
new IncludeAll(_mo2Compiler) new IncludeAll(_mo2Compiler)
}; };
} }
@ -55,13 +56,13 @@ namespace Wabbajack.Lib.CompilationSteps
if (!Consts.SupportedBSAs.Contains(Path.GetExtension(source.Path).ToLower())) return null; if (!Consts.SupportedBSAs.Contains(Path.GetExtension(source.Path).ToLower())) return null;
var defaultInclude = false; var defaultInclude = false;
if (source.Path.StartsWith("mods")) if (source.Path.StartsWith(Consts.MO2ModFolderName))
if (_includeDirectly.Any(path => source.Path.StartsWith(path))) if (_includeDirectly.Any(path => source.Path.StartsWith(path)))
defaultInclude = true; defaultInclude = true;
var sourceFiles = source.File.Children; var sourceFiles = source.File.Children;
var stack = defaultInclude ? _microstackWithInclude : _microstack; var stack = defaultInclude ? _microstackWithInclude(source.File) : _microstack(source.File);
var id = Guid.NewGuid().ToString(); var id = Guid.NewGuid().ToString();

View File

@ -22,13 +22,13 @@ namespace Wabbajack.Lib.CompilationSteps
.Where(line => line.StartsWith("+") || line.EndsWith("_separator")) .Where(line => line.StartsWith("+") || line.EndsWith("_separator"))
.Select(line => line.Substring(1)) .Select(line => line.Substring(1))
.Concat(alwaysEnabled) .Concat(alwaysEnabled)
.Select(line => Path.Combine("mods", line) + "\\") .Select(line => Path.Combine(Consts.MO2ModFolderName, line) + "\\")
.ToList(); .ToList();
} }
public override async ValueTask<Directive> Run(RawSourceFile source) public override async ValueTask<Directive> Run(RawSourceFile source)
{ {
if (!source.Path.StartsWith("mods") || _allEnabledMods.Any(mod => source.Path.StartsWith(mod))) if (!source.Path.StartsWith(Consts.MO2ModFolderName) || _allEnabledMods.Any(mod => source.Path.StartsWith(mod)))
return null; return null;
var r = source.EvolveTo<IgnoredDirectly>(); var r = source.EvolveTo<IgnoredDirectly>();
r.Reason = "Disabled Mod"; r.Reason = "Disabled Mod";
@ -50,7 +50,7 @@ namespace Wabbajack.Lib.CompilationSteps
Consts.WABBAJACK_ALWAYS_ENABLE)) Consts.WABBAJACK_ALWAYS_ENABLE))
return true; return true;
if (data.General != null && data.General.comments != null && if (data.General != null && data.General.comments != null &&
data.General.notes.Contains(Consts.WABBAJACK_ALWAYS_ENABLE)) data.General.comments.Contains(Consts.WABBAJACK_ALWAYS_ENABLE))
return true; return true;
return false; return false;
} }

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem; using Alphaleonis.Win32.Filesystem;
@ -11,13 +12,20 @@ namespace Wabbajack.Lib.CompilationSteps
public class IncludePatches : ACompilationStep public class IncludePatches : ACompilationStep
{ {
private readonly Dictionary<string, IGrouping<string, VirtualFile>> _indexed; private readonly Dictionary<string, IGrouping<string, VirtualFile>> _indexed;
private VirtualFile _bsa;
private Dictionary<string, VirtualFile> _indexedByName;
public IncludePatches(ACompiler compiler) : base(compiler) public IncludePatches(ACompiler compiler, VirtualFile constructingFromBSA = null) : base(compiler)
{ {
_bsa = constructingFromBSA;
_indexed = _compiler.IndexedFiles.Values _indexed = _compiler.IndexedFiles.Values
.SelectMany(f => f) .SelectMany(f => f)
.GroupBy(f => Path.GetFileName(f.Name).ToLower()) .GroupBy(f => Path.GetFileName(f.Name).ToLower())
.ToDictionary(f => f.Key); .ToDictionary(f => f.Key);
_indexedByName = _indexed.Values
.SelectMany(s => s)
.Where(f => f.IsNative)
.ToDictionary(f => Path.GetFileName(f.FullPath));
} }
public override async ValueTask<Directive> Run(RawSourceFile source) public override async ValueTask<Directive> Run(RawSourceFile source)
@ -28,22 +36,53 @@ namespace Wabbajack.Lib.CompilationSteps
nameWithoutExt = Path.GetFileNameWithoutExtension(name); nameWithoutExt = Path.GetFileNameWithoutExtension(name);
if (!_indexed.TryGetValue(Path.GetFileName(name), out var choices)) if (!_indexed.TryGetValue(Path.GetFileName(name), out var choices))
if (!_indexed.TryGetValue(Path.GetFileName(nameWithoutExt), out choices)) _indexed.TryGetValue(Path.GetFileName(nameWithoutExt), out choices);
return null;
var mod_ini = ((MO2Compiler)_compiler).ModMetas.FirstOrDefault(f => source.Path.StartsWith(f.Key)); dynamic mod_ini;
var installationFile = mod_ini.Value?.General?.installationFile; if (_bsa == null)
mod_ini = ((MO2Compiler)_compiler).ModMetas.FirstOrDefault(f => source.Path.StartsWith(f.Key)).Value;
else
{
var bsa_path = _bsa.FullPath.RelativeTo(((MO2Compiler)_compiler).MO2Folder);
mod_ini = ((MO2Compiler)_compiler).ModMetas.FirstOrDefault(f => bsa_path.StartsWith(f.Key)).Value;
}
var found = choices.FirstOrDefault( var installationFile = mod_ini?.General?.installationFile;
VirtualFile found = null;
// Find based on exact file name + ext
if (choices != null)
{
found = choices.FirstOrDefault(
f => Path.GetFileName(f.FilesInFullPath.First().Name) == installationFile); f => Path.GetFileName(f.FilesInFullPath.First().Name) == installationFile);
}
if (found == null) // Find based on file name only (not ext)
if (found == null && choices != null)
{ {
found = choices.OrderBy(f => f.NestingFactor) found = choices.OrderBy(f => f.NestingFactor)
.ThenByDescending(f => (f.FilesInFullPath.First() ?? f).LastModified) .ThenByDescending(f => (f.FilesInFullPath.First() ?? f).LastModified)
.First(); .First();
} }
// Find based on matchAll=<archivename> in [General] in meta.ini
var matchAllName = (string)mod_ini?.General?.matchAll;
if (matchAllName != null)
{
matchAllName = matchAllName.Trim();
if (_indexedByName.TryGetValue(matchAllName, out var arch))
{
// Just match some file in the archive based on the smallest delta difference
found = arch.ThisAndAllChildren
.OrderBy(o => Math.Abs(o.Size - source.File.Size))
.First();
}
}
if (found == null)
return null;
var e = source.EvolveTo<PatchedFromArchive>(); var e = source.EvolveTo<PatchedFromArchive>();
e.FromHash = found.Hash; e.FromHash = found.Hash;
e.ArchiveHashPath = found.MakeRelativePaths(); e.ArchiveHashPath = found.MakeRelativePaths();

View File

@ -3,6 +3,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Alphaleonis.Win32.Filesystem; using Alphaleonis.Win32.Filesystem;
using Newtonsoft.Json; using Newtonsoft.Json;
using Wabbajack.Common;
namespace Wabbajack.Lib.CompilationSteps namespace Wabbajack.Lib.CompilationSteps
{ {
@ -27,7 +28,7 @@ namespace Wabbajack.Lib.CompilationSteps
public override async ValueTask<Directive> Run(RawSourceFile source) public override async ValueTask<Directive> Run(RawSourceFile source)
{ {
if (!source.Path.StartsWith("mods")) return null; if (!source.Path.StartsWith(Consts.MO2ModFolderName)) return null;
foreach (var modpath in _includeDirectly) foreach (var modpath in _includeDirectly)
{ {
if (!source.Path.StartsWith(modpath)) continue; if (!source.Path.StartsWith(modpath)) continue;

View File

@ -29,9 +29,9 @@ namespace Wabbajack.Lib.CompilationSteps
result.SourceESMHash = _compiler.VFS.Index.ByRootPath[gameFile].Hash; result.SourceESMHash = _compiler.VFS.Index.ByRootPath[gameFile].Hash;
Utils.Status($"Generating patch of {filename}"); Utils.Status($"Generating patch of {filename}");
using (var ms = new MemoryStream()) await using (var ms = new MemoryStream())
{ {
Utils.CreatePatch(File.ReadAllBytes(gameFile), File.ReadAllBytes(source.AbsolutePath), ms); await Utils.CreatePatch(File.ReadAllBytes(gameFile), File.ReadAllBytes(source.AbsolutePath), ms);
var data = ms.ToArray(); var data = ms.ToArray();
result.SourceDataID = _compiler.IncludeFile(data); result.SourceDataID = _compiler.IncludeFile(data);
Utils.Log($"Generated a {data.Length} byte patch for {filename}"); Utils.Log($"Generated a {data.Length} byte patch for {filename}");

View File

@ -181,7 +181,7 @@ namespace Wabbajack.Lib
} }
ModMetas = Directory.EnumerateDirectories(Path.Combine(MO2Folder, "mods")) ModMetas = Directory.EnumerateDirectories(Path.Combine(MO2Folder, Consts.MO2ModFolderName))
.Keep(f => .Keep(f =>
{ {
var path = Path.Combine(f, "meta.ini"); var path = Path.Combine(f, "meta.ini");
@ -222,7 +222,7 @@ namespace Wabbajack.Lib
if (cancel.IsCancellationRequested) return false; if (cancel.IsCancellationRequested) return false;
UpdateTracker.NextStep("Loading INIs"); UpdateTracker.NextStep("Loading INIs");
ModInis = Directory.EnumerateDirectories(Path.Combine(MO2Folder, "mods")) ModInis = Directory.EnumerateDirectories(Path.Combine(MO2Folder, Consts.MO2ModFolderName))
.Select(f => .Select(f =>
{ {
var modName = Path.GetFileName(f); var modName = Path.GetFileName(f);
@ -427,20 +427,18 @@ namespace Wabbajack.Lib
var byPath = files.GroupBy(f => string.Join("|", f.FilesInFullPath.Skip(1).Select(i => i.Name))) var byPath = files.GroupBy(f => string.Join("|", f.FilesInFullPath.Skip(1).Select(i => i.Name)))
.ToDictionary(f => f.Key, f => f.First()); .ToDictionary(f => f.Key, f => f.First());
// Now Create the patches // Now Create the patches
await group.PMap(Queue, entry => await group.PMap(Queue, async entry =>
{ {
Info($"Patching {entry.To}"); Info($"Patching {entry.To}");
Status($"Patching {entry.To}"); Status($"Patching {entry.To}");
using (var origin = byPath[string.Join("|", entry.ArchiveHashPath.Skip(1))].OpenRead()) await using var origin = byPath[string.Join("|", entry.ArchiveHashPath.Skip(1))].OpenRead();
using (var output = new MemoryStream()) await using var output = new MemoryStream();
{
var a = origin.ReadAll(); var a = origin.ReadAll();
var b = LoadDataForTo(entry.To, absolutePaths); var b = LoadDataForTo(entry.To, absolutePaths);
Utils.CreatePatch(a, b, output); await Utils.CreatePatch(a, b, output);
entry.PatchID = IncludeFile(output.ToArray()); entry.PatchID = IncludeFile(output.ToArray());
var fileSize = File.GetSize(Path.Combine(ModListOutputFolder, entry.PatchID)); var fileSize = File.GetSize(Path.Combine(ModListOutputFolder, entry.PatchID));
Info($"Patch size {fileSize} for {entry.To}"); Info($"Patch size {fileSize} for {entry.To}");
}
}); });
} }
} }

View File

@ -73,7 +73,7 @@ namespace Wabbajack.Lib
Directory.CreateDirectory(OutputFolder); Directory.CreateDirectory(OutputFolder);
Directory.CreateDirectory(DownloadFolder); Directory.CreateDirectory(DownloadFolder);
if (Directory.Exists(Path.Combine(OutputFolder, "mods")) && WarnOnOverwrite) if (Directory.Exists(Path.Combine(OutputFolder, Consts.MO2ModFolderName)) && WarnOnOverwrite)
{ {
if ((await Utils.Log(new ConfirmUpdateOfExistingInstall { ModListName = ModList.Name, OutputFolder = OutputFolder }).Task) == ConfirmUpdateOfExistingInstall.Choice.Abort) if ((await Utils.Log(new ConfirmUpdateOfExistingInstall { ModListName = ModList.Name, OutputFolder = OutputFolder }).Task) == ConfirmUpdateOfExistingInstall.Choice.Abort)
{ {
@ -175,7 +175,7 @@ namespace Wabbajack.Lib
data.Coll.Do(keyData => data.Coll.Do(keyData =>
{ {
var v = keyData.Value; var v = keyData.Value;
var mod = Path.Combine(OutputFolder, "mods", v); var mod = Path.Combine(OutputFolder, Consts.MO2ModFolderName, v);
if (!Directory.Exists(mod)) if (!Directory.Exists(mod))
Directory.CreateDirectory(mod); Directory.CreateDirectory(mod);

View File

@ -492,7 +492,7 @@ namespace Wabbajack.Lib
{ {
vortexFolderPath = vortexFolderPath ?? TypicalVortexFolder(); vortexFolderPath = vortexFolderPath ?? TypicalVortexFolder();
var gameName = game.MetaData().NexusName; var gameName = game.MetaData().NexusName;
return Path.Combine(vortexFolderPath, gameName, "mods"); return Path.Combine(vortexFolderPath, gameName, Consts.MO2ModFolderName);
} }
public static IErrorResponse IsValidBaseDownloadsFolder(string path) public static IErrorResponse IsValidBaseDownloadsFolder(string path)

View File

@ -67,7 +67,7 @@ namespace Wabbajack.Lib
_mergesIndexed = _mergesIndexed =
merges.ToDictionary( merges.ToDictionary(
m => Path.Combine(_mo2Compiler.MO2Folder, "mods", m.Key.name, m.Key.filename), m => Path.Combine(_mo2Compiler.MO2Folder, Consts.MO2ModFolderName, m.Key.name, m.Key.filename),
m => m.First()); m => m.First());
} }
@ -103,9 +103,9 @@ namespace Wabbajack.Lib
var dst_data = File.ReadAllBytes(source.AbsolutePath); var dst_data = File.ReadAllBytes(source.AbsolutePath);
using (var ms = new MemoryStream()) await using (var ms = new MemoryStream())
{ {
Utils.CreatePatch(src_data, dst_data, ms); await Utils.CreatePatch(src_data, dst_data, ms);
result.PatchID = _compiler.IncludeFile(ms.ToArray()); result.PatchID = _compiler.IncludeFile(ms.ToArray());
} }

View File

@ -61,11 +61,24 @@ namespace Wabbajack.Test
"directURL=https://github.com/ModOrganizer2/modorganizer/releases/download/v2.2.1/Mod.Organizer.2.2.1.7z" "directURL=https://github.com/ModOrganizer2/modorganizer/releases/download/v2.2.1/Mod.Organizer.2.2.1.7z"
}); });
await DownloadAndInstall(Game.SkyrimSpecialEdition, 12604, "SkyUI"); var modfiles = await Task.WhenAll(
await DownloadAndInstall(Game.Fallout4, 11925, "Anti-Tank Rifle"); DownloadAndInstall(Game.SkyrimSpecialEdition, 12604, "SkyUI"),
DownloadAndInstall(Game.Fallout4, 11925, "Anti-Tank Rifle"),
DownloadAndInstall(Game.SkyrimSpecialEdition, 4783, "Frost Armor UNP"),
DownloadAndInstall(Game.SkyrimSpecialEdition, 32359, "Frost Armor HDT"));
// We're going to fully patch this mod from another source.
File.Delete(modfiles[3].Download);
utils.Configure(); utils.Configure();
File.WriteAllLines(Path.Combine(modfiles[3].ModFolder, "meta.ini"), new []
{
"[General]",
$"matchAll= {Path.GetFileName(modfiles[2].Download)}"
});
var modlist = await CompileAndInstall(profile); var modlist = await CompileAndInstall(profile);
utils.VerifyAllFiles(); utils.VerifyAllFiles();
@ -97,18 +110,19 @@ namespace Wabbajack.Test
Directory.CreateDirectory(utils.DownloadsFolder); Directory.CreateDirectory(utils.DownloadsFolder);
} }
File.Copy(src, Path.Combine(utils.DownloadsFolder, filename)); await Utils.CopyFileAsync(src, Path.Combine(utils.DownloadsFolder, filename));
await FileExtractor.ExtractAll(Queue, src, await FileExtractor.ExtractAll(Queue, src,
mod_name == null ? utils.MO2Folder : Path.Combine(utils.ModsFolder, mod_name)); mod_name == null ? utils.MO2Folder : Path.Combine(utils.ModsFolder, mod_name));
} }
private async Task DownloadAndInstall(Game game, int modid, string mod_name) private async Task<(string Download, string ModFolder)> DownloadAndInstall(Game game, int modid, string mod_name)
{ {
utils.AddMod(mod_name); utils.AddMod(mod_name);
var client = await NexusApiClient.Get(); var client = await NexusApiClient.Get();
var resp = await client.GetModFiles(game, modid); var resp = await client.GetModFiles(game, modid);
var file = resp.files.First(f => f.is_primary); var file = resp.files.FirstOrDefault(f => f.is_primary) ?? resp.files.FirstOrDefault(f => !string.IsNullOrEmpty(f.category_name));
var src = Path.Combine(DOWNLOAD_FOLDER, file.file_name); var src = Path.Combine(DOWNLOAD_FOLDER, file.file_name);
var ini = string.Join("\n", var ini = string.Join("\n",
@ -133,11 +147,13 @@ namespace Wabbajack.Test
} }
var dest = Path.Combine(utils.DownloadsFolder, file.file_name); var dest = Path.Combine(utils.DownloadsFolder, file.file_name);
File.Copy(src, dest); await Utils.CopyFileAsync(src, dest);
await FileExtractor.ExtractAll(Queue, src, Path.Combine(utils.ModsFolder, mod_name)); var modFolder = Path.Combine(utils.ModsFolder, mod_name);
await FileExtractor.ExtractAll(Queue, src, modFolder);
File.WriteAllText(dest + Consts.MetaFileExtension, ini); File.WriteAllText(dest + Consts.MetaFileExtension, ini);
return (dest, modFolder);
} }
private async Task<ModList> CompileAndInstall(string profile) private async Task<ModList> CompileAndInstall(string profile)

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Compression.BSA;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Lib; using Wabbajack.Lib;
@ -254,6 +255,5 @@ namespace Wabbajack.Test
Assert.IsNotNull(directive); Assert.IsNotNull(directive);
Assert.IsInstanceOfType(directive, typeof(PatchedFromArchive)); Assert.IsInstanceOfType(directive, typeof(PatchedFromArchive));
} }
} }
} }

View File

@ -32,7 +32,7 @@ namespace Wabbajack.Test
public string GameFolder => Path.Combine(WorkingDirectory, ID, "game_folder"); public string GameFolder => Path.Combine(WorkingDirectory, ID, "game_folder");
public string MO2Folder => Path.Combine(WorkingDirectory, ID, "mo2_folder"); public string MO2Folder => Path.Combine(WorkingDirectory, ID, "mo2_folder");
public string ModsFolder => Path.Combine(MO2Folder, "mods"); public string ModsFolder => Path.Combine(MO2Folder, Consts.MO2ModFolderName);
public string DownloadsFolder => Path.Combine(MO2Folder, "downloads"); public string DownloadsFolder => Path.Combine(MO2Folder, "downloads");
public string InstallFolder => Path.Combine(TestFolder, "installed"); public string InstallFolder => Path.Combine(TestFolder, "installed");
@ -70,14 +70,17 @@ namespace Wabbajack.Test
} }
public string AddMod(string name = null) public string AddMod(string name = null)
{
lock (this)
{ {
string mod_name = name ?? RandomName(); string mod_name = name ?? RandomName();
var mod_folder = Path.Combine(MO2Folder, "mods", mod_name); var mod_folder = Path.Combine(MO2Folder, Consts.MO2ModFolderName, mod_name);
Directory.CreateDirectory(mod_folder); Directory.CreateDirectory(mod_folder);
File.WriteAllText(Path.Combine(mod_folder, "meta.ini"), "[General]"); File.WriteAllText(Path.Combine(mod_folder, "meta.ini"), "[General]");
Mods.Add(mod_name); Mods.Add(mod_name);
return mod_name; return mod_name;
} }
}
/// <summary> /// <summary>
/// Adds a file to the given mod with a given path in the mod. Fills it with random data unless /// Adds a file to the given mod with a given path in the mod. Fills it with random data unless
@ -160,10 +163,10 @@ namespace Wabbajack.Test
public void VerifyInstalledFile(string mod, string file) public void VerifyInstalledFile(string mod, string file)
{ {
var src = Path.Combine(MO2Folder, "mods", mod, file); var src = Path.Combine(MO2Folder, Consts.MO2ModFolderName, mod, file);
Assert.IsTrue(File.Exists(src), src); Assert.IsTrue(File.Exists(src), src);
var dest = Path.Combine(InstallFolder, "mods", mod, file); var dest = Path.Combine(InstallFolder, Consts.MO2ModFolderName, mod, file);
Assert.IsTrue(File.Exists(dest), dest); Assert.IsTrue(File.Exists(dest), dest);
var src_data = File.ReadAllBytes(src); var src_data = File.ReadAllBytes(src);
@ -199,7 +202,7 @@ namespace Wabbajack.Test
} }
public string PathOfInstalledFile(string mod, string file) public string PathOfInstalledFile(string mod, string file)
{ {
return Path.Combine(InstallFolder, "mods", mod, file); return Path.Combine(InstallFolder, Consts.MO2ModFolderName, mod, file);
} }
public void VerifyAllFiles() public void VerifyAllFiles()

View File

@ -38,17 +38,17 @@ namespace Wabbajack.Test
new zEditIntegration.zEditMergePlugin() new zEditIntegration.zEditMergePlugin()
{ {
filename = "srca.esp", filename = "srca.esp",
dataFolder = Path.Combine(utils.MO2Folder, "mods", moda) dataFolder = Path.Combine(utils.MO2Folder, Consts.MO2ModFolderName, moda)
}, },
new zEditIntegration.zEditMergePlugin() new zEditIntegration.zEditMergePlugin()
{ {
filename = "srcb.esp", filename = "srcb.esp",
dataFolder = Path.Combine(utils.MO2Folder, "mods", moda), dataFolder = Path.Combine(utils.MO2Folder, Consts.MO2ModFolderName, moda),
}, },
new zEditIntegration.zEditMergePlugin() new zEditIntegration.zEditMergePlugin()
{ {
filename = "srcc.esp", filename = "srcc.esp",
dataFolder = Path.Combine(utils.MO2Folder, "mods", modb), dataFolder = Path.Combine(utils.MO2Folder, Consts.MO2ModFolderName, modb),
} }
} }
} }