mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Only 149 errors left in Wabbajack.Lib
This commit is contained in:
parent
035e376a09
commit
defbc15593
@ -53,10 +53,10 @@ namespace Compression.BSA
|
||||
}
|
||||
}
|
||||
|
||||
public void Build(string filename)
|
||||
public void Build(AbsolutePath filename)
|
||||
{
|
||||
SortEntries();
|
||||
using (var fs = File.Open(filename, FileMode.Create))
|
||||
using (var fs = filename.Create())
|
||||
using (var bw = new BinaryWriter(fs))
|
||||
{
|
||||
bw.Write(Encoding.ASCII.GetBytes(_state.HeaderMagic));
|
||||
|
@ -91,10 +91,10 @@ namespace Compression.BSA
|
||||
}
|
||||
}
|
||||
|
||||
public void Build(string outputName)
|
||||
public void Build(AbsolutePath outputName)
|
||||
{
|
||||
RegenFolderRecords();
|
||||
using (var fs = File.Open(outputName, FileMode.Create))
|
||||
using (var fs = outputName.Create())
|
||||
using (var wtr = new BinaryWriter(fs))
|
||||
{
|
||||
wtr.Write(_fileId);
|
||||
|
@ -18,7 +18,7 @@ namespace Compression.BSA
|
||||
public interface IBSABuilder : IDisposable
|
||||
{
|
||||
void AddFile(FileStateObject state, Stream src);
|
||||
void Build(string filename);
|
||||
void Build(AbsolutePath filename);
|
||||
}
|
||||
|
||||
public class ArchiveStateObject
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Wabbajack.Common;
|
||||
using File = Alphaleonis.Win32.Filesystem.File;
|
||||
|
||||
namespace Compression.BSA
|
||||
@ -22,9 +23,9 @@ namespace Compression.BSA
|
||||
_files[state.Index] = (cstate, src);
|
||||
}
|
||||
|
||||
public void Build(string filename)
|
||||
public void Build(AbsolutePath filename)
|
||||
{
|
||||
using var fs = File.Create(filename);
|
||||
using var fs = filename.Create();
|
||||
using var bw = new BinaryWriter(fs);
|
||||
|
||||
bw.Write(_state.VersionNumber);
|
||||
|
@ -12,10 +12,10 @@ namespace Wabbajack.Common
|
||||
{
|
||||
public static bool TestMode { get; set; } = false;
|
||||
|
||||
public static string GameFolderFilesDir = "Game Folder Files";
|
||||
public static string ManualGameFilesDir = "Manual Game Files";
|
||||
public static string LOOTFolderFilesDir = "LOOT Config Files";
|
||||
public static string BSACreationDir = "TEMP_BSA_FILES";
|
||||
public static RelativePath GameFolderFilesDir = (RelativePath)"Game Folder Files";
|
||||
public static RelativePath ManualGameFilesDir = (RelativePath)"Manual Game Files";
|
||||
public static RelativePath LOOTFolderFilesDir = (RelativePath)"LOOT Config Files";
|
||||
public static RelativePath BSACreationDir = (RelativePath)"TEMP_BSA_FILES";
|
||||
|
||||
public static string ModListDownloadFolder = "downloaded_mod_lists";
|
||||
|
||||
@ -109,7 +109,7 @@ namespace Wabbajack.Common
|
||||
public static string WabbajackCacheHostname = "build.wabbajack.org";
|
||||
public static int WabbajackCachePort = 80;
|
||||
public static int MaxHTTPRetries = 4;
|
||||
public const string MO2ModFolderName = "mods";
|
||||
public static RelativePath MO2ModFolderName = (RelativePath)"mods";
|
||||
|
||||
public static AbsolutePath PatchCacheFolder => LocalAppDataPath.Combine("patch_cache");
|
||||
public static int MaxConnectionsPerServer = 4;
|
||||
@ -119,8 +119,11 @@ namespace Wabbajack.Common
|
||||
public static AbsolutePath LogFile = LogsFolder.Combine(EntryPoint.FileNameWithoutExtension + ".current.log");
|
||||
public static int MaxOldLogs = 50;
|
||||
public static Extension BSA = new Extension(".BSA");
|
||||
public static Extension MOHIDDEN = new Extension(".mohidden");
|
||||
|
||||
public static AbsolutePath SettingsFile => LocalAppDataPath.Combine("settings.json");
|
||||
public static RelativePath SettingsIni = (RelativePath)"settings.ini";
|
||||
public static byte SettingsVersion => 1;
|
||||
public static RelativePath ModListTxt = (RelativePath)"modlist.txt";
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ namespace Wabbajack.Common
|
||||
if (MainExecutable == null)
|
||||
throw new NotImplementedException();
|
||||
|
||||
return FileVersionInfo.GetVersionInfo(Path.Combine(GameLocation(), MainExecutable)).ProductVersion;
|
||||
return FileVersionInfo.GetVersionInfo((string)GameLocation()?.Combine(MainExecutable)).ProductVersion;
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,9 +98,9 @@ namespace Wabbajack.Common
|
||||
|
||||
public string MainExecutable { get; internal set; }
|
||||
|
||||
public string GameLocation()
|
||||
public AbsolutePath? GameLocation()
|
||||
{
|
||||
return Consts.TestMode ? Directory.GetCurrentDirectory() : StoreHandler.Instance.GetGamePath(Game);
|
||||
return Consts.TestMode ? AbsolutePath.GetCurrentDirectory() : StoreHandler.Instance.GetGamePath(Game);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -212,9 +212,9 @@ namespace Wabbajack.Common
|
||||
}
|
||||
}
|
||||
|
||||
public bool InFolder(AbsolutePath gameFolder)
|
||||
public bool InFolder(AbsolutePath folder)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
return _path.StartsWith(folder._path + Path.DirectorySeparator);
|
||||
}
|
||||
|
||||
public async Task<byte[]> ReadAllBytesAsync()
|
||||
@ -295,6 +295,18 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return File.ReadAllBytes(_path);
|
||||
}
|
||||
|
||||
public static AbsolutePath GetCurrentDirectory()
|
||||
{
|
||||
return new AbsolutePath(Directory.GetCurrentDirectory());
|
||||
}
|
||||
|
||||
public async Task CopyToAsync(AbsolutePath destFile)
|
||||
{
|
||||
await using var src = OpenRead();
|
||||
await using var dest = destFile.Create();
|
||||
await src.CopyToAsync(dest);
|
||||
}
|
||||
}
|
||||
|
||||
public struct RelativePath : IPath, IEquatable<RelativePath>
|
||||
@ -367,6 +379,8 @@ namespace Wabbajack.Common
|
||||
|
||||
public RelativePath FileName => new RelativePath(Path.GetFileName(_path));
|
||||
|
||||
public RelativePath FileNameWithoutExtension => (RelativePath)Path.GetFileNameWithoutExtension(_path);
|
||||
|
||||
public bool Equals(RelativePath other)
|
||||
{
|
||||
return _path == other._path;
|
||||
@ -391,6 +405,16 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return _path.StartsWith(s);
|
||||
}
|
||||
|
||||
public bool StartsWith(RelativePath s)
|
||||
{
|
||||
return _path.StartsWith(s._path);
|
||||
}
|
||||
|
||||
public RelativePath Combine(params RelativePath[] paths )
|
||||
{
|
||||
return (RelativePath)Path.Combine(paths.Select(p => (string)p).Cons(_path).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class Utils
|
||||
@ -615,7 +639,7 @@ namespace Wabbajack.Common
|
||||
}
|
||||
}
|
||||
|
||||
public struct FullPath : IEquatable<FullPath>
|
||||
public struct FullPath : IEquatable<FullPath>, IPath
|
||||
{
|
||||
public AbsolutePath Base { get; }
|
||||
public RelativePath[] Paths { get; }
|
||||
@ -675,5 +699,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return obj is FullPath other && Equals(other);
|
||||
}
|
||||
|
||||
public RelativePath FileName => Paths.Length == 0 ? Base.FileName : Paths.Last().FileName;
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
public override Game Game { get; internal set; }
|
||||
public override string Name { get; internal set; }
|
||||
public override string Path { get; internal set; }
|
||||
public override AbsolutePath Path { get; internal set; }
|
||||
public override int ID { get; internal set; }
|
||||
public override StoreType Type { get; internal set; } = StoreType.GOG;
|
||||
}
|
||||
@ -101,7 +101,7 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
ID = gameID,
|
||||
Name = gameName,
|
||||
Path = path
|
||||
Path = (AbsolutePath)path
|
||||
};
|
||||
|
||||
var gameMeta = GameRegistry.Games.Values.FirstOrDefault(g => (g.GOGIDs?.Contains(gameID) ?? false));
|
||||
|
@ -12,7 +12,7 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
{
|
||||
public override Game Game { get; internal set; }
|
||||
public override string Name { get; internal set; }
|
||||
public override string Path { get; internal set; }
|
||||
public override AbsolutePath Path { get; internal set; }
|
||||
public override int ID { get; internal set; }
|
||||
public override StoreType Type { get; internal set; } = StoreType.STEAM;
|
||||
|
||||
@ -153,15 +153,15 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
|
||||
var path = Path.Combine(u, "common", GetVdfValue(l));
|
||||
if (Directory.Exists(path))
|
||||
game.Path = path;
|
||||
game.Path = (AbsolutePath)path;
|
||||
});
|
||||
|
||||
if (!gotID || !Directory.Exists(game.Path)) return;
|
||||
if (!gotID || !game.Path.IsDirectory) return;
|
||||
|
||||
var gameMeta = GameRegistry.Games.Values.FirstOrDefault(g =>
|
||||
{
|
||||
return (g.SteamIDs?.Contains(game.ID) ?? false)
|
||||
&& (g.RequiredFiles?.TrueForAll(file => File.Exists(Path.Combine(game.Path, file))) ?? true);
|
||||
&& (g.RequiredFiles?.TrueForAll(file => game.Path.Combine(file).Exists) ?? true);
|
||||
});
|
||||
|
||||
if (gameMeta == null)
|
||||
|
@ -52,27 +52,17 @@ namespace Wabbajack.Common.StoreHandlers
|
||||
}
|
||||
}
|
||||
|
||||
public string GetGamePath(Game game)
|
||||
public AbsolutePath? GetGamePath(Game game)
|
||||
{
|
||||
return StoreGames.FirstOrDefault(g => g.Game == game)?.Path;
|
||||
}
|
||||
|
||||
public string GetGamePath(Game game, StoreType type)
|
||||
{
|
||||
return StoreGames.FirstOrDefault(g => g.Type == type && g.Game == game)?.Path;
|
||||
}
|
||||
|
||||
public string GetGamePath(int id)
|
||||
{
|
||||
return StoreGames.FirstOrDefault(g => g.ID == id)?.Path;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AStoreGame
|
||||
{
|
||||
public abstract Game Game { get; internal set; }
|
||||
public abstract string Name { get; internal set; }
|
||||
public abstract string Path { get; internal set; }
|
||||
public abstract AbsolutePath Path { get; internal set; }
|
||||
public abstract int ID { get; internal set; }
|
||||
public abstract StoreType Type { get; internal set; }
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace Wabbajack.Lib
|
||||
public abstract class ACompiler : ABatchProcessor
|
||||
{
|
||||
public string ModListName, ModListAuthor, ModListDescription, ModListWebsite;
|
||||
public RelativePath ModListImage, ModListReadme;
|
||||
public AbsolutePath ModListImage, ModListReadme;
|
||||
public bool ReadmeIsWebsite;
|
||||
protected Version WabbajackVersion;
|
||||
|
||||
@ -91,10 +91,10 @@ namespace Wabbajack.Lib
|
||||
return id;
|
||||
}
|
||||
|
||||
internal RelativePath IncludeFile(AbsolutePath data)
|
||||
internal async Task<RelativePath> IncludeFile(AbsolutePath data)
|
||||
{
|
||||
var id = IncludeId();
|
||||
data.Copy(ModListOutputFolder.Combine(id));
|
||||
await data.CopyToAsync(ModListOutputFolder.Combine(id));
|
||||
return id;
|
||||
}
|
||||
|
||||
@ -124,57 +124,53 @@ namespace Wabbajack.Lib
|
||||
Utils.Log($"Exporting ModList to {ModListOutputFile}");
|
||||
|
||||
// Modify readme and ModList image to relative paths if they exist
|
||||
if (File.Exists(ModListImage))
|
||||
if (ModListImage.Exists)
|
||||
{
|
||||
ModList.Image = "modlist-image.png";
|
||||
ModList.Image = (RelativePath)"modlist-image.png";
|
||||
}
|
||||
if (File.Exists(ModListReadme))
|
||||
if (ModListReadme.Exists)
|
||||
{
|
||||
var readme = new FileInfo(ModListReadme);
|
||||
ModList.Readme = $"readme{readme.Extension}";
|
||||
ModList.Readme = $"readme{ModListReadme.Extension}";
|
||||
}
|
||||
|
||||
ModList.ReadmeIsWebsite = ReadmeIsWebsite;
|
||||
|
||||
using (var of = File.Create(Path.Combine(ModListOutputFolder, "modlist")))
|
||||
using (var of = ModListOutputFolder.Combine("modlist").Create())
|
||||
of.WriteAsMessagePack(ModList);
|
||||
|
||||
if (File.Exists(ModListOutputFile))
|
||||
File.Delete(ModListOutputFile);
|
||||
ModListOutputFile.Delete();
|
||||
|
||||
using (var fs = new FileStream(ModListOutputFile, FileMode.Create))
|
||||
using (var fs = ModListOutputFile.Create())
|
||||
{
|
||||
using (var za = new ZipArchive(fs, ZipArchiveMode.Create))
|
||||
{
|
||||
Directory.EnumerateFiles(ModListOutputFolder, "*.*")
|
||||
ModListOutputFolder.EnumerateFiles()
|
||||
.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);
|
||||
}
|
||||
var ze = za.CreateEntry((string)f.FileName);
|
||||
using var os = ze.Open();
|
||||
using var ins = f.OpenRead();
|
||||
ins.CopyTo(os);
|
||||
});
|
||||
|
||||
// Copy in modimage
|
||||
if (File.Exists(ModListImage))
|
||||
if (ModListImage.Exists)
|
||||
{
|
||||
var ze = za.CreateEntry(ModList.Image);
|
||||
var ze = za.CreateEntry((string)ModList.Image);
|
||||
using (var os = ze.Open())
|
||||
using (var ins = File.OpenRead(ModListImage))
|
||||
using (var ins = ModListImage.OpenRead())
|
||||
{
|
||||
ins.CopyTo(os);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy in readme
|
||||
if (File.Exists(ModListReadme))
|
||||
if (ModListReadme.Exists)
|
||||
{
|
||||
var ze = za.CreateEntry(ModList.Readme);
|
||||
using (var os = ze.Open())
|
||||
using (var ins = File.OpenRead(ModListReadme))
|
||||
using (var ins = ModListReadme.OpenRead())
|
||||
{
|
||||
ins.CopyTo(os);
|
||||
}
|
||||
@ -185,7 +181,7 @@ namespace Wabbajack.Lib
|
||||
Utils.Log("Exporting ModList metadata");
|
||||
var metadata = new DownloadMetadata
|
||||
{
|
||||
Size = File.GetSize(ModListOutputFile),
|
||||
Size = ModListOutputFile.Size,
|
||||
Hash = ModListOutputFile.FileHash(),
|
||||
NumberOfArchives = ModList.Archives.Count,
|
||||
SizeOfArchives = ModList.Archives.Sum(a => a.Size),
|
||||
@ -210,7 +206,7 @@ namespace Wabbajack.Lib
|
||||
Info("Building a list of archives based on the files required");
|
||||
|
||||
var hashes = InstallDirectives.OfType<FromArchive>()
|
||||
.Select(a => Hash.FromBase64(a.ArchiveHashPath[0]))
|
||||
.Select(a => a.Hash)
|
||||
.Distinct();
|
||||
|
||||
var archives = IndexedArchives.OrderByDescending(f => f.File.LastModified)
|
||||
|
@ -56,17 +56,18 @@ namespace Wabbajack.Lib
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
public byte[] LoadBytesFromPath(string path)
|
||||
public async Task<byte[]> LoadBytesFromPath(RelativePath 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())
|
||||
await using var fs = new FileStream(ModListArchive, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
using var ar = new ZipArchive(fs, ZipArchiveMode.Read);
|
||||
await using var ms = new MemoryStream();
|
||||
var entry = ar.GetEntry((string)path);
|
||||
await using (var e = entry.Open())
|
||||
{
|
||||
var entry = ar.GetEntry(path);
|
||||
using (var e = entry.Open())
|
||||
e.CopyTo(ms);
|
||||
return ms.ToArray();
|
||||
await e.CopyToAsync(ms);
|
||||
}
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static ModList LoadFromFile(string path)
|
||||
@ -190,7 +191,7 @@ namespace Wabbajack.Lib
|
||||
Status($"Patching {toPatch.To.FileName}");
|
||||
// Read in the patch data
|
||||
|
||||
byte[] patchData = LoadBytesFromPath(toPatch.PatchID);
|
||||
byte[] patchData = await LoadBytesFromPath(toPatch.PatchID);
|
||||
|
||||
var toFile = OutputFolder.Combine(toPatch.To);
|
||||
var oldData = new MemoryStream(await toFile.ReadAllBytesAsync());
|
||||
|
@ -12,7 +12,7 @@ namespace Wabbajack.Lib.CompilationSteps.CompilationErrors
|
||||
public class InvalidGameESMError : AErrorMessage
|
||||
{
|
||||
public Hash Hash { get; }
|
||||
public string PathToFile { get; }
|
||||
public AbsolutePath PathToFile { get; }
|
||||
private readonly CleanedESM _esm;
|
||||
public RelativePath GameFileName => _esm.To.FileName;
|
||||
public override string ShortDescription
|
||||
@ -30,7 +30,7 @@ the modlist expecting a different of the game than you currently have installed,
|
||||
the game, and then attempting to re-install this modlist. Also verify that the version of the game you have installed matches the version expected by this modlist.";
|
||||
}
|
||||
|
||||
public InvalidGameESMError(CleanedESM esm, Hash hash, string path)
|
||||
public InvalidGameESMError(CleanedESM esm, Hash hash, AbsolutePath path)
|
||||
{
|
||||
Hash = hash;
|
||||
PathToFile = path;
|
||||
|
@ -53,10 +53,10 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!Consts.SupportedBSAs.Contains(Path.GetExtension(source.Path).ToLower())) return null;
|
||||
if (!Consts.SupportedBSAs.Contains(source.Path.Extension)) return null;
|
||||
|
||||
var defaultInclude = false;
|
||||
if (source.Path.StartsWith(Consts.MO2ModFolderName))
|
||||
if (source.Path.RelativeTo(_mo2Compiler.MO2Folder).InFolder(_mo2Compiler.MO2Folder.Combine(Consts.MO2ModFolderName)))
|
||||
if (_includeDirectly.Any(path => source.Path.StartsWith(path)))
|
||||
defaultInclude = true;
|
||||
|
||||
@ -66,7 +66,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
var id = Guid.NewGuid().ToString();
|
||||
|
||||
var matches = await sourceFiles.PMap(_mo2Compiler.Queue, e => _mo2Compiler.RunStack(stack, new RawSourceFile(e, Path.Combine(Consts.BSACreationDir, id, e.Name))));
|
||||
var matches = await sourceFiles.PMap(_mo2Compiler.Queue, e => _mo2Compiler.RunStack(stack, new RawSourceFile(e, Consts.BSACreationDir.Combine((RelativePath)id, e.Name.FileName))));
|
||||
|
||||
|
||||
foreach (var match in matches)
|
||||
@ -82,7 +82,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
directive = new CreateBSA
|
||||
{
|
||||
To = source.Path,
|
||||
TempID = id,
|
||||
TempID = (RelativePath)id,
|
||||
State = bsa.State,
|
||||
FileStates = bsa.Files.Select(f => f.State).ToList()
|
||||
};
|
||||
|
@ -22,7 +22,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
.Where(line => line.StartsWith("+") || line.EndsWith("_separator"))
|
||||
.Select(line => line.Substring(1))
|
||||
.Concat(alwaysEnabled)
|
||||
.Select(line => Path.Combine(Consts.MO2ModFolderName, line) + "\\")
|
||||
.Select(line => Path.Combine((string)Consts.MO2ModFolderName, line) + "\\")
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
@ -11,40 +11,41 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
public class IncludePatches : ACompilationStep
|
||||
{
|
||||
private readonly Dictionary<string, IGrouping<string, VirtualFile>> _indexed;
|
||||
private readonly Dictionary<RelativePath, IGrouping<RelativePath, VirtualFile>> _indexed;
|
||||
private VirtualFile _bsa;
|
||||
private Dictionary<string, VirtualFile> _indexedByName;
|
||||
private Dictionary<RelativePath, VirtualFile> _indexedByName;
|
||||
|
||||
public IncludePatches(ACompiler compiler, VirtualFile constructingFromBSA = null) : base(compiler)
|
||||
{
|
||||
_bsa = constructingFromBSA;
|
||||
_indexed = _compiler.IndexedFiles.Values
|
||||
.SelectMany(f => f)
|
||||
.GroupBy(f => Path.GetFileName(f.Name).ToLower())
|
||||
.GroupBy(f => f.Name.FileName)
|
||||
.ToDictionary(f => f.Key);
|
||||
_indexedByName = _indexed.Values
|
||||
.SelectMany(s => s)
|
||||
.Where(f => f.IsNative)
|
||||
.ToDictionary(f => Path.GetFileName(f.FullPath));
|
||||
.ToDictionary(f => f.FullPath.FileName);
|
||||
}
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
var name = Path.GetFileName(source.File.Name.ToLower());
|
||||
string nameWithoutExt = name;
|
||||
if (Path.GetExtension(name) == ".mohidden")
|
||||
nameWithoutExt = Path.GetFileNameWithoutExtension(name);
|
||||
|
||||
var name = source.File.Name.FileName;
|
||||
RelativePath nameWithoutExt = name;
|
||||
if (name.Extension == Consts.MOHIDDEN)
|
||||
nameWithoutExt = name.FileNameWithoutExtension;
|
||||
|
||||
if (!_indexed.TryGetValue(Path.GetFileName(name), out var choices))
|
||||
_indexed.TryGetValue(Path.GetFileName(nameWithoutExt), out choices);
|
||||
if (!_indexed.TryGetValue(name, out var choices))
|
||||
_indexed.TryGetValue(nameWithoutExt, out choices);
|
||||
|
||||
dynamic mod_ini;
|
||||
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 bsa_path = _bsa.FullPath.Paths.Last().RelativeTo(((MO2Compiler)_compiler).MO2Folder);
|
||||
mod_ini = ((MO2Compiler)_compiler).ModMetas.FirstOrDefault(f => ((string)bsa_path).StartsWith(f.Key)).Value;
|
||||
}
|
||||
|
||||
var installationFile = mod_ini?.General?.installationFile;
|
||||
@ -55,7 +56,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
if (choices != null)
|
||||
{
|
||||
found = choices.FirstOrDefault(
|
||||
f => Path.GetFileName(f.FilesInFullPath.First().Name) == installationFile);
|
||||
f => f.FilesInFullPath.First().Name.FileName == installationFile);
|
||||
}
|
||||
|
||||
// Find based on file name only (not ext)
|
||||
@ -67,11 +68,10 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
}
|
||||
|
||||
// Find based on matchAll=<archivename> in [General] in meta.ini
|
||||
var matchAllName = (string)mod_ini?.General?.matchAll;
|
||||
var matchAllName = (RelativePath?)mod_ini?.General?.matchAll;
|
||||
if (matchAllName != null)
|
||||
{
|
||||
matchAllName = matchAllName.Trim();
|
||||
if (_indexedByName.TryGetValue(matchAllName, out var arch))
|
||||
if (_indexedByName.TryGetValue(matchAllName.Value, out var arch))
|
||||
{
|
||||
// Just match some file in the archive based on the smallest delta difference
|
||||
found = arch.ThisAndAllChildren
|
||||
@ -92,7 +92,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
Utils.TryGetPatch(found.Hash, source.File.Hash, out var data);
|
||||
|
||||
if (data != null)
|
||||
e.PatchID = _compiler.IncludeFile(data);
|
||||
e.PatchID = await _compiler.IncludeFile(data);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
@ -25,16 +25,16 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
var isBanner = source.AbsolutePath == _compiler.ModListImage;
|
||||
//var isReadme = source.AbsolutePath == ModListReadme;
|
||||
var result = source.EvolveTo<PropertyFile>();
|
||||
result.SourceDataID = await _compiler.IncludeFile(source.AbsolutePath.ReadAllBytesAsync());
|
||||
result.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
if (isBanner)
|
||||
{
|
||||
result.Type = PropertyType.Banner;
|
||||
_compiler.ModListImage = result.SourceDataID;
|
||||
_compiler.ModListImage = result.SourceDataID.RelativeTo(_compiler.ModListOutputFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Type = PropertyType.Readme;
|
||||
_compiler.ModListReadme = result.SourceDataID;
|
||||
_compiler.ModListReadme = result.SourceDataID.RelativeTo(_compiler.ModListOutputFolder);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -20,12 +20,12 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!_regex.IsMatch(source.Path))
|
||||
if (!_regex.IsMatch((string)source.Path))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var lines = File.ReadAllLines(source.AbsolutePath);
|
||||
var lines = await source.AbsolutePath.ReadAllLinesAsync();
|
||||
var id = 0;
|
||||
lines.Where(l => l.StartsWith("itemID=")).Do(l => int.TryParse(l.Replace("itemID=", ""), out id));
|
||||
if (id == 0)
|
||||
@ -37,7 +37,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
return null;
|
||||
|
||||
var fromSteam = source.EvolveTo<SteamMeta>();
|
||||
fromSteam.SourceDataID = _compiler.IncludeFile(source.AbsolutePath);
|
||||
fromSteam.SourceDataID = await _compiler.IncludeFile(source.AbsolutePath);
|
||||
fromSteam.ItemID = item.ItemID;
|
||||
fromSteam.Size = item.Size;
|
||||
return fromSteam;
|
||||
|
@ -46,7 +46,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
if (data == originalData)
|
||||
return null;
|
||||
var result = source.EvolveTo<RemappedInlineFile>();
|
||||
result.SourceDataID = _compiler.IncludeFile(Encoding.UTF8.GetBytes(data));
|
||||
result.SourceDataID = await _compiler.IncludeFile(Encoding.UTF8.GetBytes(data));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
if (!source.Path.StartsWith(modpath)) continue;
|
||||
var result = source.EvolveTo<InlineFile>();
|
||||
result.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
result.SourceDataID = await _compiler.IncludeFile(source.AbsolutePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
@ -22,12 +23,12 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
if (_correctProfiles.Any(p => source.Path.StartsWith(p)))
|
||||
{
|
||||
var data = source.Path.EndsWith("\\modlist.txt")
|
||||
? ReadAndCleanModlist(source.AbsolutePath)
|
||||
: File.ReadAllBytes(source.AbsolutePath);
|
||||
var data = source.Path.FileName == Consts.ModListTxt
|
||||
? await ReadAndCleanModlist(source.AbsolutePath)
|
||||
: await source.AbsolutePath.ReadAllBytesAsync();
|
||||
|
||||
var e = source.EvolveTo<InlineFile>();
|
||||
e.SourceDataID = _compiler.IncludeFile(data);
|
||||
e.SourceDataID = await _compiler.IncludeFile(data);
|
||||
return e;
|
||||
}
|
||||
|
||||
@ -39,12 +40,11 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
return new State();
|
||||
}
|
||||
|
||||
private static byte[] ReadAndCleanModlist(string absolutePath)
|
||||
private static async Task<byte[]> ReadAndCleanModlist(AbsolutePath absolutePath)
|
||||
{
|
||||
var lines = File.ReadAllLines(absolutePath);
|
||||
lines = (from line in lines
|
||||
where !(line.StartsWith("-") && !line.EndsWith("_separator"))
|
||||
select line).ToArray();
|
||||
var lines = await absolutePath.ReadAllLinesAsync();
|
||||
lines = lines.Where(line => !(line.StartsWith("-") && !line.EndsWith("_separator")))
|
||||
.ToArray();
|
||||
return Encoding.UTF8.GetBytes(string.Join("\r\n", lines));
|
||||
}
|
||||
|
||||
|
@ -14,22 +14,24 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
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 => source.Path.Contains(a))) return null;
|
||||
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 (!source.Path.Contains("vortex.deployment.json"))
|
||||
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;
|
||||
|
||||
path = path.Substring(Consts.GameFolderFilesDir.Length + 1);
|
||||
path = $"{Consts.ManualGameFilesDir}\\{path}";
|
||||
inline.To = path;
|
||||
|
||||
return inline;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IState GetState()
|
||||
|
@ -73,7 +73,7 @@ namespace Wabbajack.Lib
|
||||
/// Hash of the banner-image
|
||||
/// </summary>
|
||||
[Key(5)]
|
||||
public string Image;
|
||||
public RelativePath Image;
|
||||
|
||||
/// <summary>
|
||||
/// The Mod Manager used to create the modlist
|
||||
@ -229,7 +229,7 @@ namespace Wabbajack.Lib
|
||||
public class CreateBSA : Directive
|
||||
{
|
||||
[Key(3)]
|
||||
public string TempID { get; set; }
|
||||
public RelativePath TempID { get; set; }
|
||||
[Key(4)]
|
||||
public ArchiveStateObject State { get; set; }
|
||||
[Key(5)]
|
||||
@ -246,7 +246,7 @@ namespace Wabbajack.Lib
|
||||
/// The file to apply to the source file to patch it
|
||||
/// </summary>
|
||||
[Key(5)]
|
||||
public string PatchID { get; set; }
|
||||
public RelativePath PatchID { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
@ -262,7 +262,7 @@ namespace Wabbajack.Lib
|
||||
public class MergedPatch : Directive
|
||||
{
|
||||
[Key(3)]
|
||||
public string PatchID { get; set; }
|
||||
public RelativePath PatchID { get; set; }
|
||||
[Key(4)]
|
||||
public List<SourcePatch> Sources { get; set; }
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using MessagePack;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.Validation;
|
||||
|
||||
namespace Wabbajack.Lib.Downloaders
|
||||
@ -96,15 +97,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
/// Downloads this file to the given destination location
|
||||
/// </summary>
|
||||
/// <param name="destination"></param>
|
||||
public abstract Task<bool> Download(Archive a, string destination);
|
||||
public abstract Task<bool> Download(Archive a, AbsolutePath destination);
|
||||
|
||||
public async Task<bool> Download(string destination)
|
||||
public async Task<bool> Download(AbsolutePath destination)
|
||||
{
|
||||
var path = Path.GetDirectoryName(destination);
|
||||
if (!string.IsNullOrEmpty(path) && !Directory.Exists(path))
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
return await Download(new Archive {Name = Path.GetFileName(destination)}, destination);
|
||||
destination.Parent.CreateDirectory();
|
||||
return await Download(new Archive {Name = (string)destination.FileName}, destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -91,12 +91,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
await using var stream = await ResolveDownloadStream();
|
||||
await using (var file = File.Open(destination, FileMode.Create))
|
||||
await using (var file = destination.Create())
|
||||
{
|
||||
stream.CopyTo(file);
|
||||
await stream.CopyToAsync(file);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
public static async Task<BethesdaNetData> Login(Game game)
|
||||
{
|
||||
var metadata = game.MetaData();
|
||||
var gamePath = Path.Combine(metadata.GameLocation(), metadata.MainExecutable);
|
||||
var gamePath = metadata.GameLocation()?.Combine(metadata.MainExecutable);
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
FileName = @"Downloaders\BethesdaNet\bethnetlogin.exe",
|
||||
@ -125,7 +125,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var (client, info, collected) = await ResolveDownloadInfo();
|
||||
using var tf = new TempFile();
|
||||
@ -151,16 +151,16 @@ namespace Wabbajack.Lib.Downloaders
|
||||
}
|
||||
}
|
||||
file.Close();
|
||||
await ConvertCKMToZip(file.Name, destination);
|
||||
await ConvertCKMToZip((AbsolutePath)file.Name, destination);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private const uint CKM_Magic = 0x52415442; // BTAR
|
||||
private async Task ConvertCKMToZip(string src, string dest)
|
||||
private async Task ConvertCKMToZip(AbsolutePath src, AbsolutePath dest)
|
||||
{
|
||||
using var reader = new BinaryReader(File.OpenRead(src));
|
||||
using var reader = new BinaryReader(src.OpenRead());
|
||||
var magic = reader.ReadUInt32();
|
||||
if (magic != CKM_Magic)
|
||||
throw new InvalidDataException("Invalid magic format in CKM parsing");
|
||||
@ -173,7 +173,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
if (minorVersion < 2 || minorVersion > 4)
|
||||
throw new InvalidDataException("Archive minor version is unknown. Should be 2, 3, or 4.");
|
||||
|
||||
await using var fos = File.Create(dest);
|
||||
await using var fos = dest.Create();
|
||||
using var archive = new ZipArchive(fos, ZipArchiveMode.Create);
|
||||
while (reader.PeekChar() != -1)
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
.Do(t => Downloaders.First(d => d.GetType() == t).Prepare());
|
||||
}
|
||||
|
||||
public static async Task<bool> DownloadWithPossibleUpgrade(Archive archive, string destination)
|
||||
public static async Task<bool> DownloadWithPossibleUpgrade(Archive archive, AbsolutePath destination)
|
||||
{
|
||||
var success = await Download(archive, destination);
|
||||
if (success)
|
||||
@ -104,12 +104,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
}
|
||||
|
||||
Utils.Log($"Upgrading {archive.Hash}");
|
||||
var upgradePath = Path.Combine(Path.GetDirectoryName(destination), "_Upgrade_" + archive.Name);
|
||||
var upgradePath = destination.Parent.Combine("_Upgrade_" + archive.Name);
|
||||
var upgradeResult = await Download(upgrade, upgradePath);
|
||||
if (!upgradeResult) return false;
|
||||
|
||||
var patchName = $"{archive.Hash.ToHex()}_{upgrade.Hash.ToHex()}";
|
||||
var patchPath = Path.Combine(Path.GetDirectoryName(destination), "_Patch_" + patchName);
|
||||
var patchPath = destination.Parent.Combine("_Patch_" + patchName);
|
||||
|
||||
var patchState = new Archive
|
||||
{
|
||||
@ -124,9 +124,9 @@ namespace Wabbajack.Lib.Downloaders
|
||||
if (!patchResult) return false;
|
||||
|
||||
Utils.Status($"Applying Upgrade to {archive.Hash}");
|
||||
await using (var patchStream = File.OpenRead(patchPath))
|
||||
await using (var srcStream = File.OpenRead(upgradePath))
|
||||
await using (var destStream = File.Create(destination))
|
||||
await using (var patchStream = patchPath.OpenRead())
|
||||
await using (var srcStream = upgradePath.OpenRead())
|
||||
await using (var destStream = destination.Create())
|
||||
{
|
||||
OctoDiff.Apply(srcStream, patchStream, destStream);
|
||||
}
|
||||
@ -136,7 +136,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> Download(Archive archive, string destination)
|
||||
private static async Task<bool> Download(Archive archive, AbsolutePath destination)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -25,12 +25,14 @@ namespace Wabbajack.Lib.Downloaders
|
||||
if (game == null) return null;
|
||||
|
||||
var path = game.GameLocation();
|
||||
var filePath = Path.Combine(path, gameFile);
|
||||
var filePath = path?.Combine(gameFile);
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
|
||||
if (!filePath?.Exists ?? false)
|
||||
return null;
|
||||
|
||||
var hash = filePath.FileHashCached();
|
||||
var fp = filePath.Value;
|
||||
var hash = await fp.FileHashCachedAsync();
|
||||
|
||||
return new State
|
||||
{
|
||||
@ -53,7 +55,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
public string GameVersion { get; set; }
|
||||
|
||||
internal string SourcePath => Path.Combine(Game.MetaData().GameLocation(), GameFile);
|
||||
internal AbsolutePath SourcePath => Game.MetaData().GameLocation().Value.Combine(GameFile);
|
||||
|
||||
public override object[] PrimaryKey { get => new object[] {Game, GameVersion, GameFile}; }
|
||||
|
||||
@ -62,12 +64,12 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
using(var src = File.OpenRead(SourcePath))
|
||||
using (var dest = File.Open(destination, System.IO.FileMode.Create))
|
||||
using(var src = SourcePath.OpenRead())
|
||||
using (var dest = destination.Create())
|
||||
{
|
||||
var size = new FileInfo(SourcePath).Length;
|
||||
var size = SourcePath.Size;
|
||||
src.CopyToWithStatus(size, dest, "Copying from Game folder");
|
||||
}
|
||||
return true;
|
||||
@ -75,7 +77,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
public override async Task<bool> Verify(Archive a)
|
||||
{
|
||||
return File.Exists(SourcePath) && SourcePath.FileHashCached() == Hash;
|
||||
return SourcePath.Exists && await SourcePath.FileHashCachedAsync() == Hash;
|
||||
}
|
||||
|
||||
public override IDownloader GetDownloader()
|
||||
|
@ -44,7 +44,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return whitelist.GoogleIDs.Contains(Id);
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var state = await ToHttpState();
|
||||
return await state.Download(a, destination);
|
||||
|
@ -64,21 +64,19 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return whitelist.AllowedPrefixes.Any(p => Url.StartsWith(p));
|
||||
}
|
||||
|
||||
public override Task<bool> Download(Archive a, string destination)
|
||||
public override Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
return DoDownload(a, destination, true);
|
||||
}
|
||||
|
||||
public async Task<bool> DoDownload(Archive a, string destination, bool download)
|
||||
public async Task<bool> DoDownload(Archive a, AbsolutePath destination, bool download)
|
||||
{
|
||||
if (download)
|
||||
{
|
||||
var parent = Directory.GetParent(destination);
|
||||
if (!Directory.Exists(parent.FullName))
|
||||
Directory.CreateDirectory(parent.FullName);
|
||||
destination.Parent.CreateDirectory();
|
||||
}
|
||||
|
||||
using (var fs = download ? File.Open(destination, FileMode.Create) : null)
|
||||
using (var fs = download ? destination.Create() : null)
|
||||
{
|
||||
var client = Client ?? new Common.Http.Client();
|
||||
client.Headers.Add(("User-Agent", Consts.UserAgent));
|
||||
@ -186,7 +184,7 @@ TOP:
|
||||
|
||||
public override async Task<bool> Verify(Archive a)
|
||||
{
|
||||
return await DoDownload(a, "", false);
|
||||
return await DoDownload(a, ((RelativePath)"").RelativeToEntryPoint(), false);
|
||||
}
|
||||
|
||||
public override IDownloader GetDownloader()
|
||||
|
@ -26,7 +26,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
public class State : HTTPDownloader.State
|
||||
{
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var client = new MegaApiClient();
|
||||
Utils.Status("Logging into MEGA (as anonymous)");
|
||||
@ -34,7 +34,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
var fileLink = new Uri(Url);
|
||||
var node = client.GetNodeFromLink(fileLink);
|
||||
Utils.Status($"Downloading MEGA file: {a.Name}");
|
||||
client.DownloadFile(fileLink, destination);
|
||||
client.DownloadFile(fileLink, (string)destination);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var (uri, client) = await Utils.Log(await ManuallyDownloadFile.Create(this)).Task;
|
||||
var state = new HTTPDownloader.State {Url = uri.ToString(), Client = client};
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.Validation;
|
||||
using Wabbajack.Lib.WebAutomation;
|
||||
|
||||
@ -31,7 +32,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return whitelist.AllowedPrefixes.Any(p => Url.StartsWith(p));
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var result = await Resolve();
|
||||
return await result.Download(a, destination);
|
||||
|
@ -46,7 +46,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var urls = await GetDownloadUrls();
|
||||
Utils.Log($"Found {urls.Length} ModDB mirrors for {a.Name}");
|
||||
|
@ -152,7 +152,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
string url;
|
||||
try
|
||||
|
@ -49,7 +49,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
var currentLib = Item.Game.Universe;
|
||||
|
||||
|
@ -82,13 +82,13 @@ namespace Wabbajack.Lib.Downloaders
|
||||
return true;
|
||||
}
|
||||
|
||||
public override async Task<bool> Download(Archive a, string destination)
|
||||
public override async Task<bool> Download(Archive a, AbsolutePath destination)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var queue = new WorkQueue();
|
||||
using var folder = new TempFolder();
|
||||
Directory.CreateDirectory(Path.Combine(folder.Dir.FullName, "tracks"));
|
||||
folder.Dir.Combine("tracks").CreateDirectory();
|
||||
var client = new YoutubeClient(Common.Http.ClientFactory.Client);
|
||||
var meta = await client.GetVideoAsync(Key);
|
||||
var video = await client.GetVideoMediaStreamInfosAsync(Key);
|
||||
@ -96,17 +96,17 @@ namespace Wabbajack.Lib.Downloaders
|
||||
var stream = video.GetAll().OfType<AudioStreamInfo>().Where(f => f.AudioEncoding == AudioEncoding.Aac).OrderByDescending(a => a.Bitrate)
|
||||
.ToArray().First();
|
||||
|
||||
var initialDownload = Path.Combine(folder.Dir.FullName, "initial_download");
|
||||
var initialDownload = folder.Dir.Combine("initial_download");
|
||||
|
||||
var trackFolder = Path.Combine(folder.Dir.FullName, "tracks");
|
||||
var trackFolder = folder.Dir.Combine("tracks");
|
||||
|
||||
await using (var fs = File.Create(initialDownload))
|
||||
await using (var fs = initialDownload.Create())
|
||||
{
|
||||
await client.DownloadMediaStreamAsync(stream, fs, new Progress($"Downloading {a.Name}"),
|
||||
CancellationToken.None);
|
||||
}
|
||||
|
||||
File.Copy(initialDownload, @$"c:\tmp\{Path.GetFileName(destination)}.dest_stream");
|
||||
initialDownload.CopyTo(destination.WithExtension(new Extension(".dest_stream")));
|
||||
|
||||
await Tracks.PMap(queue, async track =>
|
||||
{
|
||||
@ -114,15 +114,15 @@ namespace Wabbajack.Lib.Downloaders
|
||||
await ExtractTrack(initialDownload, trackFolder, track);
|
||||
});
|
||||
|
||||
await using var dest = File.Create(destination);
|
||||
await using var dest = destination.Create();
|
||||
using var ar = new ZipArchive(dest, ZipArchiveMode.Create);
|
||||
foreach (var track in Directory.EnumerateFiles(trackFolder).OrderBy(e => e))
|
||||
foreach (var track in trackFolder.EnumerateFiles().OrderBy(e => e))
|
||||
{
|
||||
Utils.Status($"Adding {Path.GetFileName(track)} to archive");
|
||||
var entry = ar.CreateEntry(Path.Combine("Data", "tracks", track.RelativeTo(trackFolder)), CompressionLevel.NoCompression);
|
||||
Utils.Status($"Adding {track.FileName} to archive");
|
||||
var entry = ar.CreateEntry(Path.Combine("Data", "tracks", (string)track.RelativeTo(trackFolder)), CompressionLevel.NoCompression);
|
||||
entry.LastWriteTime = meta.UploadDate;
|
||||
await using var es = entry.Open();
|
||||
await using var ins = File.OpenRead(track);
|
||||
await using var ins = track.OpenRead();
|
||||
await ins.CopyToAsync(es);
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ namespace Wabbajack.Lib.Downloaders
|
||||
|
||||
private const string FFMpegPath = "Downloaders/Converters/ffmpeg.exe";
|
||||
private const string xWMAEncodePath = "Downloaders/Converters/xWMAEncode.exe";
|
||||
private async Task ExtractTrack(string source, string dest_folder, Track track)
|
||||
private async Task ExtractTrack(AbsolutePath source, AbsolutePath dest_folder, Track track)
|
||||
{
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
|
@ -21,31 +21,25 @@ namespace Wabbajack.Lib.FileUploader
|
||||
{
|
||||
public static IObservable<bool> HaveAuthorAPIKey => Utils.HaveEncryptedJsonObservable("author-api-key.txt");
|
||||
|
||||
public static IObservable<string> AuthorAPIKey => HaveAuthorAPIKey.Where(h => h)
|
||||
.Select(_ => File.ReadAllText(Path.Combine(Consts.LocalAppDataPath, "author-api-key.txt")));
|
||||
|
||||
|
||||
public static string GetAPIKey()
|
||||
public static async Task<string> GetAPIKey()
|
||||
{
|
||||
return File.ReadAllText(Path.Combine(Consts.LocalAppDataPath, "author-api-key.txt")).Trim();
|
||||
return (await Consts.LocalAppDataPath.Combine("author-api-key.txt").ReadAllTextAsync()).Trim();
|
||||
}
|
||||
public static bool HasAPIKey => File.Exists(Path.Combine(Consts.LocalAppDataPath, "author-api-key.txt"));
|
||||
|
||||
|
||||
public static readonly Uri UploadURL = new Uri("https://build.wabbajack.org/upload_file");
|
||||
public static long BLOCK_SIZE = (long)1024 * 1024 * 2;
|
||||
public static int MAX_CONNECTIONS = 8;
|
||||
public static Task<string> UploadFile(WorkQueue queue, string filename, Action<double> progressFn)
|
||||
public static Task<string> UploadFile(WorkQueue queue, AbsolutePath filename, Action<double> progressFn)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<string>();
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var client = GetAuthorizedClient();
|
||||
|
||||
var fsize = new FileInfo(filename).Length;
|
||||
var fsize = filename.Size;
|
||||
var hash_task = filename.FileHashAsync();
|
||||
|
||||
var response = await client.PutAsync(UploadURL+$"/{Path.GetFileName(filename)}/start", new StringContent(""));
|
||||
var response = await client.PutAsync(UploadURL+$"/{filename.FileName.ToString()}/start", new StringContent(""));
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
tcs.SetException(new Exception($"Start Error: {response.StatusCode} {response.ReasonPhrase}"));
|
||||
@ -75,29 +69,27 @@ namespace Wabbajack.Lib.FileUploader
|
||||
progressFn((double)sent / fsize);
|
||||
|
||||
int retries = 0;
|
||||
|
||||
using (var fs = File.OpenRead(filename))
|
||||
{
|
||||
fs.Position = block_offset;
|
||||
var data = new byte[block_size];
|
||||
await fs.ReadAsync(data, 0, data.Length);
|
||||
|
||||
await using var fs = filename.OpenRead();
|
||||
fs.Position = block_offset;
|
||||
var data = new byte[block_size];
|
||||
await fs.ReadAsync(data, 0, data.Length);
|
||||
|
||||
|
||||
var putResponse = await client.PutAsync(UploadURL + $"/{key}/data/{block_offset}",
|
||||
new ByteArrayContent(data));
|
||||
response = await client.PutAsync(UploadURL + $"/{key}/data/{block_offset}",
|
||||
new ByteArrayContent(data));
|
||||
|
||||
if (!putResponse.IsSuccessStatusCode)
|
||||
{
|
||||
tcs.SetException(new Exception($"Put Error: {putResponse.StatusCode} {putResponse.ReasonPhrase}"));
|
||||
return;
|
||||
}
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
tcs.SetException(new Exception($"Put Error: {response.StatusCode} {response.ReasonPhrase}"));
|
||||
return;
|
||||
}
|
||||
|
||||
var val = long.Parse(await putResponse.Content.ReadAsStringAsync());
|
||||
if (val != block_offset + data.Length)
|
||||
{
|
||||
tcs.SetResult($"Sync Error {val} vs {block_offset + data.Length}");
|
||||
tcs.SetException(new Exception($"Sync Error {val} vs {block_offset + data.Length}"));
|
||||
}
|
||||
var val = long.Parse(await response.Content.ReadAsStringAsync());
|
||||
if (val != block_offset + data.Length)
|
||||
{
|
||||
tcs.SetResult($"Sync Error {val} vs {block_offset + data.Length}");
|
||||
tcs.SetException(new Exception($"Sync Error {val} vs {block_offset + data.Length}"));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -119,16 +111,16 @@ namespace Wabbajack.Lib.FileUploader
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
public static Common.Http.Client GetAuthorizedClient()
|
||||
public static async Task<Common.Http.Client> GetAuthorizedClient()
|
||||
{
|
||||
var client = new Common.Http.Client();
|
||||
client.Headers.Add(("X-API-KEY", GetAPIKey()));
|
||||
client.Headers.Add(("X-API-KEY", await GetAPIKey()));
|
||||
return client;
|
||||
}
|
||||
|
||||
public static async Task<string> RunJob(string jobtype)
|
||||
{
|
||||
var client = GetAuthorizedClient();
|
||||
var client = await GetAuthorizedClient();
|
||||
return await client.GetStringAsync($"https://{Consts.WabbajackCacheHostname}/jobs/enqueue_job/{jobtype}");
|
||||
|
||||
}
|
||||
@ -173,17 +165,17 @@ namespace Wabbajack.Lib.FileUploader
|
||||
|
||||
public static async Task<string> GetServerLog()
|
||||
{
|
||||
return await GetAuthorizedClient().GetStringAsync($"https://{Consts.WabbajackCacheHostname}/heartbeat/logs");
|
||||
return await (await GetAuthorizedClient()).GetStringAsync($"https://{Consts.WabbajackCacheHostname}/heartbeat/logs");
|
||||
}
|
||||
|
||||
public static async Task<IEnumerable<string>> GetMyFiles()
|
||||
{
|
||||
return (await GetAuthorizedClient().GetStringAsync($"https://{Consts.WabbajackCacheHostname}/uploaded_files/list")).FromJSONString<string[]>();
|
||||
return (await (await GetAuthorizedClient()).GetStringAsync($"https://{Consts.WabbajackCacheHostname}/uploaded_files/list")).FromJSONString<string[]>();
|
||||
}
|
||||
|
||||
public static async Task<string> DeleteFile(string name)
|
||||
{
|
||||
var result = await GetAuthorizedClient()
|
||||
var result = await (await GetAuthorizedClient())
|
||||
.DeleteStringAsync($"https://{Consts.WabbajackCacheHostname}/uploaded_files/{name}");
|
||||
return result;
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ namespace Wabbajack.Lib
|
||||
|
||||
public override ModManager ModManager => ModManager.MO2;
|
||||
|
||||
public string GameFolder { get; set; }
|
||||
public AbsolutePath? GameFolder { get; set; }
|
||||
|
||||
public MO2Installer(string archive, ModList modList, string outputFolder, string downloadFolder, SystemParameters parameters)
|
||||
public MO2Installer(string archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters)
|
||||
: base(
|
||||
archive: archive,
|
||||
modList: modList,
|
||||
@ -84,10 +84,10 @@ namespace Wabbajack.Lib
|
||||
UpdateTracker.NextStep("Validating Modlist");
|
||||
await ValidateModlist.RunValidation(ModList);
|
||||
|
||||
Directory.CreateDirectory(OutputFolder);
|
||||
Directory.CreateDirectory(DownloadFolder);
|
||||
OutputFolder.CreateDirectory();
|
||||
DownloadFolder.CreateDirectory();
|
||||
|
||||
if (Directory.Exists(Path.Combine(OutputFolder, Consts.MO2ModFolderName)) && WarnOnOverwrite)
|
||||
if (OutputFolder.Combine(Consts.MO2ModFolderName).IsDirectory && WarnOnOverwrite)
|
||||
{
|
||||
if ((await Utils.Log(new ConfirmUpdateOfExistingInstall { ModListName = ModList.Name, OutputFolder = OutputFolder }).Task) == ConfirmUpdateOfExistingInstall.Choice.Abort)
|
||||
{
|
||||
@ -152,7 +152,7 @@ namespace Wabbajack.Lib
|
||||
await zEditIntegration.GenerateMerges(this);
|
||||
|
||||
UpdateTracker.NextStep("Set MO2 into portable");
|
||||
ForcePortable();
|
||||
await ForcePortable();
|
||||
|
||||
UpdateTracker.NextStep("Create Empty Output Mods");
|
||||
CreateOutputMods();
|
||||
@ -168,7 +168,11 @@ namespace Wabbajack.Lib
|
||||
|
||||
private void CreateOutputMods()
|
||||
{
|
||||
Directory.EnumerateFiles(Path.Combine(OutputFolder, "profiles"), "settings.ini", DirectoryEnumerationOptions.Recursive).Do(f =>
|
||||
|
||||
OutputFolder.Combine("profiles")
|
||||
.EnumerateFiles(true)
|
||||
.Where(f => f.FileName == Consts.SettingsIni)
|
||||
.Do(f =>
|
||||
{
|
||||
var ini = f.LoadIniFile();
|
||||
if (ini == null)
|
||||
@ -189,23 +193,22 @@ namespace Wabbajack.Lib
|
||||
data.Coll.Do(keyData =>
|
||||
{
|
||||
var v = keyData.Value;
|
||||
var mod = Path.Combine(OutputFolder, Consts.MO2ModFolderName, v);
|
||||
var mod = OutputFolder.Combine(Consts.MO2ModFolderName, (RelativePath)v);
|
||||
|
||||
if (!Directory.Exists(mod))
|
||||
Directory.CreateDirectory(mod);
|
||||
mod.CreateDirectory();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ForcePortable()
|
||||
private async Task ForcePortable()
|
||||
{
|
||||
var path = Path.Combine(OutputFolder, "portable.txt");
|
||||
if (File.Exists(path)) return;
|
||||
var path = OutputFolder.Combine("portable.txt");
|
||||
if (path.Exists) return;
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(path, "Created by Wabbajack");
|
||||
await path.WriteAllTextAsync("Created by Wabbajack");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -217,12 +220,12 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
await ModList.Directives
|
||||
.OfType<ArchiveMeta>()
|
||||
.PMap(Queue, directive =>
|
||||
.PMap(Queue, async directive =>
|
||||
{
|
||||
Status($"Writing included .meta file {directive.To}");
|
||||
var outPath = Path.Combine(DownloadFolder, directive.To);
|
||||
if (File.Exists(outPath)) File.Delete(outPath);
|
||||
File.WriteAllBytes(outPath, LoadBytesFromPath(directive.SourceDataID));
|
||||
var outPath = DownloadFolder.Combine(directive.To);
|
||||
if (outPath.IsFile) outPath.Delete();
|
||||
await outPath.WriteAllBytesAsync(await LoadBytesFromPath(directive.SourceDataID));
|
||||
});
|
||||
}
|
||||
|
||||
@ -230,8 +233,8 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
foreach (var esm in ModList.Directives.OfType<CleanedESM>().ToList())
|
||||
{
|
||||
var filename = Path.GetFileName(esm.To);
|
||||
var gameFile = Path.Combine(GameFolder, "Data", filename);
|
||||
var filename = esm.To.FileName;
|
||||
var gameFile = GameFolder.Value.Combine((RelativePath)"Data", filename);
|
||||
Utils.Log($"Validating {filename}");
|
||||
var hash = gameFile.FileHash();
|
||||
if (hash != esm.SourceESMHash)
|
||||
@ -249,28 +252,28 @@ namespace Wabbajack.Lib
|
||||
foreach (var bsa in bsas)
|
||||
{
|
||||
Status($"Building {bsa.To}");
|
||||
var sourceDir = Path.Combine(OutputFolder, Consts.BSACreationDir, bsa.TempID);
|
||||
var sourceDir = OutputFolder.Combine(Consts.BSACreationDir, bsa.TempID);
|
||||
|
||||
var bsaSize = bsa.FileStates.Select(state => File.GetSize(Path.Combine(sourceDir, state.Path))).Sum();
|
||||
var bsaSize = bsa.FileStates.Select(state => sourceDir.Combine(state.Path).Size).Sum();
|
||||
|
||||
using (var a = bsa.State.MakeBuilder(bsaSize))
|
||||
{
|
||||
var streams = await bsa.FileStates.PMap(Queue, state =>
|
||||
{
|
||||
Status($"Adding {state.Path} to BSA");
|
||||
var fs = File.OpenRead(Path.Combine(sourceDir, state.Path));
|
||||
var fs = sourceDir.Combine(state.Path).OpenRead();
|
||||
a.AddFile(state, fs);
|
||||
return fs;
|
||||
});
|
||||
|
||||
Info($"Writing {bsa.To}");
|
||||
a.Build(Path.Combine(OutputFolder, bsa.To));
|
||||
a.Build(OutputFolder.Combine(bsa.To));
|
||||
streams.Do(s => s.Dispose());
|
||||
}
|
||||
}
|
||||
|
||||
var bsaDir = Path.Combine(OutputFolder, Consts.BSACreationDir);
|
||||
if (Directory.Exists(bsaDir))
|
||||
var bsaDir = OutputFolder.Combine(Consts.BSACreationDir);
|
||||
if (bsaDir.Exists)
|
||||
{
|
||||
Info($"Removing temp folder {Consts.BSACreationDir}");
|
||||
Utils.DeleteDirectory(bsaDir);
|
||||
@ -282,40 +285,45 @@ namespace Wabbajack.Lib
|
||||
Info("Writing inline files");
|
||||
await ModList.Directives
|
||||
.OfType<InlineFile>()
|
||||
.PMap(Queue, directive =>
|
||||
.PMap(Queue, async directive =>
|
||||
{
|
||||
Status($"Writing included file {directive.To}");
|
||||
var outPath = Path.Combine(OutputFolder, directive.To);
|
||||
if (File.Exists(outPath)) File.Delete(outPath);
|
||||
if (directive is RemappedInlineFile)
|
||||
WriteRemappedFile((RemappedInlineFile)directive);
|
||||
else if (directive is CleanedESM)
|
||||
GenerateCleanedESM((CleanedESM)directive);
|
||||
else
|
||||
File.WriteAllBytes(outPath, LoadBytesFromPath(directive.SourceDataID));
|
||||
var outPath = OutputFolder.Combine(directive.To);
|
||||
outPath.Delete();
|
||||
|
||||
switch (directive)
|
||||
{
|
||||
case RemappedInlineFile file:
|
||||
await WriteRemappedFile(file);
|
||||
break;
|
||||
case CleanedESM esm:
|
||||
await GenerateCleanedESM(esm);
|
||||
break;
|
||||
default:
|
||||
await outPath.WriteAllBytesAsync(await LoadBytesFromPath(directive.SourceDataID));
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void GenerateCleanedESM(CleanedESM directive)
|
||||
private async Task GenerateCleanedESM(CleanedESM directive)
|
||||
{
|
||||
var filename = Path.GetFileName(directive.To);
|
||||
var gameFile = Path.Combine(GameFolder, "Data", filename);
|
||||
var filename = directive.To.FileName;
|
||||
var gameFile = GameFolder.Value.Combine((RelativePath)"Data", filename);
|
||||
Info($"Generating cleaned ESM for {filename}");
|
||||
if (!File.Exists(gameFile)) throw new InvalidDataException($"Missing {filename} at {gameFile}");
|
||||
if (!gameFile.Exists) throw new InvalidDataException($"Missing {filename} at {gameFile}");
|
||||
Status($"Hashing game version of {filename}");
|
||||
var sha = gameFile.FileHash();
|
||||
var sha = await gameFile.FileHashAsync();
|
||||
if (sha != directive.SourceESMHash)
|
||||
throw new InvalidDataException(
|
||||
$"Cannot patch {filename} from the game folder because the hashes do not match. Have you already cleaned the file?");
|
||||
|
||||
var patchData = LoadBytesFromPath(directive.SourceDataID);
|
||||
var toFile = Path.Combine(OutputFolder, directive.To);
|
||||
var patchData = await LoadBytesFromPath(directive.SourceDataID);
|
||||
var toFile = OutputFolder.Combine(directive.To);
|
||||
Status($"Patching {filename}");
|
||||
using (var output = File.Open(toFile, FileMode.Create))
|
||||
using (var input = File.OpenRead(gameFile))
|
||||
{
|
||||
Utils.ApplyPatch(input, () => new MemoryStream(patchData), output);
|
||||
}
|
||||
using var output = toFile.Create();
|
||||
using var input = gameFile.OpenRead();
|
||||
Utils.ApplyPatch(input, () => new MemoryStream(patchData), output);
|
||||
}
|
||||
|
||||
private void SetScreenSizeInPrefs()
|
||||
@ -363,23 +371,23 @@ namespace Wabbajack.Lib
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteRemappedFile(RemappedInlineFile directive)
|
||||
private async Task WriteRemappedFile(RemappedInlineFile directive)
|
||||
{
|
||||
var data = Encoding.UTF8.GetString(LoadBytesFromPath(directive.SourceDataID));
|
||||
var data = Encoding.UTF8.GetString(await LoadBytesFromPath(directive.SourceDataID));
|
||||
|
||||
data = data.Replace(Consts.GAME_PATH_MAGIC_BACK, GameFolder);
|
||||
data = data.Replace(Consts.GAME_PATH_MAGIC_DOUBLE_BACK, GameFolder.Replace("\\", "\\\\"));
|
||||
data = data.Replace(Consts.GAME_PATH_MAGIC_FORWARD, GameFolder.Replace("\\", "/"));
|
||||
data = data.Replace(Consts.GAME_PATH_MAGIC_BACK, (string)GameFolder);
|
||||
data = data.Replace(Consts.GAME_PATH_MAGIC_DOUBLE_BACK, ((string)GameFolder).Replace("\\", "\\\\"));
|
||||
data = data.Replace(Consts.GAME_PATH_MAGIC_FORWARD, ((string)GameFolder).Replace("\\", "/"));
|
||||
|
||||
data = data.Replace(Consts.MO2_PATH_MAGIC_BACK, OutputFolder);
|
||||
data = data.Replace(Consts.MO2_PATH_MAGIC_DOUBLE_BACK, OutputFolder.Replace("\\", "\\\\"));
|
||||
data = data.Replace(Consts.MO2_PATH_MAGIC_FORWARD, OutputFolder.Replace("\\", "/"));
|
||||
data = data.Replace(Consts.MO2_PATH_MAGIC_BACK, (string)OutputFolder);
|
||||
data = data.Replace(Consts.MO2_PATH_MAGIC_DOUBLE_BACK, ((string)OutputFolder).Replace("\\", "\\\\"));
|
||||
data = data.Replace(Consts.MO2_PATH_MAGIC_FORWARD, ((string)OutputFolder).Replace("\\", "/"));
|
||||
|
||||
data = data.Replace(Consts.DOWNLOAD_PATH_MAGIC_BACK, DownloadFolder);
|
||||
data = data.Replace(Consts.DOWNLOAD_PATH_MAGIC_DOUBLE_BACK, DownloadFolder.Replace("\\", "\\\\"));
|
||||
data = data.Replace(Consts.DOWNLOAD_PATH_MAGIC_FORWARD, DownloadFolder.Replace("\\", "/"));
|
||||
data = data.Replace(Consts.DOWNLOAD_PATH_MAGIC_BACK, (string)DownloadFolder);
|
||||
data = data.Replace(Consts.DOWNLOAD_PATH_MAGIC_DOUBLE_BACK, ((string)DownloadFolder).Replace("\\", "\\\\"));
|
||||
data = data.Replace(Consts.DOWNLOAD_PATH_MAGIC_FORWARD, ((string)DownloadFolder).Replace("\\", "/"));
|
||||
|
||||
File.WriteAllText(Path.Combine(OutputFolder, directive.To), data);
|
||||
await OutputFolder.Combine(directive.To).WriteAllTextAsync(data);
|
||||
}
|
||||
|
||||
public static IErrorResponse CheckValidInstallPath(string path, string downloadFolder)
|
||||
|
@ -82,16 +82,6 @@ namespace Wabbajack.Lib.ModListRegistry
|
||||
|
||||
return metadata.OrderBy(m => (m.ValidationSummary?.HasFailures ?? false ? 1 : 0, m.Title)).ToList();
|
||||
}
|
||||
|
||||
public bool NeedsDownload(string modlistPath)
|
||||
{
|
||||
if (!File.Exists(modlistPath)) return true;
|
||||
if (DownloadMetadata?.Hash == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return DownloadMetadata.Hash != modlistPath.FileHashCached(true);
|
||||
}
|
||||
}
|
||||
|
||||
public class DownloadMetadata
|
||||
|
@ -9,7 +9,7 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
public class ConfirmUpdateOfExistingInstall : ConfirmationIntervention
|
||||
{
|
||||
public string OutputFolder { get; set; }
|
||||
public AbsolutePath OutputFolder { get; set; }
|
||||
public string ModListName { get; set; }
|
||||
|
||||
public override string ShortDescription { get; } = "Do you want to overwrite existing files?";
|
||||
|
@ -47,11 +47,9 @@ namespace Wabbajack.Lib
|
||||
private SteamGame _steamGame;
|
||||
private bool _hasSteamWorkshopItems;
|
||||
|
||||
public override string VFSCacheName => Path.Combine(
|
||||
Consts.LocalAppDataPath,
|
||||
$"vfs_compile_cache-{StagingFolder?.StringSha256Hex() ?? "Unknown"}.bin");
|
||||
public override AbsolutePath VFSCacheName => Consts.LocalAppDataPath.Combine($"vfs_compile_cache-{((string)StagingFolder)?.StringSha256Hex() ?? "Unknown"}.bin");
|
||||
|
||||
public VortexCompiler(Game game, string gamePath, string vortexFolder, string downloadsFolder, string stagingFolder, string outputFile)
|
||||
public VortexCompiler(Game game, AbsolutePath gamePath, AbsolutePath vortexFolder, AbsolutePath downloadsFolder, AbsolutePath stagingFolder, AbsolutePath outputFile)
|
||||
{
|
||||
Game = game;
|
||||
|
||||
@ -65,7 +63,7 @@ namespace Wabbajack.Lib
|
||||
if (string.IsNullOrEmpty(ModListName))
|
||||
{
|
||||
ModListName = $"Vortex ModList for {Game.ToString()}";
|
||||
ModListOutputFile = $"{ModListName}{Consts.ModListExtension}";
|
||||
ModListOutputFile = ((RelativePath)ModListName).RelativeToEntryPoint().WithExtension(Consts.ModListExtension);
|
||||
}
|
||||
|
||||
GameName = Game.MetaData().NexusName;
|
||||
|
@ -20,7 +20,7 @@ namespace Wabbajack.Lib
|
||||
|
||||
public override ModManager ModManager => ModManager.Vortex;
|
||||
|
||||
public VortexInstaller(string archive, ModList modList, string outputFolder, string downloadFolder, SystemParameters parameters)
|
||||
public VortexInstaller(string archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters)
|
||||
: base(
|
||||
archive: archive,
|
||||
modList: modList,
|
||||
@ -52,7 +52,7 @@ namespace Wabbajack.Lib
|
||||
|
||||
if (cancel.IsCancellationRequested) return false;
|
||||
ConfigureProcessor(10, ConstructDynamicNumThreads(await RecommendQueueSize()));
|
||||
Directory.CreateDirectory(DownloadFolder);
|
||||
DownloadFolder.CreateDirectory();
|
||||
|
||||
if (cancel.IsCancellationRequested) return false;
|
||||
UpdateTracker.NextStep("Hashing Archives");
|
||||
@ -120,22 +120,22 @@ namespace Wabbajack.Lib
|
||||
if (result != ConfirmationIntervention.Choice.Continue)
|
||||
return;
|
||||
|
||||
var manualFilesDir = Path.Combine(OutputFolder, Consts.ManualGameFilesDir);
|
||||
var manualFilesDir = OutputFolder.Combine(Consts.ManualGameFilesDir);
|
||||
|
||||
var gameFolder = GameInfo.GameLocation();
|
||||
|
||||
Info($"Copying files from {manualFilesDir} " +
|
||||
$"to the game folder at {gameFolder}");
|
||||
|
||||
if (!Directory.Exists(manualFilesDir))
|
||||
if (!manualFilesDir.Exists)
|
||||
{
|
||||
Info($"{manualFilesDir} does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
await Directory.EnumerateDirectories(manualFilesDir).PMap(Queue, dir =>
|
||||
/* TODO FIX THIS
|
||||
await manualFilesDir.EnumerateFiles().PMap(Queue, dir =>
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(dir);
|
||||
dirInfo.GetDirectories("*", SearchOption.AllDirectories).Do(d =>
|
||||
{
|
||||
var destPath = d.FullName.Replace(manualFilesDir, gameFolder);
|
||||
@ -157,6 +157,8 @@ namespace Wabbajack.Lib
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
private async Task InstallSteamWorkshopItems()
|
||||
@ -182,12 +184,12 @@ namespace Wabbajack.Lib
|
||||
return;
|
||||
|
||||
await ModList.Directives.OfType<SteamMeta>()
|
||||
.PMap(Queue, item =>
|
||||
.PMap(Queue, async item =>
|
||||
{
|
||||
Status("Extracting Steam meta file to temp folder");
|
||||
var path = Path.Combine(DownloadFolder, $"steamWorkshopItem_{item.ItemID}.meta");
|
||||
if (!File.Exists(path))
|
||||
File.WriteAllBytes(path, LoadBytesFromPath(item.SourceDataID));
|
||||
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");
|
||||
|
||||
@ -209,15 +211,15 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
Info("Writing inline files");
|
||||
await ModList.Directives.OfType<InlineFile>()
|
||||
.PMap(Queue,directive =>
|
||||
.PMap(Queue,async directive =>
|
||||
{
|
||||
if (directive.To.EndsWith(Consts.MetaFileExtension))
|
||||
if (directive.To.Extension == Consts.MetaFileExtension)
|
||||
return;
|
||||
|
||||
Info($"Writing included file {directive.To}");
|
||||
var outPath = Path.Combine(OutputFolder, directive.To);
|
||||
if(File.Exists(outPath)) File.Delete(outPath);
|
||||
File.WriteAllBytes(outPath, LoadBytesFromPath(directive.SourceDataID));
|
||||
var outPath = OutputFolder.Combine(directive.To);
|
||||
outPath.Delete();
|
||||
await outPath.WriteAllBytesAsync(await LoadBytesFromPath(directive.SourceDataID));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user