modlists are now .zip files, several bug fixes found in testing

This commit is contained in:
Timothy Baldridge 2019-10-01 16:39:25 -06:00
parent eb827f5909
commit 4597135de5
20 changed files with 193 additions and 109 deletions

View File

@ -2,6 +2,9 @@
#### Version 0.9.4 - ???
* Point github icon to https://github.com/wabbajack-tools/wabbajack
* Add game registry entry for Skyrim VR
* Modlists are now .zip files.
* Modlists now end with `.modlist_v1` to enable better version control
#### Version 0.9.3 - 9/30/2019
* Add WABBAJACK_NOMATCH_INCLUDE works like WABBAJACK_INCLUDE but only includes files that are found to be missing at the end of compilation

View File

@ -7,6 +7,7 @@ namespace Wabbajack.Common
{
public static class Consts
{
public static string ModlistExtension = ".modlist_v1";
public static string GameFolderFilesDir = "Game Folder Files";
public static string LOOTFolderFilesDir = "LOOT Config Files";
public static string ModListMagic = "Celebration!, Cheese for Everyone!";

View File

@ -14,7 +14,8 @@ namespace Wabbajack.Common
FalloutNewVegas,
Skyrim,
SkyrimSpecialEdition,
Fallout4
Fallout4,
SkyrimVR
}
public class GameMetaData
@ -102,6 +103,16 @@ namespace Wabbajack.Common
MO2ArchiveName = "fallout4",
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Fallout4"
}
},
{
Game.SkyrimVR, new GameMetaData
{
Game = Game.SkyrimVR,
NexusName = "skyrimspecialedition",
MO2Name = "Skyrim VR",
MO2ArchiveName = "skyrimse",
GameLocationRegistryKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Bethesda Softworks\Skyrim VR"
}
}
};
}

View File

@ -202,7 +202,8 @@ namespace Wabbajack.Common
public static T FromJSON<T>(this Stream data)
{
var s = Encoding.UTF8.GetString(data.ReadAll());
return JsonConvert.DeserializeObject<T>(s);
return JsonConvert.DeserializeObject<T>(s,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
}
public static bool FileExists(this string filename)
@ -490,6 +491,12 @@ namespace Wabbajack.Common
return dict.TryGetValue(key, out var result) ? result : default;
}
public static IEnumerable<T> ButLast<T>(this IEnumerable<T> coll)
{
var lst = coll.ToList();
return lst.Take(lst.Count() - 1);
}
public static byte[] ConcatArrays(this IEnumerable<byte[]> arrays)
{
var outarr = new byte[arrays.Sum(a => a.Length)];

View File

@ -100,7 +100,6 @@
<ItemGroup>
<EmbeddedResource Include="7z.dll.gz" />
<EmbeddedResource Include="7z.exe.gz" />
<None Include="innounp.exe.gz" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
@ -116,7 +115,6 @@
<ItemGroup>
<Content Include="7z.dll" />
<Content Include="7z.exe" />
<None Include="innounp.exe" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Binary file not shown.

Binary file not shown.

View File

@ -160,7 +160,7 @@ namespace Wabbajack.Test
// Error due to patched file
modlist.Directives[0] = new PatchedFromArchive
{
Patch = new byte[]{0, 1, 3},
PatchID = Guid.NewGuid().ToString(),
ArchiveHashPath = new[] {"DEADBEEF", "foo\\bar\\baz.pex"},
};
@ -176,7 +176,15 @@ namespace Wabbajack.Test
errors = validate.Validate(modlist);
Assert.AreEqual(errors.Count(), 1);
// No error since we're just installing the .bsa, not extracting it
modlist.Directives[0] = new FromArchive
{
ArchiveHashPath = new[] { "DEADBEEF", "foo.bsa"},
};
errors = validate.Validate(modlist);
Assert.AreEqual(0, errors.Count());
// Error due to game conversion
modlist.GameType = Game.SkyrimSpecialEdition;
modlist.Directives[0] = new FromArchive

View File

@ -103,7 +103,8 @@ namespace Wabbajack.Test
private void Install(Compiler compiler)
{
var installer = new Installer(compiler.ModList, utils.InstallFolder);
var modlist = Installer.LoadFromFile(compiler.ModListOutputFile);
var installer = new Installer(compiler.ModListOutputFile, modlist, utils.InstallFolder);
installer.DownloadFolder = utils.DownloadsFolder;
installer.GameFolder = utils.GameFolder;
installer.Install();

View File

@ -280,6 +280,8 @@ namespace Wabbajack
}
public string _splashScreenSummary = "";
private string _modListPath;
public string SplashScreenSummary
{
get => _splashScreenSummary;
@ -379,9 +381,10 @@ namespace Wabbajack
public bool Running { get; set; } = true;
internal void ConfigureForInstall(ModList modlist)
internal void ConfigureForInstall(string source, ModList modlist)
{
_modList = modlist;
_modListPath = source;
Mode = "Installing";
ModListName = _modList.Name;
HTMLReport = _modList.ReportHTML;
@ -481,7 +484,7 @@ namespace Wabbajack
UIReady = false;
if (Mode == "Installing")
{
var installer = new Installer(_modList, Location);
var installer = new Installer(_modListPath, _modList, Location);
installer.DownloadFolder = DownloadLocation;
var th = new Thread(() =>

View File

@ -14,6 +14,7 @@ using Compression.BSA;
using K4os.Compression.LZ4;
using K4os.Compression.LZ4.Streams;
using Newtonsoft.Json;
using System.IO.Compression;
using VFS;
using Wabbajack.Common;
using Wabbajack.NexusApi;
@ -67,6 +68,9 @@ namespace Wabbajack
public string MO2ProfileDir => Path.Combine(MO2Folder, "profiles", MO2Profile);
public string ModListOutputFolder => "output_folder";
public string ModListOutputFile => MO2Profile + Consts.ModlistExtension;
public List<Directive> InstallDirectives { get; private set; }
internal UserStatus User { get; private set; }
public List<Archive> SelectedArchives { get; private set; }
@ -98,6 +102,20 @@ namespace Wabbajack
throw new Exception(msg);
}
internal string IncludeFile(byte[] data)
{
var id = Guid.NewGuid().ToString();
File.WriteAllBytes(Path.Combine(ModListOutputFolder, id), data);
return id;
}
internal string IncludeFile(string data)
{
var id = Guid.NewGuid().ToString();
File.WriteAllText(Path.Combine(ModListOutputFolder, id), data);
return id;
}
public bool Compile()
{
VirtualFileSystem.Clean();
@ -117,6 +135,12 @@ namespace Wabbajack
Info($"Indexing {MO2DownloadsFolder}");
VFS.AddRoot(MO2DownloadsFolder);
Info("Cleaning output folder");
if (Directory.Exists(ModListOutputFolder))
Directory.Delete(ModListOutputFolder, true);
Directory.CreateDirectory(ModListOutputFolder);
var mo2_files = Directory.EnumerateFiles(MO2Folder, "*", SearchOption.AllDirectories)
.Where(p => p.FileExists())
.Select(p => new RawSourceFile(VFS.Lookup(p)) {Path = p.RelativeTo(MO2Folder)});
@ -274,20 +298,35 @@ namespace Wabbajack
private void ExportModlist()
{
var out_path = MO2Profile + ".modlist";
Utils.Log($"Exporting Modlist to : {ModListOutputFile}");
Utils.Log($"Exporting Modlist to : {out_path}");
ModList.ToJSON(Path.Combine(ModListOutputFolder, "modlist.json"));
using (var os = File.OpenWrite(out_path))
using (var bw = new BinaryWriter(os))
if (File.Exists(ModListOutputFile))
File.Delete(ModListOutputFile);
using (var fs = new FileStream(ModListOutputFile, FileMode.Create))
{
var formatter = new BinaryFormatter();
using (var compressed = LZ4Stream.Encode(bw.BaseStream,
new LZ4EncoderSettings { CompressionLevel = LZ4Level.L10_OPT }, true))
using (var za = new ZipArchive(fs, ZipArchiveMode.Create))
{
formatter.Serialize(compressed, ModList);
Directory.EnumerateFiles(ModListOutputFolder, "*.*")
.DoProgress("Compressing Modlist",
f =>
{
var ze = za.CreateEntry(Path.GetFileName(f));
using (var os = ze.Open())
using (var ins = File.OpenRead(f))
{
ins.CopyTo(os);
}
});
}
}
Utils.Log("Removing modlist staging folder");
Directory.Delete(ModListOutputFolder, true);
}
private void ShowReport()
@ -313,7 +352,7 @@ namespace Wabbajack
using (var fs = File.OpenWrite($"{ModList.Name}.md"))
{
fs.SetLength(0);
using (var reporter = new ReportBuilder(fs))
using (var reporter = new ReportBuilder(fs, ModListOutputFolder))
{
reporter.Build(ModList);
}
@ -342,7 +381,7 @@ namespace Wabbajack
{
Info("Gathering patch files");
var groups = InstallDirectives.OfType<PatchedFromArchive>()
.Where(p => p.Patch == null)
.Where(p => p.PatchID == null)
.GroupBy(p => p.ArchiveHashPath[0])
.ToList();
@ -350,7 +389,7 @@ namespace Wabbajack
var absolute_paths = AllFiles.ToDictionary(e => e.Path, e => e.AbsolutePath);
groups.PMap(group => BuildArchivePatches(group.Key, group, absolute_paths));
if (InstallDirectives.OfType<PatchedFromArchive>().FirstOrDefault(f => f.Patch == null) != null)
if (InstallDirectives.OfType<PatchedFromArchive>().FirstOrDefault(f => f.PatchID == null) != null)
Error("Missing patches after generation, this should not happen");
}
@ -372,8 +411,9 @@ namespace Wabbajack
var a = origin.ReadAll();
var b = LoadDataForTo(entry.To, absolute_paths);
Utils.CreatePatch(a, b, output);
entry.Patch = output.ToArray();
Info($"Patch size {entry.Patch.Length} for {entry.To}");
entry.PatchID = IncludeFile(output.ToArray());
var file_size = File.GetSize(Path.Combine(ModListOutputFolder, entry.PatchID));
Info($"Patch size {file_size} for {entry.To}");
}
});
}
@ -534,7 +574,7 @@ namespace Wabbajack
Info($"Checking link for {found.Name}");
var installer = new Installer(null, "");
var installer = new Installer("", null, "");
if (!installer.DownloadArchive(result, false))
Error(
@ -650,7 +690,7 @@ namespace Wabbajack
{
if (!Consts.ConfigFileExtensions.Contains(Path.GetExtension(source.Path))) return null;
var result = source.EvolveTo<InlineFile>();
result.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
result.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
return result;
};
}
@ -672,10 +712,12 @@ namespace Wabbajack
using (var ms = new MemoryStream())
{
Utils.CreatePatch(File.ReadAllBytes(game_file), File.ReadAllBytes(source.AbsolutePath), ms);
result.SourceData = ms.ToArray().ToBase64();
var data = ms.ToArray().ToBase64();
result.SourceDataID = IncludeFile(data);
Info($"Generated a {data.Length} byte patch for {filename}");
}
Info($"Generated a {result.SourceData.Length} byte patch for {filename}");
return result;
}
@ -693,7 +735,7 @@ namespace Wabbajack
if (source.Path.StartsWith(prefix))
{
var result = source.EvolveTo<InlineFile>();
result.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
result.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath).ToBase64());
return result;
}
@ -731,7 +773,7 @@ namespace Wabbajack
if (data == original_data)
return null;
var result = source.EvolveTo<RemappedInlineFile>();
result.SourceData = Encoding.UTF8.GetBytes(data).ToBase64();
result.SourceDataID = IncludeFile(Encoding.UTF8.GetBytes(data));
return result;
}
@ -778,7 +820,7 @@ namespace Wabbajack
if (source.Path.StartsWith(modpath))
{
var result = source.EvolveTo<InlineFile>();
result.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
result.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
return result;
}
@ -808,7 +850,7 @@ namespace Wabbajack
if (esp_size <= 250 && (File.Exists(bsa) || File.Exists(bsa_textures)))
{
var inline = source.EvolveTo<InlineFile>();
inline.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
inline.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
return inline;
}
}
@ -908,7 +950,7 @@ namespace Wabbajack
return source =>
{
var inline = source.EvolveTo<InlineFile>();
inline.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
inline.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
return inline;
};
}
@ -971,7 +1013,12 @@ namespace Wabbajack
e.ArchiveHashPath = found.MakeRelativePaths();
e.To = source.Path;
e.Hash = source.File.Hash;
Utils.TryGetPatch(found.Hash, source.File.Hash, out e.Patch);
Utils.TryGetPatch(found.Hash, source.File.Hash, out var data);
if (data != null)
e.PatchID = IncludeFile(data);
return e;
};
}
@ -983,7 +1030,7 @@ namespace Wabbajack
if (source.Path.StartsWith("mods\\") && source.Path.EndsWith("\\meta.ini"))
{
var e = source.EvolveTo<InlineFile>();
e.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
e.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
return e;
}
@ -1022,7 +1069,7 @@ namespace Wabbajack
data = File.ReadAllBytes(source.AbsolutePath);
var e = source.EvolveTo<InlineFile>();
e.SourceData = data.ToBase64();
e.SourceDataID = IncludeFile(data);
return e;
}
@ -1101,7 +1148,7 @@ namespace Wabbajack
if (regex.IsMatch(source.Path))
{
var result = source.EvolveTo<InlineFile>();
result.SourceData = File.ReadAllBytes(source.AbsolutePath).ToBase64();
result.SourceDataID = IncludeFile(File.ReadAllBytes(source.AbsolutePath));
return result;
}
@ -1162,32 +1209,6 @@ namespace Wabbajack
};
}
internal void PatchExecutable()
{
Utils.Log("Exporting Installer");
var settings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto};
var executable = Assembly.GetExecutingAssembly().Location;
var out_path = Path.Combine(Path.GetDirectoryName(executable), MO2Profile + ".exe");
Info($"Patching Executable {Path.GetFileName(out_path)}");
File.Copy(executable, out_path, true);
using (var os = File.OpenWrite(out_path))
using (var bw = new BinaryWriter(os))
{
var orig_pos = os.Length;
os.Position = os.Length;
var formatter = new BinaryFormatter();
using (var compressed = LZ4Stream.Encode(bw.BaseStream,
new LZ4EncoderSettings {CompressionLevel = LZ4Level.L10_OPT}, true))
{
formatter.Serialize(compressed, ModList);
}
bw.Write(orig_pos);
bw.Write(Encoding.ASCII.GetBytes(Consts.ModListMagic));
}
}
public class IndexedFileMatch
{
public IndexedArchive Archive;

View File

@ -88,7 +88,7 @@ namespace Wabbajack
/// <summary>
/// Data that will be written as-is to the destination location;
/// </summary>
public string SourceData;
public string SourceDataID;
}
[Serializable]
@ -150,7 +150,7 @@ namespace Wabbajack
/// <summary>
/// The file to apply to the source file to patch it
/// </summary>
public byte[] Patch;
public String PatchID;
}
[Serializable]
@ -165,7 +165,7 @@ namespace Wabbajack
{
public List<SourcePatch> Sources;
public string Hash;
public byte[] Patch;
public string PatchID;
}
[Serializable]

View File

@ -12,6 +12,7 @@ using System.Windows;
using CG.Web.MegaApiClient;
using Compression.BSA;
using K4os.Compression.LZ4.Streams;
using System.IO.Compression;
using VFS;
using Wabbajack.Common;
using Wabbajack.NexusApi;
@ -27,8 +28,9 @@ namespace Wabbajack
{
private string _downloadsFolder;
public Installer(ModList mod_list, string output_folder)
public Installer(string archive, ModList mod_list, string output_folder)
{
ModListArchive = archive;
Outputfolder = output_folder;
ModList = mod_list;
}
@ -43,6 +45,7 @@ namespace Wabbajack
set => _downloadsFolder = value;
}
public string ModListArchive { get; }
public ModList ModList { get; }
public Dictionary<string, string> HashedArchives { get; private set; }
@ -70,6 +73,31 @@ namespace Wabbajack
throw new Exception(msg);
}
private byte[] LoadBytesFromPath(string path)
{
using (var fs = new FileStream(ModListArchive, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var ar = new ZipArchive(fs,ZipArchiveMode.Read))
using (var ms = new MemoryStream())
{
var entry = ar.GetEntry(path);
using (var e = entry.Open())
e.CopyTo(ms);
return ms.ToArray();
}
}
public static ModList LoadFromFile(string path)
{
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
using (var ms = new MemoryStream())
{
var entry = ar.GetEntry("modlist.json");
using (var e = entry.Open())
return e.FromJSON<ModList>();
}
}
public void Install()
{
@ -268,7 +296,7 @@ namespace Wabbajack
else if (directive is CleanedESM)
GenerateCleanedESM((CleanedESM) directive);
else
File.WriteAllBytes(out_path, directive.SourceData.FromBase64());
File.WriteAllBytes(out_path, LoadBytesFromPath(directive.SourceDataID));
});
}
@ -284,7 +312,7 @@ namespace Wabbajack
throw new InvalidDataException(
$"Cannot patch {filename} from the game folder hashes don't match have you already cleaned the file?");
var patch_data = directive.SourceData.FromBase64();
var patch_data = LoadBytesFromPath(directive.SourceDataID);
var to_file = Path.Combine(Outputfolder, directive.To);
Status($"Patching {filename}");
using (var output = File.OpenWrite(to_file))
@ -295,7 +323,7 @@ namespace Wabbajack
private void WriteRemappedFile(RemappedInlineFile directive)
{
var data = Encoding.UTF8.GetString(directive.SourceData.FromBase64());
var data = Encoding.UTF8.GetString(LoadBytesFromPath(directive.SourceDataID));
data = data.Replace(Consts.GAME_PATH_MAGIC_BACK, GameFolder);
data = data.Replace(Consts.GAME_PATH_MAGIC_DOUBLE_BACK, GameFolder.Replace("\\", "\\\\"));
@ -377,7 +405,7 @@ namespace Wabbajack
Status($"Patching {Path.GetFileName(to_patch.To)}");
// Read in the patch data
var patch_data = to_patch.Patch;
var patch_data = LoadBytesFromPath(to_patch.PatchID);
var to_file = Path.Combine(Outputfolder, to_patch.To);
var old_data = new MemoryStream(File.ReadAllBytes(to_file));
@ -629,31 +657,5 @@ namespace Wabbajack
File.WriteAllText(cache, e.FileSHA256());
return HashArchive(e);
}
public static ModList LoadModlist(string file)
{
Utils.Log("Reading Modlist, this may take a moment");
try
{
using (var s = File.OpenRead(file))
{
using (var br = new BinaryReader(s))
{
using (var dc = LZ4Stream.Decode(br.BaseStream, leaveOpen: true))
{
IFormatter formatter = new BinaryFormatter();
var list = formatter.Deserialize(dc);
Utils.Log("Modlist loaded.");
return (ModList) list;
}
}
}
}
catch (Exception)
{
Utils.Log("Error Loading modlist");
return null;
}
}
}
}

View File

@ -54,7 +54,7 @@ namespace Wabbajack
else if (mode == RunMode.Install)
{
context.UIReady = false;
var modlist = Installer.LoadModlist(source);
var modlist = Installer.LoadFromFile(source);
if (modlist == null)
{
MessageBox.Show("Invalid Modlist, or file not found.", "Invalid Modlist", MessageBoxButton.OK,
@ -71,7 +71,7 @@ namespace Wabbajack
}
else
{
context.ConfigureForInstall(modlist);
context.ConfigureForInstall(source, modlist);
}
}

View File

@ -14,6 +14,7 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Wabbajack.Common;
using static Wabbajack.MainWindow;
namespace Wabbajack
@ -49,7 +50,7 @@ namespace Wabbajack
private void InstallModlist_Click(object sender, RoutedEventArgs e)
{
var file = UIUtils.OpenFileDialog("Wabbajack Modlist (*.modlist)|*.modlist");
var file = UIUtils.OpenFileDialog($"Wabbajack Modlist (*{Consts.ModlistExtension})|*{Consts.ModlistExtension}");
if (file != null)
{
ShutdownOnClose = false;

View File

@ -267,7 +267,19 @@ namespace Wabbajack.NexusApi
return Directory.EnumerateFiles(Consts.NexusCacheDirectory)
.Where(f => f.EndsWith(".json"))
.Select(f => f.FromJSON<ModInfo>())
.Select(f =>
{
try
{
return f.FromJSON<ModInfo>();
}
catch (Exception)
{
File.Delete(f);
return null;
}
})
.Where(m => m != null)
.Where(m => m._internal_version == CACHED_VERSION_NUMBER && m.picture_url != null)
.Select(m => new SlideShowItem
{

View File

@ -4,6 +4,8 @@ using System.IO;
using System.Linq;
using Wabbajack.Common;
using Wabbajack.NexusApi;
using File = Alphaleonis.Win32.Filesystem.File;
using Path = Alphaleonis.Win32.Filesystem.Path;
namespace Wabbajack
{
@ -11,9 +13,11 @@ namespace Wabbajack
{
private const int WRAP_SIZE = 80;
private readonly StreamWriter wtr;
private string _output_folder;
public ReportBuilder(Stream str)
public ReportBuilder(Stream str, string output_folder)
{
_output_folder = output_folder;
wtr = new StreamWriter(str);
}
@ -82,7 +86,7 @@ namespace Wabbajack
Text($"#### Summary of ({patched.Count}) patches");
foreach (var directive in patched)
NoWrapText(
$"* Applying {directive.Patch.Length} byte patch `{directive.FullPath}` to create `{directive.To}`");
$"* Applying {SizeForID(directive.PatchID)} byte patch `{directive.FullPath}` to create `{directive.To}`");
var files = lst.Directives.OrderBy(d => d.To).ToList();
@ -101,7 +105,7 @@ namespace Wabbajack
NoWrapText($"* `{i.To}` by remapping the contents of an inline file");
break;
case InlineFile i:
NoWrapText($"* `{i.To}` from `{i.SourceData.Length.ToFileSizeString()}` file included in modlist");
NoWrapText($"* `{i.To}` from `{SizeForID(i.SourceDataID).ToFileSizeString()}` file included in modlist");
break;
case CreateBSA i:
NoWrapText(
@ -110,20 +114,25 @@ namespace Wabbajack
}
var inlined = lst.Directives.OfType<InlineFile>()
.Select(f => (f.To, "inlined", f.SourceData.Length))
.Select(f => (f.To, "inlined", SizeForID(f.SourceDataID)))
.Concat(lst.Directives
.OfType<PatchedFromArchive>()
.Select(f => (f.To, "patched", f.Patch.Length)))
.Select(f => (f.To, "patched", SizeForID(f.PatchID))))
.ToHashSet()
.OrderByDescending(f => f.Length);
.OrderByDescending(f => f.Item3);
NoWrapText("\n\n### Summary of inlined files in this installer");
foreach (var inline in inlined)
{
NoWrapText($"* {inline.Length.ToFileSizeString()} for {inline.Item2} file {inline.To}");
NoWrapText($"* {inline.Item3.ToFileSizeString()} for {inline.Item2} file {inline.To}");
}
}
private long SizeForID(string id)
{
return File.GetSize(Path.Combine(_output_folder, id));
}
private IEnumerable<Archive> SortArchives(List<Archive> lstArchives)
{
var lst = lstArchives.OfType<NexusMod>().OrderBy(m => m.Author).ThenBy(m => m.Name);

View File

@ -48,12 +48,14 @@ namespace Wabbajack.Validation
using (var result = new StringReader(client.GetStringSync(Consts.ModPermissionsURL)))
{
AuthorPermissions = d.Deserialize<Dictionary<string, Author>>(result);
Utils.Log($"Loaded permissions for {AuthorPermissions.Count} authors");
}
Utils.Log("Loading Server Whitelist");
using (var result = new StringReader(client.GetStringSync(Consts.ServerWhitelistURL)))
{
ServerWhitelist = d.Deserialize<ServerWhitelist>(result);
Utils.Log($"Loaded permissions for {ServerWhitelist.AllowedPrefixes.Count} servers and {ServerWhitelist.GoogleIDs.Count} GDrive files");
}
}
@ -62,13 +64,17 @@ namespace Wabbajack.Validation
{
var validator = new ValidateModlist();
validator.LoadListsFromGithub();
Utils.Log("Running validation checks");
var errors = validator.Validate(modlist);
errors.Do(e => Utils.Log(e));
if (errors.Count() > 0)
{
Utils.Log($"{errors.Count()} validation errors found, cannot continue.");
throw new AccessViolationException();
throw new Exception($"{errors.Count()} validation errors found, cannot continue.");
}
else
{
Utils.Log("No Validation failures");
}
}
@ -134,7 +140,7 @@ namespace Wabbajack.Validation
if (nexus_mod_permissions.TryGetValue(p.ArchiveHashPath[0], out var archive))
{
if (!(archive.permissions.CanExtractBSAs ?? true) &&
p.ArchiveHashPath.Skip(1).Any(a => Consts.SupportedBSAs.Contains(Path.GetExtension(a))))
p.ArchiveHashPath.Skip(1).ButLast().Any(a => Consts.SupportedBSAs.Contains(Path.GetExtension(a))))
{
ValidationErrors.Push($"{p.To} from {archive.archive.NexusURL} is set to disallow BSA Extraction");
}

View File

@ -143,6 +143,7 @@
<Reference Include="System.Data" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference>

View File

@ -88,7 +88,7 @@ namespace Wabbajack
using (var ms = new MemoryStream())
{
Utils.CreatePatch(src_data, dst_data, ms);
result.Patch = ms.ToArray();
result.PatchID = compiler.IncludeFile(ms.ToArray());
}
return result;