mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Only 246 errors left in Wabbajack.Lib
This commit is contained in:
parent
72d77bef1a
commit
035e376a09
@ -30,12 +30,14 @@ namespace Wabbajack.Common
|
||||
public static readonly HashSet<Extension> SupportedBSAs = new[] {".bsa", ".ba2"}
|
||||
.Select(s => new Extension(s)).ToHashSet();
|
||||
|
||||
public static HashSet<string> ConfigFileExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {".json", ".ini", ".yml", ".xml"};
|
||||
public static HashSet<string> ESPFileExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".esp", ".esm", ".esl"};
|
||||
public static HashSet<string> AssetFileExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {".dds", ".tga", ".nif", ".psc", ".pex"};
|
||||
public static HashSet<Extension> ConfigFileExtensions = new[]{".json", ".ini", ".yml", ".xml"}.Select(s => new Extension(s)).ToHashSet();
|
||||
public static HashSet<Extension> ESPFileExtensions = new []{ ".esp", ".esm", ".esl"}.Select(s => new Extension(s)).ToHashSet();
|
||||
public static HashSet<Extension> AssetFileExtensions = new[] {".dds", ".tga", ".nif", ".psc", ".pex"}.Select(s => new Extension(s)).ToHashSet();
|
||||
|
||||
public static readonly Extension EXE = new Extension(".exe");
|
||||
public static readonly Extension OMOD = new Extension(".omod");
|
||||
public static readonly Extension ESM = new Extension(".esm");
|
||||
public static readonly Extension ESP = new Extension(".esp");
|
||||
|
||||
public static string NexusCacheDirectory = "nexus_link_cache";
|
||||
|
||||
@ -59,7 +61,7 @@ namespace Wabbajack.Common
|
||||
|
||||
public static string AppName = "Wabbajack";
|
||||
|
||||
public static HashSet<string> GameESMs = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
public static HashSet<RelativePath> GameESMs = new []
|
||||
{
|
||||
// Skyrim LE/SE
|
||||
"Skyrim.esm",
|
||||
@ -77,7 +79,7 @@ namespace Wabbajack.Common
|
||||
"DLCNukaWorld.esm",
|
||||
"DLCUltraHighResolution.esm"
|
||||
|
||||
};
|
||||
}.Select(s => (RelativePath)s).ToHashSet();
|
||||
|
||||
public static string ModPermissionsURL = "https://raw.githubusercontent.com/wabbajack-tools/opt-out-lists/master/NexusModPermissions.yml";
|
||||
public static string ServerWhitelistURL = "https://raw.githubusercontent.com/wabbajack-tools/opt-out-lists/master/ServerWhitelist.yml";
|
||||
@ -93,11 +95,13 @@ namespace Wabbajack.Common
|
||||
return headerString;
|
||||
}
|
||||
}
|
||||
|
||||
public static RelativePath MetaIni = new RelativePath("meta.ini");
|
||||
|
||||
public static string HashFileExtension => ".xxHash";
|
||||
public static string MetaFileExtension => ".meta";
|
||||
public static string ModListExtension = ".wabbajack";
|
||||
public static string LocalAppDataPath => Path.Combine(KnownFolders.LocalAppData.Path, "Wabbajack");
|
||||
public static Extension HashFileExtension = new Extension(".xxHash");
|
||||
public static Extension MetaFileExtension = new Extension(".meta");
|
||||
public static Extension ModListExtension = new Extension(".wabbajack");
|
||||
public static AbsolutePath LocalAppDataPath => new AbsolutePath(Path.Combine(KnownFolders.LocalAppData.Path, "Wabbajack"));
|
||||
public static string MetricsKeyHeader => "x-metrics-key";
|
||||
|
||||
public static string WabbajackCacheLocation = "http://build.wabbajack.org/nexus_api_cache/";
|
||||
@ -107,13 +111,16 @@ namespace Wabbajack.Common
|
||||
public static int MaxHTTPRetries = 4;
|
||||
public const string MO2ModFolderName = "mods";
|
||||
|
||||
public static string PatchCacheFolder => Path.Combine(LocalAppDataPath, "patch_cache");
|
||||
public static AbsolutePath PatchCacheFolder => LocalAppDataPath.Combine("patch_cache");
|
||||
public static int MaxConnectionsPerServer = 4;
|
||||
|
||||
public static string LogsFolder = "logs";
|
||||
public static AbsolutePath LogsFolder = ((RelativePath)"logs").RelativeToEntryPoint();
|
||||
public static AbsolutePath EntryPoint = (AbsolutePath)(Assembly.GetEntryAssembly()?.Location ?? (string)((RelativePath)"Unknown").RelativeToWorkingDirectory());
|
||||
public static AbsolutePath LogFile = LogsFolder.Combine(EntryPoint.FileNameWithoutExtension + ".current.log");
|
||||
public static int MaxOldLogs = 50;
|
||||
public static Extension BSA = new Extension(".BSA");
|
||||
|
||||
public static string SettingsFile => Path.Combine(LocalAppDataPath, "settings.json");
|
||||
public static AbsolutePath SettingsFile => LocalAppDataPath.Combine("settings.json");
|
||||
public static byte SettingsVersion => 1;
|
||||
}
|
||||
}
|
||||
|
@ -139,13 +139,13 @@ namespace Wabbajack.Common
|
||||
|
||||
public static bool TryGetHashCache(AbsolutePath file, out Hash hash)
|
||||
{
|
||||
var hashFile = file + Consts.HashFileExtension;
|
||||
var hashFile = file.WithExtension(Consts.HashFileExtension);
|
||||
hash = Hash.Empty;
|
||||
if (!File.Exists(hashFile)) return false;
|
||||
if (!hashFile.IsFile) return false;
|
||||
|
||||
if (File.GetSize(hashFile) != 20) return false;
|
||||
if (hashFile.Size != 20) return false;
|
||||
|
||||
using var fs = File.OpenRead(hashFile);
|
||||
using var fs = hashFile.OpenRead();
|
||||
using var br = new BinaryReader(fs);
|
||||
var version = br.ReadUInt32();
|
||||
if (version != HashCacheVersion) return false;
|
||||
@ -160,7 +160,7 @@ namespace Wabbajack.Common
|
||||
private const uint HashCacheVersion = 0x01;
|
||||
private static void WriteHashCache(AbsolutePath file, Hash hash)
|
||||
{
|
||||
using var fs = File.Create(file + Consts.HashFileExtension);
|
||||
using var fs = file.WithExtension(Consts.HashFileExtension).Create();
|
||||
using var bw = new BinaryWriter(fs);
|
||||
bw.Write(HashCacheVersion);
|
||||
var lastModified = file.LastModifiedUtc.AsUnixTime();
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -16,13 +15,18 @@ namespace Wabbajack.Common
|
||||
{
|
||||
public interface IPath
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the final file name, for c:\bar\baz this is `baz` for c:\bar.zip this is `bar.zip`
|
||||
/// for `bar.zip` this is `bar.zip`
|
||||
/// </summary>
|
||||
public RelativePath FileName { get; }
|
||||
}
|
||||
|
||||
|
||||
public struct AbsolutePath : IPath
|
||||
{
|
||||
|
||||
#region ObjectEquality
|
||||
bool Equals(AbsolutePath other)
|
||||
|
||||
private bool Equals(AbsolutePath other)
|
||||
{
|
||||
return _path == other._path;
|
||||
}
|
||||
@ -39,51 +43,57 @@ namespace Wabbajack.Common
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.GetType() != this.GetType())
|
||||
if (obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((AbsolutePath) obj);
|
||||
return Equals((AbsolutePath)obj);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (_path != null ? _path.GetHashCode() : 0);
|
||||
return _path != null ? _path.GetHashCode() : 0;
|
||||
}
|
||||
|
||||
private readonly string _path;
|
||||
private Extension _extension;
|
||||
|
||||
public AbsolutePath(string path)
|
||||
{
|
||||
_path = path.ToLowerInvariant().Replace("/", "\\").TrimEnd('\\');
|
||||
_extension = new Extension(Path.GetExtension(_path));
|
||||
Extension = new Extension(Path.GetExtension(_path));
|
||||
ValidateAbsolutePath();
|
||||
}
|
||||
|
||||
public AbsolutePath(string path, bool skipValidation)
|
||||
{
|
||||
_path = path.ToLowerInvariant().Replace("/", "\\").TrimEnd('\\');
|
||||
_extension = Extension.FromPath(path);
|
||||
if (!skipValidation)
|
||||
Extension = Extension.FromPath(path);
|
||||
if (!skipValidation)
|
||||
{
|
||||
ValidateAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
public AbsolutePath(AbsolutePath path)
|
||||
{
|
||||
_path = path._path;
|
||||
_extension = path._extension;
|
||||
Extension = path.Extension;
|
||||
}
|
||||
|
||||
private void ValidateAbsolutePath()
|
||||
{
|
||||
if (Path.IsPathRooted(_path)) return;
|
||||
throw new InvalidDataException($"Absolute path must be absolute");
|
||||
if (Path.IsPathRooted(_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidDataException("Absolute path must be absolute");
|
||||
}
|
||||
|
||||
public Extension Extension => _extension;
|
||||
public Extension Extension { get; }
|
||||
|
||||
public FileStream OpenRead()
|
||||
{
|
||||
@ -112,23 +122,22 @@ namespace Wabbajack.Common
|
||||
|
||||
public void DeleteDirectory()
|
||||
{
|
||||
if (IsDirectory)
|
||||
Utils.DeleteDirectory(this);
|
||||
if (IsDirectory)
|
||||
{
|
||||
Utils.DeleteDirectory(this);
|
||||
}
|
||||
}
|
||||
|
||||
public long Size => (new FileInfo(_path)).Length;
|
||||
|
||||
public long Size => new FileInfo(_path).Length;
|
||||
|
||||
public DateTime LastModified => File.GetLastWriteTime(_path);
|
||||
public DateTime LastModifiedUtc => File.GetLastWriteTimeUtc(_path);
|
||||
public AbsolutePath Parent => (AbsolutePath)Path.GetDirectoryName(_path);
|
||||
public RelativePath FileName => (RelativePath)Path.GetFileName(_path);
|
||||
public void Copy(AbsolutePath otherPath)
|
||||
{
|
||||
File.Copy(_path, otherPath._path);
|
||||
}
|
||||
public RelativePath FileNameWithoutExtension => (RelativePath)Path.GetFileNameWithoutExtension(_path);
|
||||
|
||||
/// <summary>
|
||||
/// Moves this file to the specified location
|
||||
/// Moves this file to the specified location
|
||||
/// </summary>
|
||||
/// <param name="otherPath"></param>
|
||||
/// <param name="overwrite">Replace the destination file if it exists</param>
|
||||
@ -139,11 +148,14 @@ namespace Wabbajack.Common
|
||||
|
||||
public RelativePath RelativeTo(AbsolutePath p)
|
||||
{
|
||||
if (_path.Substring(0, p._path.Length + 1) != p._path + "\\")
|
||||
if (_path.Substring(0, p._path.Length + 1) != p._path + "\\")
|
||||
{
|
||||
throw new InvalidDataException("Not a parent path");
|
||||
}
|
||||
|
||||
return new RelativePath(_path.Substring(p._path.Length + 1));
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> ReadAllTextAsync()
|
||||
{
|
||||
await using var fs = File.OpenRead(_path);
|
||||
@ -151,7 +163,7 @@ namespace Wabbajack.Common
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assuming the path is a folder, enumerate all the files in the folder
|
||||
/// Assuming the path is a folder, enumerate all the files in the folder
|
||||
/// </summary>
|
||||
/// <param name="recursive">if true, also returns files in sub-folders</param>
|
||||
/// <returns></returns>
|
||||
@ -164,25 +176,27 @@ namespace Wabbajack.Common
|
||||
|
||||
|
||||
#region Operators
|
||||
|
||||
public static explicit operator string(AbsolutePath path)
|
||||
{
|
||||
return path._path;
|
||||
}
|
||||
|
||||
|
||||
public static explicit operator AbsolutePath(string path)
|
||||
{
|
||||
return !Path.IsPathRooted(path) ? ((RelativePath)path).RelativeToEntryPoint() : new AbsolutePath(path);
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(AbsolutePath a, AbsolutePath b)
|
||||
{
|
||||
return a._path == b._path;
|
||||
}
|
||||
|
||||
|
||||
public static bool operator !=(AbsolutePath a, AbsolutePath b)
|
||||
{
|
||||
return a._path != b._path;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void CreateDirectory()
|
||||
@ -193,25 +207,117 @@ namespace Wabbajack.Common
|
||||
public void Delete()
|
||||
{
|
||||
if (IsFile)
|
||||
{
|
||||
File.Delete(_path);
|
||||
}
|
||||
}
|
||||
|
||||
public bool InFolder(AbsolutePath gameFolder)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<byte[]> ReadAllBytesAsync()
|
||||
{
|
||||
await using var f = OpenRead();
|
||||
return await f.ReadAllAsync();
|
||||
}
|
||||
|
||||
public AbsolutePath WithExtension(Extension hashFileExtension)
|
||||
{
|
||||
return new AbsolutePath(_path + (string)Extension, true);
|
||||
}
|
||||
|
||||
public AbsolutePath ReplaceExtension(Extension extension)
|
||||
{
|
||||
return new AbsolutePath(
|
||||
Path.Combine(Path.GetDirectoryName(_path), Path.GetFileNameWithoutExtension(_path) + (string)extension),
|
||||
true);
|
||||
}
|
||||
|
||||
public AbsolutePath AppendToName(AbsolutePath bsa, string toAppend)
|
||||
{
|
||||
return new AbsolutePath(
|
||||
Path.Combine(Path.GetDirectoryName(_path),
|
||||
Path.GetFileNameWithoutExtension(_path) + toAppend + (string)Extension));
|
||||
}
|
||||
|
||||
public AbsolutePath Combine(params RelativePath[] paths)
|
||||
{
|
||||
return new AbsolutePath(Path.Combine(paths.Select(s => (string)s).Cons(_path).ToArray()));
|
||||
}
|
||||
|
||||
public AbsolutePath Combine(params string[] paths)
|
||||
{
|
||||
return new AbsolutePath(Path.Combine(paths.Cons(_path).ToArray()));
|
||||
}
|
||||
|
||||
public IEnumerable<string> ReadAllLines()
|
||||
{
|
||||
return File.ReadAllLines(_path);
|
||||
}
|
||||
|
||||
public void WriteAllBytes(byte[] data)
|
||||
{
|
||||
using var fs = Create();
|
||||
fs.Write(data);
|
||||
}
|
||||
|
||||
public async Task WriteAllBytesAsync(byte[] data)
|
||||
{
|
||||
await using var fs = Create();
|
||||
await fs.WriteAsync(data);
|
||||
}
|
||||
|
||||
public void AppendAllText(string text)
|
||||
{
|
||||
File.AppendAllText(_path, text);
|
||||
}
|
||||
|
||||
public void CopyTo(AbsolutePath dest, bool useMove = false)
|
||||
{
|
||||
if (useMove)
|
||||
{
|
||||
File.Move(_path, dest._path);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Copy(_path, dest._path);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> ReadAllLinesAsync()
|
||||
{
|
||||
return (await ReadAllTextAsync()).Split(new[] {'\n', '\r'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public byte[] ReadAllBytes()
|
||||
{
|
||||
return File.ReadAllBytes(_path);
|
||||
}
|
||||
}
|
||||
|
||||
public struct RelativePath : IPath, IEquatable<RelativePath>
|
||||
{
|
||||
private readonly string _path;
|
||||
private Extension _extension;
|
||||
|
||||
public RelativePath(string path)
|
||||
{
|
||||
_path = path.ToLowerInvariant().Replace("/", "\\").Trim('\\');
|
||||
_extension = new Extension(Path.GetExtension(path));
|
||||
Extension = new Extension(Path.GetExtension(path));
|
||||
Validate();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
public Extension Extension { get; }
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (_path != null ? _path.GetHashCode() : 0);
|
||||
return _path != null ? _path.GetHashCode() : 0;
|
||||
}
|
||||
|
||||
public static RelativePath RandomFileName()
|
||||
@ -222,7 +328,9 @@ namespace Wabbajack.Common
|
||||
private void Validate()
|
||||
{
|
||||
if (Path.IsPathRooted(_path))
|
||||
{
|
||||
throw new InvalidDataException("Cannot create relative path from absolute path string");
|
||||
}
|
||||
}
|
||||
|
||||
public AbsolutePath RelativeTo(AbsolutePath abs)
|
||||
@ -234,17 +342,17 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return RelativeTo(((AbsolutePath)Assembly.GetEntryAssembly().Location).Parent);
|
||||
}
|
||||
|
||||
|
||||
public AbsolutePath RelativeToWorkingDirectory()
|
||||
{
|
||||
return RelativeTo((AbsolutePath)Directory.GetCurrentDirectory());
|
||||
}
|
||||
|
||||
|
||||
public static explicit operator string(RelativePath path)
|
||||
{
|
||||
return path._path;
|
||||
}
|
||||
|
||||
|
||||
public static explicit operator RelativePath(string path)
|
||||
{
|
||||
return new RelativePath(path);
|
||||
@ -254,9 +362,9 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return RelativeTo((AbsolutePath)Environment.SystemDirectory);
|
||||
}
|
||||
|
||||
|
||||
public RelativePath Parent => (RelativePath)Path.GetDirectoryName(_path);
|
||||
|
||||
|
||||
public RelativePath FileName => new RelativePath(Path.GetFileName(_path));
|
||||
|
||||
public bool Equals(RelativePath other)
|
||||
@ -268,16 +376,21 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return obj is RelativePath other && Equals(other);
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(RelativePath a, RelativePath b)
|
||||
{
|
||||
return a._path == b._path;
|
||||
}
|
||||
|
||||
|
||||
public static bool operator !=(RelativePath a, RelativePath b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public bool StartsWith(string s)
|
||||
{
|
||||
return _path.StartsWith(s);
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class Utils
|
||||
@ -286,7 +399,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return (RelativePath)str;
|
||||
}
|
||||
|
||||
|
||||
public static AbsolutePath RelativeTo(this string str, AbsolutePath path)
|
||||
{
|
||||
return ((RelativePath)str).RelativeTo(path);
|
||||
@ -296,15 +409,20 @@ namespace Wabbajack.Common
|
||||
{
|
||||
wtr.Write(path is AbsolutePath);
|
||||
if (path is AbsolutePath)
|
||||
{
|
||||
wtr.Write((AbsolutePath)path);
|
||||
}
|
||||
else
|
||||
{
|
||||
wtr.Write((RelativePath)path);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter wtr, AbsolutePath path)
|
||||
{
|
||||
wtr.Write((string)path);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter wtr, RelativePath path)
|
||||
{
|
||||
wtr.Write((string)path);
|
||||
@ -313,7 +431,10 @@ namespace Wabbajack.Common
|
||||
public static IPath ReadIPath(this BinaryReader rdr)
|
||||
{
|
||||
if (rdr.ReadBoolean())
|
||||
{
|
||||
return rdr.ReadAbsolutePath();
|
||||
}
|
||||
|
||||
return rdr.ReadRelativePath();
|
||||
}
|
||||
|
||||
@ -334,15 +455,15 @@ namespace Wabbajack.Common
|
||||
newArr[arr.Length] = itm;
|
||||
return newArr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct Extension
|
||||
{
|
||||
public static Extension None = new Extension("", false);
|
||||
|
||||
public static Extension None = new Extension("", false);
|
||||
|
||||
#region ObjectEquality
|
||||
bool Equals(Extension other)
|
||||
|
||||
private bool Equals(Extension other)
|
||||
{
|
||||
return _extension == other._extension;
|
||||
}
|
||||
@ -359,18 +480,19 @@ namespace Wabbajack.Common
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.GetType() != this.GetType())
|
||||
if (obj.GetType() != GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Equals((Extension) obj);
|
||||
return Equals((Extension)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (_extension != null ? _extension.GetHashCode() : 0);
|
||||
return _extension != null ? _extension.GetHashCode() : 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly string _extension;
|
||||
@ -390,39 +512,51 @@ namespace Wabbajack.Common
|
||||
private Extension(string extension, bool validate)
|
||||
{
|
||||
_extension = string.Intern(extension);
|
||||
if (validate) Validate();
|
||||
|
||||
if (validate)
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
}
|
||||
|
||||
public Extension(Extension other)
|
||||
{
|
||||
_extension = other._extension;
|
||||
}
|
||||
|
||||
|
||||
private void Validate()
|
||||
{
|
||||
if (!_extension.StartsWith("."))
|
||||
throw new InvalidDataException($"Extensions must start with '.'");
|
||||
{
|
||||
throw new InvalidDataException("Extensions must start with '.'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static explicit operator string(Extension path)
|
||||
{
|
||||
return path._extension;
|
||||
}
|
||||
|
||||
|
||||
public static explicit operator Extension(string path)
|
||||
{
|
||||
return new Extension(path);
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(Extension a, Extension b)
|
||||
{
|
||||
// Super fast comparison because extensions are interned
|
||||
if ((object)a == null && (object)b == null) return true;
|
||||
if ((object)a == null || (object)b == null) return false;
|
||||
if ((object)a == null && (object)b == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((object)a == null || (object)b == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReferenceEquals(a._extension, b._extension);
|
||||
}
|
||||
|
||||
|
||||
public static bool operator !=(Extension a, Extension b)
|
||||
{
|
||||
return !(a == b);
|
||||
@ -445,7 +579,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
EMPTY_PATH = new RelativePath[0];
|
||||
}
|
||||
|
||||
|
||||
public HashRelativePath(Hash baseHash, params RelativePath[] paths)
|
||||
{
|
||||
BaseHash = baseHash;
|
||||
@ -456,25 +590,31 @@ namespace Wabbajack.Common
|
||||
{
|
||||
return string.Join("|", Paths.Select(t => t.ToString()).Cons(BaseHash.ToString()));
|
||||
}
|
||||
|
||||
|
||||
public static bool operator ==(HashRelativePath a, HashRelativePath b)
|
||||
{
|
||||
if (a.BaseHash != b.BaseHash || a.Paths.Length == b.Paths.Length)
|
||||
{
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < a.Paths.Length; idx += 1)
|
||||
}
|
||||
|
||||
for (var idx = 0; idx < a.Paths.Length; idx += 1)
|
||||
{
|
||||
if (a.Paths[idx] != b.Paths[idx])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool operator !=(HashRelativePath a, HashRelativePath b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct FullPath : IEquatable<FullPath>
|
||||
{
|
||||
public AbsolutePath Base { get; }
|
||||
@ -488,7 +628,9 @@ namespace Wabbajack.Common
|
||||
Paths = paths;
|
||||
_hash = Base.GetHashCode();
|
||||
foreach (var itm in Paths)
|
||||
{
|
||||
_hash ^= itm.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -504,15 +646,21 @@ namespace Wabbajack.Common
|
||||
public static bool operator ==(FullPath a, FullPath b)
|
||||
{
|
||||
if (a.Base != b.Base || a.Paths.Length != b.Paths.Length)
|
||||
{
|
||||
return false;
|
||||
|
||||
for (int idx = 0; idx < a.Paths.Length; idx += 1)
|
||||
}
|
||||
|
||||
for (var idx = 0; idx < a.Paths.Length; idx += 1)
|
||||
{
|
||||
if (a.Paths[idx] != b.Paths[idx])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static bool operator !=(FullPath a, FullPath b)
|
||||
{
|
||||
return !(a == b);
|
||||
|
@ -38,8 +38,8 @@ namespace Wabbajack.Common
|
||||
return processList.Where(process => process.ProcessName == "ModOrganizer").Any(process => Path.GetDirectoryName(process.MainModule?.FileName) == mo2Path);
|
||||
}
|
||||
|
||||
public static string LogFile { get; }
|
||||
public static string LogFolder { get; }
|
||||
public static AbsolutePath LogFile { get; }
|
||||
public static AbsolutePath LogFolder { get; }
|
||||
|
||||
public enum FileEventType
|
||||
{
|
||||
@ -52,34 +52,28 @@ namespace Wabbajack.Common
|
||||
{
|
||||
MessagePackInit();
|
||||
|
||||
if (!Directory.Exists(Consts.LocalAppDataPath))
|
||||
Directory.CreateDirectory(Consts.LocalAppDataPath);
|
||||
Consts.LocalAppDataPath.CreateDirectory();
|
||||
Consts.LogsFolder.CreateDirectory();
|
||||
|
||||
if (!Directory.Exists(Consts.LogsFolder))
|
||||
Directory.CreateDirectory(Consts.LogsFolder);
|
||||
|
||||
var programName = Assembly.GetEntryAssembly()?.Location ?? "Wabbajack";
|
||||
LogFolder = Path.Combine(Path.GetDirectoryName(programName), Consts.LogsFolder);
|
||||
LogFile = Path.Combine(Consts.LogsFolder, Path.GetFileNameWithoutExtension(programName) + ".current.log");
|
||||
LogFolder = Consts.LogsFolder;
|
||||
LogFile = Consts.LogFile;
|
||||
_startTime = DateTime.Now;
|
||||
|
||||
if (LogFile.FileExists())
|
||||
if (LogFile.Exists)
|
||||
{
|
||||
var newPath = Path.Combine(Consts.LogsFolder, Path.GetFileNameWithoutExtension(programName) + new FileInfo(LogFile).LastWriteTime.ToString(" yyyy-MM-dd HH_mm_ss") + ".log");
|
||||
File.Move(LogFile, newPath, MoveOptions.ReplaceExisting);
|
||||
var newPath = Consts.LogsFolder.Combine(Consts.EntryPoint.FileNameWithoutExtension + LogFile.LastModified.ToString(" yyyy-MM-dd HH_mm_ss") + ".log");
|
||||
LogFile.MoveTo(newPath, true);
|
||||
}
|
||||
|
||||
var logFiles = Directory.GetFiles(Consts.LogsFolder);
|
||||
if (logFiles.Length >= Consts.MaxOldLogs)
|
||||
var logFiles = Consts.LogsFolder.EnumerateFiles(false).ToList();
|
||||
if (logFiles.Count >= Consts.MaxOldLogs)
|
||||
{
|
||||
Log($"Maximum amount of old logs reached ({logFiles.Length} >= {Consts.MaxOldLogs})");
|
||||
Log($"Maximum amount of old logs reached ({logFiles.Count} >= {Consts.MaxOldLogs})");
|
||||
var filesToDelete = logFiles
|
||||
.Where(File.Exists)
|
||||
.OrderBy(f =>
|
||||
{
|
||||
var fi = new FileInfo(f);
|
||||
return fi.LastWriteTime;
|
||||
}).Take(logFiles.Length - Consts.MaxOldLogs).ToList();
|
||||
.Where(f => f.IsFile)
|
||||
.OrderBy(f => f.LastModified)
|
||||
.Take(logFiles.Count - Consts.MaxOldLogs)
|
||||
.ToList();
|
||||
|
||||
Log($"Found {filesToDelete.Count} old log files to delete");
|
||||
|
||||
@ -89,7 +83,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(f);
|
||||
f.Delete();
|
||||
success++;
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -102,7 +96,7 @@ namespace Wabbajack.Common
|
||||
Log($"Deleted {success} log files, failed to delete {failed} logs");
|
||||
}
|
||||
|
||||
var watcher = new FileSystemWatcher(Consts.LocalAppDataPath);
|
||||
var watcher = new FileSystemWatcher((string)Consts.LocalAppDataPath);
|
||||
AppLocalEvents = Observable.Merge(Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => watcher.Changed += h, h => watcher.Changed -= h).Select(e => (FileEventType.Changed, e.EventArgs)),
|
||||
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => watcher.Created += h, h => watcher.Created -= h).Select(e => (FileEventType.Created, e.EventArgs)),
|
||||
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(h => watcher.Deleted += h, h => watcher.Deleted -= h).Select(e => (FileEventType.Deleted, e.EventArgs)))
|
||||
@ -164,7 +158,7 @@ namespace Wabbajack.Common
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
File.AppendAllText(LogFile, $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}\r\n");
|
||||
LogFile.AppendAllText($"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,9 +322,9 @@ namespace Wabbajack.Common
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public static dynamic LoadIniFile(this string file)
|
||||
public static dynamic LoadIniFile(this AbsolutePath file)
|
||||
{
|
||||
return new DynamicIniData(new FileIniDataParser().ReadFile(file));
|
||||
return new DynamicIniData(new FileIniDataParser().ReadFile((string)file));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -749,18 +743,17 @@ namespace Wabbajack.Common
|
||||
{
|
||||
var dataA = a.xxHash().FromBase64().ToHex();
|
||||
var dataB = b.xxHash().FromBase64().ToHex();
|
||||
var cacheFile = Path.Combine(Consts.PatchCacheFolder, $"{dataA}_{dataB}.patch");
|
||||
if (!Directory.Exists(Consts.PatchCacheFolder))
|
||||
Directory.CreateDirectory(Consts.PatchCacheFolder);
|
||||
var cacheFile = Consts.PatchCacheFolder.Combine($"{dataA}_{dataB}.patch");
|
||||
Consts.PatchCacheFolder.CreateDirectory();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (File.Exists(cacheFile))
|
||||
if (cacheFile.IsFile)
|
||||
{
|
||||
RETRY_OPEN:
|
||||
try
|
||||
{
|
||||
await using var f = File.OpenRead(cacheFile);
|
||||
await using var f = cacheFile.OpenRead();
|
||||
await f.CopyToAsync(output);
|
||||
}
|
||||
catch (IOException)
|
||||
@ -773,9 +766,9 @@ namespace Wabbajack.Common
|
||||
}
|
||||
else
|
||||
{
|
||||
var tmpName = Path.Combine(Consts.PatchCacheFolder, Guid.NewGuid() + ".tmp");
|
||||
var tmpName = Consts.PatchCacheFolder.Combine(Guid.NewGuid() + ".tmp");
|
||||
|
||||
await using (var f = File.Open(tmpName, System.IO.FileMode.Create))
|
||||
await using (var f = tmpName.Create())
|
||||
{
|
||||
Status("Creating Patch");
|
||||
OctoDiff.Create(a, b, f);
|
||||
@ -784,12 +777,11 @@ namespace Wabbajack.Common
|
||||
RETRY:
|
||||
try
|
||||
{
|
||||
|
||||
File.Move(tmpName, cacheFile, MoveOptions.ReplaceExisting);
|
||||
tmpName.MoveTo(cacheFile, true);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
if (File.Exists(cacheFile))
|
||||
if (cacheFile.IsFile)
|
||||
continue;
|
||||
await Task.Delay(1000);
|
||||
goto RETRY;
|
||||
@ -808,9 +800,9 @@ namespace Wabbajack.Common
|
||||
await using var sigFile = new TempStream();
|
||||
OctoDiff.Create(srcStream, destStream, sigFile, patchStream);
|
||||
patchStream.Position = 0;
|
||||
var tmpName = Path.Combine(Consts.PatchCacheFolder, Guid.NewGuid() + ".tmp");
|
||||
var tmpName = Consts.PatchCacheFolder.Combine(Guid.NewGuid() + ".tmp");
|
||||
|
||||
await using (var f = File.Create(tmpName))
|
||||
await using (var f = tmpName.Create())
|
||||
{
|
||||
await patchStream.CopyToAsync(f);
|
||||
patchStream.Position = 0;
|
||||
@ -818,26 +810,23 @@ namespace Wabbajack.Common
|
||||
|
||||
try
|
||||
{
|
||||
var cacheFile = Path.Combine(Consts.PatchCacheFolder, $"{srcHash.ToHex()}_{destHash.ToHex()}.patch");
|
||||
if (!Directory.Exists(Consts.PatchCacheFolder))
|
||||
Directory.CreateDirectory(Consts.PatchCacheFolder);
|
||||
var cacheFile = Consts.PatchCacheFolder.Combine($"{srcHash.ToHex()}_{destHash.ToHex()}.patch");
|
||||
Consts.PatchCacheFolder.CreateDirectory();
|
||||
|
||||
File.Move(tmpName, cacheFile, MoveOptions.ReplaceExisting);
|
||||
tmpName.MoveTo(cacheFile, true);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
if (File.Exists(tmpName))
|
||||
File.Delete(tmpName);
|
||||
tmpName.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetPatch(Hash foundHash, Hash fileHash, out byte[] ePatch)
|
||||
{
|
||||
var patchName = Path.Combine(Consts.PatchCacheFolder,
|
||||
$"{foundHash.ToHex()}_{fileHash.ToHex()}.patch");
|
||||
if (File.Exists(patchName))
|
||||
var patchName = Consts.PatchCacheFolder.Combine($"{foundHash.ToHex()}_{fileHash.ToHex()}.patch");
|
||||
if (patchName.Exists)
|
||||
{
|
||||
ePatch = File.ReadAllBytes(patchName);
|
||||
ePatch = patchName.ReadAllBytes();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1084,42 +1073,35 @@ namespace Wabbajack.Common
|
||||
public static void ToEcryptedData(this byte[] bytes, string key)
|
||||
{
|
||||
var encoded = ProtectedData.Protect(bytes, Encoding.UTF8.GetBytes(key), DataProtectionScope.LocalMachine);
|
||||
Consts.LocalAppDataPath.CreateDirectory();
|
||||
|
||||
if (!Directory.Exists(Consts.LocalAppDataPath))
|
||||
Directory.CreateDirectory(Consts.LocalAppDataPath);
|
||||
|
||||
var path = Path.Combine(Consts.LocalAppDataPath, key);
|
||||
File.WriteAllBytes(path, encoded);
|
||||
Consts.LocalAppDataPath.Combine(key).WriteAllBytes(bytes);
|
||||
}
|
||||
public static byte[] FromEncryptedData(string key)
|
||||
{
|
||||
var path = Path.Combine(Consts.LocalAppDataPath, key);
|
||||
var bytes = File.ReadAllBytes(path);
|
||||
var bytes = Consts.LocalAppDataPath.Combine(key).ReadAllBytes();
|
||||
return ProtectedData.Unprotect(bytes, Encoding.UTF8.GetBytes(key), DataProtectionScope.LocalMachine);
|
||||
}
|
||||
|
||||
public static bool HaveEncryptedJson(string key)
|
||||
{
|
||||
var path = Path.Combine(Consts.LocalAppDataPath, key);
|
||||
return File.Exists(path);
|
||||
return Consts.LocalAppDataPath.Combine(key).IsFile;
|
||||
}
|
||||
|
||||
public static IObservable<(FileEventType, FileSystemEventArgs)> AppLocalEvents { get; }
|
||||
|
||||
public static IObservable<bool> HaveEncryptedJsonObservable(string key)
|
||||
{
|
||||
var path = Path.Combine(Consts.LocalAppDataPath, key).ToLower();
|
||||
return AppLocalEvents.Where(t => t.Item2.FullPath.ToLower() == path)
|
||||
.Select(_ => File.Exists(path))
|
||||
.StartWith(File.Exists(path))
|
||||
var path = Consts.LocalAppDataPath.Combine(key);
|
||||
return AppLocalEvents.Where(t => (AbsolutePath)t.Item2.FullPath.ToLower() == path)
|
||||
.Select(_ => path.Exists)
|
||||
.StartWith(path.Exists)
|
||||
.DistinctUntilChanged();
|
||||
}
|
||||
|
||||
public static void DeleteEncryptedJson(string key)
|
||||
{
|
||||
var path = Path.Combine(Consts.LocalAppDataPath, key);
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
Consts.LocalAppDataPath.Combine(key).Delete();
|
||||
}
|
||||
|
||||
public static void StartProcessFromFile(string file)
|
||||
|
@ -19,11 +19,12 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
public abstract class ACompiler : ABatchProcessor
|
||||
{
|
||||
public string ModListName, ModListAuthor, ModListDescription, ModListImage, ModListWebsite, ModListReadme;
|
||||
public string ModListName, ModListAuthor, ModListDescription, ModListWebsite;
|
||||
public RelativePath ModListImage, ModListReadme;
|
||||
public bool ReadmeIsWebsite;
|
||||
protected Version WabbajackVersion;
|
||||
|
||||
public abstract string VFSCacheName { get; }
|
||||
public abstract AbsolutePath VFSCacheName { get; }
|
||||
//protected string VFSCacheName => Path.Combine(Consts.LocalAppDataPath, $"vfs_compile_cache.bin");
|
||||
/// <summary>
|
||||
/// A stream of tuples of ("Update Title", 0.25) which represent the name of the current task
|
||||
@ -34,10 +35,10 @@ namespace Wabbajack.Lib
|
||||
|
||||
public abstract ModManager ModManager { get; }
|
||||
|
||||
public abstract string GamePath { get; }
|
||||
public abstract AbsolutePath GamePath { get; }
|
||||
|
||||
public abstract string ModListOutputFolder { get; }
|
||||
public abstract string ModListOutputFile { get; }
|
||||
public abstract AbsolutePath ModListOutputFolder { get; }
|
||||
public abstract AbsolutePath ModListOutputFile { get; }
|
||||
|
||||
public bool IgnoreMissingFiles { get; set; }
|
||||
|
||||
@ -65,23 +66,35 @@ namespace Wabbajack.Lib
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
internal string IncludeFile(byte[] data)
|
||||
internal RelativePath IncludeId()
|
||||
{
|
||||
var id = Guid.NewGuid().ToString();
|
||||
File.WriteAllBytes(Path.Combine(ModListOutputFolder, id), data);
|
||||
return RelativePath.RandomFileName();
|
||||
}
|
||||
|
||||
internal async Task<RelativePath> IncludeFile(byte[] data)
|
||||
{
|
||||
var id = IncludeId();
|
||||
await ModListOutputFolder.Combine(id).WriteAllBytesAsync(data);
|
||||
return id;
|
||||
}
|
||||
|
||||
internal FileStream IncludeFile(out string id)
|
||||
internal FileStream IncludeFile(out RelativePath id)
|
||||
{
|
||||
id = Guid.NewGuid().ToString();
|
||||
return File.Create(Path.Combine(ModListOutputFolder, id));
|
||||
id = IncludeId();
|
||||
return ModListOutputFolder.Combine(id).Create();
|
||||
}
|
||||
|
||||
internal string IncludeFile(string data)
|
||||
internal async Task<RelativePath> IncludeFile(string data)
|
||||
{
|
||||
var id = Guid.NewGuid().ToString();
|
||||
File.WriteAllText(Path.Combine(ModListOutputFolder, id), data);
|
||||
var id = IncludeId();
|
||||
await ModListOutputFolder.Combine(id).WriteAllTextAsync(data);
|
||||
return id;
|
||||
}
|
||||
|
||||
internal RelativePath IncludeFile(AbsolutePath data)
|
||||
{
|
||||
var id = IncludeId();
|
||||
data.Copy(ModListOutputFolder.Combine(id));
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -20,18 +20,18 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
public bool IgnoreMissingFiles { get; internal set; } = false;
|
||||
|
||||
public string OutputFolder { get; private set; }
|
||||
public string DownloadFolder { get; private set; }
|
||||
public AbsolutePath OutputFolder { get; private set; }
|
||||
public AbsolutePath DownloadFolder { get; private set; }
|
||||
|
||||
public abstract ModManager ModManager { get; }
|
||||
|
||||
public string ModListArchive { get; private set; }
|
||||
public ModList ModList { get; private set; }
|
||||
public Dictionary<Hash, string> HashedArchives { get; set; }
|
||||
public Dictionary<Hash, AbsolutePath> HashedArchives { get; set; }
|
||||
|
||||
public SystemParameters SystemParameters { get; set; }
|
||||
|
||||
public AInstaller(string archive, ModList modList, string outputFolder, string downloadFolder, SystemParameters parameters)
|
||||
public AInstaller(string archive, ModList modList, AbsolutePath outputFolder, AbsolutePath downloadFolder, SystemParameters parameters)
|
||||
{
|
||||
ModList = modList;
|
||||
ModListArchive = archive;
|
||||
@ -90,20 +90,9 @@ namespace Wabbajack.Lib
|
||||
/// We don't want to make the installer index all the archives, that's just a waste of time, so instead
|
||||
/// we'll pass just enough information to VFS to let it know about the files we have.
|
||||
/// </summary>
|
||||
public async Task PrimeVFS()
|
||||
protected async Task PrimeVFS()
|
||||
{
|
||||
VFS.AddKnown(HashedArchives.Select(a => new KnownFile
|
||||
{
|
||||
Paths = new[] { a.Value },
|
||||
Hash = a.Key
|
||||
}));
|
||||
|
||||
|
||||
VFS.AddKnown(
|
||||
ModList.Directives
|
||||
.OfType<FromArchive>()
|
||||
.Select(f => new KnownFile { Paths = f.ArchiveHashPath, Hash = f.Hash}));
|
||||
|
||||
VFS.AddKnown(ModList.Directives.OfType<FromArchive>().Select(d => d.ArchiveHashPath), HashedArchives);
|
||||
await VFS.BackfillMissing();
|
||||
}
|
||||
|
||||
@ -111,13 +100,9 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
Info("Building Folder Structure");
|
||||
ModList.Directives
|
||||
.Select(d => Path.Combine(OutputFolder, Path.GetDirectoryName(d.To)))
|
||||
.Select(d => OutputFolder.Combine(d.To.Parent))
|
||||
.Distinct()
|
||||
.Do(f =>
|
||||
{
|
||||
if (Directory.Exists(f)) return;
|
||||
Directory.CreateDirectory(f);
|
||||
});
|
||||
.Do(f => OutputFolder.CreateDirectory());
|
||||
}
|
||||
|
||||
public async Task InstallArchives()
|
||||
@ -126,8 +111,8 @@ namespace Wabbajack.Lib
|
||||
Info("Grouping Install Files");
|
||||
var grouped = ModList.Directives
|
||||
.OfType<FromArchive>()
|
||||
.GroupBy(e => e.ArchiveHashPath[0])
|
||||
.ToDictionary(k => Hash.FromBase64(k.Key));
|
||||
.GroupBy(e => e.ArchiveHashPath.BaseHash)
|
||||
.ToDictionary(k => k.Key);
|
||||
var archives = ModList.Archives
|
||||
.Select(a => new { Archive = a, AbsolutePath = HashedArchives.GetOrDefault(a.Hash) })
|
||||
.Where(a => a.AbsolutePath != null)
|
||||
@ -137,7 +122,7 @@ namespace Wabbajack.Lib
|
||||
await archives.PMap(Queue, UpdateTracker,a => InstallArchive(Queue, a.Archive, a.AbsolutePath, grouped[a.Archive.Hash]));
|
||||
}
|
||||
|
||||
private async Task InstallArchive(WorkQueue queue, Archive archive, string absolutePath, IGrouping<string, FromArchive> grouping)
|
||||
private async Task InstallArchive(WorkQueue queue, Archive archive, AbsolutePath absolutePath, IGrouping<Hash, FromArchive> grouping)
|
||||
{
|
||||
Status($"Extracting {archive.Name}");
|
||||
|
||||
@ -184,13 +169,12 @@ namespace Wabbajack.Lib
|
||||
.PDoIndexed(queue, (idx, group) =>
|
||||
{
|
||||
Utils.Status("Installing files", Percent.FactoryPutInRange(idx, vFiles.Count));
|
||||
var firstDest = Path.Combine(OutputFolder, group.First().To);
|
||||
CopyFile(group.Key.StagedPath, firstDest, true);
|
||||
var firstDest = OutputFolder.Combine(group.First().To);
|
||||
group.Key.StagedPath.CopyTo(firstDest, true);
|
||||
|
||||
foreach (var copy in group.Skip(1))
|
||||
{
|
||||
var nextDest = Path.Combine(OutputFolder, copy.To);
|
||||
CopyFile(firstDest, nextDest, false);
|
||||
firstDest.CopyTo(OutputFolder.Combine(copy.To));
|
||||
}
|
||||
|
||||
});
|
||||
@ -203,25 +187,25 @@ namespace Wabbajack.Lib
|
||||
.PMap(queue, async toPatch =>
|
||||
{
|
||||
await using var patchStream = new MemoryStream();
|
||||
Status($"Patching {Path.GetFileName(toPatch.To)}");
|
||||
Status($"Patching {toPatch.To.FileName}");
|
||||
// Read in the patch data
|
||||
|
||||
byte[] patchData = LoadBytesFromPath(toPatch.PatchID);
|
||||
|
||||
var toFile = Path.Combine(OutputFolder, toPatch.To);
|
||||
var oldData = new MemoryStream(File.ReadAllBytes(toFile));
|
||||
var toFile = OutputFolder.Combine(toPatch.To);
|
||||
var oldData = new MemoryStream(await toFile.ReadAllBytesAsync());
|
||||
|
||||
// Remove the file we're about to patch
|
||||
File.Delete(toFile);
|
||||
toFile.Delete();
|
||||
|
||||
// Patch it
|
||||
await using (var outStream = File.Open(toFile, FileMode.Create))
|
||||
await using (var outStream = toFile.Create())
|
||||
{
|
||||
Utils.ApplyPatch(oldData, () => new MemoryStream(patchData), outStream);
|
||||
}
|
||||
|
||||
Status($"Verifying Patch {Path.GetFileName(toPatch.To)}");
|
||||
var resultSha = toFile.FileHash();
|
||||
Status($"Verifying Patch {toPatch.To.FileName}");
|
||||
var resultSha = await toFile.FileHashAsync();
|
||||
if (resultSha != toPatch.Hash)
|
||||
throw new InvalidDataException($"Invalid Hash for {toPatch.To} after patching");
|
||||
});
|
||||
|
@ -14,7 +14,7 @@ namespace Wabbajack.Lib.CompilationSteps.CompilationErrors
|
||||
public Hash Hash { get; }
|
||||
public string PathToFile { get; }
|
||||
private readonly CleanedESM _esm;
|
||||
public string GameFileName => Path.GetFileName(_esm.To);
|
||||
public RelativePath GameFileName => _esm.To.FileName;
|
||||
public override string ShortDescription
|
||||
{
|
||||
get =>
|
||||
@ -24,7 +24,7 @@ namespace Wabbajack.Lib.CompilationSteps.CompilationErrors
|
||||
public override string ExtendedDescription
|
||||
{
|
||||
get =>
|
||||
$@"This modlist is setup to perform automatic cleaning of the stock game file {GameFileName} in order to perform this cleaning Wabbajack must first verify that the
|
||||
$@"This modlist is setup to perform automatic cleaning of the stock game file {(string)GameFileName} in order to perform this cleaning Wabbajack must first verify that the
|
||||
source file is in the correct state. It seems that the file in your game directory has a hash of {Hash} instead of the expect hash of {_esm.SourceESMHash}. This could be caused by
|
||||
the modlist expecting a different of the game than you currently have installed, or perhaps you have already cleaned the file. You could attempt to fix this error by re-installing
|
||||
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.";
|
||||
|
@ -16,7 +16,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
if (!_compiler.IndexedFiles.TryGetValue(source.Hash, out var found)) return null;
|
||||
var result = source.EvolveTo<FromArchive>();
|
||||
|
||||
var match = found.Where(f => Path.GetFileName(f.Name) == Path.GetFileName(source.Path))
|
||||
var match = found.Where(f => f.Name.FileName == source.Path.FileName)
|
||||
.OrderBy(f => f.NestingFactor)
|
||||
.FirstOrDefault()
|
||||
?? found.OrderBy(f => f.NestingFactor).FirstOrDefault();
|
||||
|
@ -18,7 +18,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
var alwaysEnabled = _mo2Compiler.ModInis.Where(f => IsAlwaysEnabled(f.Value)).Select(f => f.Key).Distinct();
|
||||
|
||||
_allEnabledMods = _mo2Compiler.SelectedProfiles
|
||||
.SelectMany(p => File.ReadAllLines(Path.Combine(_mo2Compiler.MO2Folder, "profiles", p, "modlist.txt")))
|
||||
.SelectMany(p => _mo2Compiler.MO2Folder.Combine("profiles", p, "modlist.txt").ReadAllLines())
|
||||
.Where(line => line.StartsWith("+") || line.EndsWith("_separator"))
|
||||
.Select(line => line.Substring(1))
|
||||
.Concat(alwaysEnabled)
|
||||
|
@ -17,7 +17,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
var b = false;
|
||||
_vortexCompiler.ActiveArchives.Do(a =>
|
||||
{
|
||||
if (source.Path.Contains(a)) b = true;
|
||||
if (((string)source.Path).Contains(a)) b = true;
|
||||
});
|
||||
if (b) return null;
|
||||
var r = source.EvolveTo<IgnoredDirectly>();
|
||||
|
@ -16,7 +16,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!source.Path.EndsWith(_postfix)) return null;
|
||||
if (!((string)source.Path).EndsWith(_postfix)) return null;
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = _reason;
|
||||
return result;
|
||||
|
@ -15,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!source.Path.StartsWith(_startDir)) return null;
|
||||
if (!((string)source.Path).StartsWith(_startDir)) return null;
|
||||
var i = source.EvolveTo<IgnoredDirectly>();
|
||||
i.Reason = "Default game file";
|
||||
return i;
|
||||
|
@ -7,11 +7,11 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
public class IgnoreGameFilesIfGameFolderFilesExist : ACompilationStep
|
||||
{
|
||||
private readonly bool _gameFolderFilesExists;
|
||||
private readonly string _gameFolder;
|
||||
private readonly AbsolutePath _gameFolder;
|
||||
|
||||
public IgnoreGameFilesIfGameFolderFilesExist(ACompiler compiler) : base(compiler)
|
||||
{
|
||||
_gameFolderFilesExists = Directory.Exists(Path.Combine(((MO2Compiler)compiler).MO2Folder, Consts.GameFolderFilesDir));
|
||||
_gameFolderFilesExists = ((MO2Compiler)compiler).MO2Folder.Combine(Consts.GameFolderFilesDir).IsDirectory;
|
||||
_gameFolder = compiler.GamePath;
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
if (_gameFolderFilesExists)
|
||||
{
|
||||
if (source.AbsolutePath.IsInPath(_gameFolder))
|
||||
if (source.AbsolutePath.InFolder(_gameFolder))
|
||||
{
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = $"Ignoring game files because {Consts.GameFolderFilesDir} exists";
|
||||
|
@ -16,7 +16,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!source.Path.Contains(_pattern)) return null;
|
||||
if (!((string)source.Path).Contains(_pattern)) return null;
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = _reason;
|
||||
return result;
|
||||
|
@ -19,7 +19,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!_regex.IsMatch(source.Path)) return null;
|
||||
if (!_regex.IsMatch((string)source.Path)) return null;
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = _reason;
|
||||
return result;
|
||||
|
@ -16,14 +16,15 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (source.Path.StartsWith(_prefix))
|
||||
if (!((string)source.Path).StartsWith(_prefix))
|
||||
{
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = _reason;
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = _reason;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public override IState GetState()
|
||||
|
@ -15,7 +15,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (Path.GetDirectoryName(source.AbsolutePath) != _vortex.DownloadsFolder) return null;
|
||||
if (source.AbsolutePath.Parent != _vortex.DownloadsFolder) return null;
|
||||
var result = source.EvolveTo<IgnoredDirectly>();
|
||||
result.Reason = "Ignored because it is a Vortex file";
|
||||
return result;
|
||||
|
@ -13,7 +13,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
var inline = source.EvolveTo<InlineFile>();
|
||||
inline.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
inline.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
return inline;
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,9 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!Consts.ConfigFileExtensions.Contains(Path.GetExtension(source.Path))) return null;
|
||||
if (!Consts.ConfigFileExtensions.Contains(source.Path.Extension)) return null;
|
||||
var result = source.EvolveTo<InlineFile>();
|
||||
result.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
result.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
@ -12,19 +13,16 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (Path.GetExtension(source.AbsolutePath) != ".esp" &&
|
||||
Path.GetExtension(source.AbsolutePath) != ".esm") return null;
|
||||
if (source.AbsolutePath.Extension != Consts.ESP &&
|
||||
source.AbsolutePath.Extension != Consts.ESM) return null;
|
||||
|
||||
var bsa = Path.Combine(Path.GetDirectoryName(source.AbsolutePath),
|
||||
Path.GetFileNameWithoutExtension(source.AbsolutePath) + ".bsa");
|
||||
var bsaTextures = Path.Combine(Path.GetDirectoryName(source.AbsolutePath),
|
||||
Path.GetFileNameWithoutExtension(source.AbsolutePath) + " - Textures.bsa");
|
||||
var espSize = new FileInfo(source.AbsolutePath).Length;
|
||||
var bsa = source.AbsolutePath.ReplaceExtension(Consts.BSA);
|
||||
var bsaTextures = source.AbsolutePath.AppendToName(bsa, " - Textures");
|
||||
|
||||
if (espSize > 250 || !File.Exists(bsa) && !File.Exists(bsaTextures)) return null;
|
||||
if (source.AbsolutePath.Size > 250 || !bsa.IsFile && !bsaTextures.IsFile) return null;
|
||||
|
||||
var inline = source.EvolveTo<InlineFile>();
|
||||
inline.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
inline.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
return inline;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
if (!source.Path.StartsWith(_prefix)) return null;
|
||||
var result = source.EvolveTo<InlineFile>();
|
||||
result.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
result.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
@ -12,9 +13,9 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!source.Path.StartsWith("mods\\") || !source.Path.EndsWith("\\meta.ini")) return null;
|
||||
if (!source.Path.StartsWith("mods\\") || source.Path.FileName != Consts.MetaIni) return null;
|
||||
var e = source.EvolveTo<InlineFile>();
|
||||
e.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
e.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
return e;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using Newtonsoft.Json;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack.Lib.CompilationSteps
|
||||
{
|
||||
@ -15,16 +16,16 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
var files = new HashSet<string>
|
||||
var files = new HashSet<AbsolutePath>
|
||||
{
|
||||
_compiler.ModListImage, _compiler.ModListReadme
|
||||
};
|
||||
if (!files.Any(f => source.AbsolutePath.Equals(f))) return null;
|
||||
if (!File.Exists(source.AbsolutePath)) return null;
|
||||
if (!source.AbsolutePath.Exists) return null;
|
||||
var isBanner = source.AbsolutePath == _compiler.ModListImage;
|
||||
//var isReadme = source.AbsolutePath == ModListReadme;
|
||||
var result = source.EvolveTo<PropertyFile>();
|
||||
result.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
result.SourceDataID = await _compiler.IncludeFile(source.AbsolutePath.ReadAllBytesAsync());
|
||||
if (isBanner)
|
||||
{
|
||||
result.Type = PropertyType.Banner;
|
||||
|
@ -18,10 +18,10 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
if (!_regex.IsMatch(source.Path)) return null;
|
||||
if (!_regex.IsMatch((string)source.Path)) return null;
|
||||
|
||||
var result = source.EvolveTo<InlineFile>();
|
||||
result.SourceDataID = _compiler.IncludeFile(File.ReadAllBytes(source.AbsolutePath));
|
||||
result.SourceDataID = await _compiler.IncludeFile(await source.AbsolutePath.ReadAllBytesAsync());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
return Consts.ConfigFileExtensions.Contains(Path.GetExtension(source.Path)) ? RemapFile(source) : null;
|
||||
return Consts.ConfigFileExtensions.Contains(source.Path.Extension) ? await RemapFile(source) : null;
|
||||
}
|
||||
|
||||
public override IState GetState()
|
||||
@ -25,23 +25,23 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
return new State();
|
||||
}
|
||||
|
||||
private Directive RemapFile(RawSourceFile source)
|
||||
private async Task<Directive> RemapFile(RawSourceFile source)
|
||||
{
|
||||
var data = File.ReadAllText(source.AbsolutePath);
|
||||
var data = await source.AbsolutePath.ReadAllTextAsync();
|
||||
var originalData = data;
|
||||
|
||||
data = data.Replace(_mo2Compiler.GamePath, Consts.GAME_PATH_MAGIC_BACK);
|
||||
data = data.Replace(_mo2Compiler.GamePath.Replace("\\", "\\\\"), Consts.GAME_PATH_MAGIC_DOUBLE_BACK);
|
||||
data = data.Replace(_mo2Compiler.GamePath.Replace("\\", "/"), Consts.GAME_PATH_MAGIC_FORWARD);
|
||||
data = data.Replace((string)_mo2Compiler.GamePath, Consts.GAME_PATH_MAGIC_BACK);
|
||||
data = data.Replace(((string)_mo2Compiler.GamePath).Replace("\\", "\\\\"), Consts.GAME_PATH_MAGIC_DOUBLE_BACK);
|
||||
data = data.Replace(((string)_mo2Compiler.GamePath).Replace("\\", "/"), Consts.GAME_PATH_MAGIC_FORWARD);
|
||||
|
||||
data = data.Replace(_mo2Compiler.MO2Folder, Consts.MO2_PATH_MAGIC_BACK);
|
||||
data = data.Replace(_mo2Compiler.MO2Folder.Replace("\\", "\\\\"), Consts.MO2_PATH_MAGIC_DOUBLE_BACK);
|
||||
data = data.Replace(_mo2Compiler.MO2Folder.Replace("\\", "/"), Consts.MO2_PATH_MAGIC_FORWARD);
|
||||
data = data.Replace((string)_mo2Compiler.MO2Folder, Consts.MO2_PATH_MAGIC_BACK);
|
||||
data = data.Replace(((string)_mo2Compiler.MO2Folder).Replace("\\", "\\\\"), Consts.MO2_PATH_MAGIC_DOUBLE_BACK);
|
||||
data = data.Replace(((string)_mo2Compiler.MO2Folder).Replace("\\", "/"), Consts.MO2_PATH_MAGIC_FORWARD);
|
||||
|
||||
data = data.Replace(_mo2Compiler.MO2DownloadsFolder, Consts.DOWNLOAD_PATH_MAGIC_BACK);
|
||||
data = data.Replace(_mo2Compiler.MO2DownloadsFolder.Replace("\\", "\\\\"),
|
||||
data = data.Replace((string)_mo2Compiler.MO2DownloadsFolder, Consts.DOWNLOAD_PATH_MAGIC_BACK);
|
||||
data = data.Replace(((string)_mo2Compiler.MO2DownloadsFolder).Replace("\\", "\\\\"),
|
||||
Consts.DOWNLOAD_PATH_MAGIC_DOUBLE_BACK);
|
||||
data = data.Replace(_mo2Compiler.MO2DownloadsFolder.Replace("\\", "/"), Consts.DOWNLOAD_PATH_MAGIC_FORWARD);
|
||||
data = data.Replace(((string)_mo2Compiler.MO2DownloadsFolder).Replace("\\", "/"), Consts.DOWNLOAD_PATH_MAGIC_FORWARD);
|
||||
|
||||
if (data == originalData)
|
||||
return null;
|
||||
|
@ -18,10 +18,10 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
|
||||
public override async ValueTask<Directive> Run(RawSourceFile source)
|
||||
{
|
||||
var filename = Path.GetFileName(source.Path);
|
||||
var gameFile = Path.Combine(_mo2Compiler.GamePath, "Data", filename);
|
||||
var filename = source.Path.FileName;
|
||||
var gameFile = _mo2Compiler.GamePath.Combine((RelativePath)"Data", filename);
|
||||
if (!Consts.GameESMs.Contains(filename) || !source.Path.StartsWith("mods\\") ||
|
||||
!File.Exists(gameFile)) return null;
|
||||
!gameFile.Exists) return null;
|
||||
|
||||
Utils.Log(
|
||||
$"An ESM named {filename} was found in a mod that shares a name with one of the core game ESMs, it is assumed this is a cleaned ESM and it will be binary patched");
|
||||
@ -31,9 +31,9 @@ namespace Wabbajack.Lib.CompilationSteps
|
||||
Utils.Status($"Generating patch of {filename}");
|
||||
await using (var ms = new MemoryStream())
|
||||
{
|
||||
await Utils.CreatePatch(File.ReadAllBytes(gameFile), File.ReadAllBytes(source.AbsolutePath), ms);
|
||||
await Utils.CreatePatch(await gameFile.ReadAllBytesAsync(), await source.AbsolutePath.ReadAllBytesAsync(), ms);
|
||||
var data = ms.ToArray();
|
||||
result.SourceDataID = _compiler.IncludeFile(data);
|
||||
result.SourceDataID = await _compiler.IncludeFile(data);
|
||||
Utils.Log($"Generated a {data.Length} byte patch for {filename}");
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,9 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
public class RawSourceFile
|
||||
{
|
||||
// ToDo
|
||||
// Make readonly
|
||||
public string Path;
|
||||
public readonly RelativePath Path;
|
||||
|
||||
public RawSourceFile(VirtualFile file, string path)
|
||||
public RawSourceFile(VirtualFile file, RelativePath path)
|
||||
{
|
||||
File = file;
|
||||
Path = path;
|
||||
@ -153,7 +151,7 @@ namespace Wabbajack.Lib
|
||||
/// location the file will be copied to, relative to the install path.
|
||||
/// </summary>
|
||||
[Key(2)]
|
||||
public string To { get; set; }
|
||||
public RelativePath To { get; set; }
|
||||
}
|
||||
|
||||
public class IgnoredDirectly : Directive
|
||||
@ -172,14 +170,14 @@ namespace Wabbajack.Lib
|
||||
/// Data that will be written as-is to the destination location;
|
||||
/// </summary>
|
||||
[Key(3)]
|
||||
public string SourceDataID;
|
||||
public RelativePath SourceDataID { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class ArchiveMeta : Directive
|
||||
{
|
||||
[Key(3)]
|
||||
public string SourceDataID { get; set; }
|
||||
public RelativePath SourceDataID { get; set; }
|
||||
}
|
||||
|
||||
public enum PropertyType { Banner, Readme }
|
||||
@ -218,7 +216,7 @@ namespace Wabbajack.Lib
|
||||
private string _fullPath;
|
||||
|
||||
[Key(3)]
|
||||
public string[] ArchiveHashPath { get; set; }
|
||||
public HashRelativePath ArchiveHashPath { get; set; }
|
||||
|
||||
[IgnoreMember]
|
||||
public VirtualFile FromFile { get; set; }
|
||||
@ -257,7 +255,7 @@ namespace Wabbajack.Lib
|
||||
[Key(0)]
|
||||
public Hash Hash { get; set; }
|
||||
[Key(1)]
|
||||
public string RelativePath { get; set; }
|
||||
public RelativePath RelativePath { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
|
@ -26,41 +26,41 @@ namespace Wabbajack.Lib
|
||||
public class MO2Compiler : ACompiler
|
||||
{
|
||||
|
||||
private string _mo2DownloadsFolder;
|
||||
private AbsolutePath _mo2DownloadsFolder;
|
||||
|
||||
public string MO2Folder;
|
||||
public AbsolutePath MO2Folder;
|
||||
|
||||
public string MO2Profile { get; }
|
||||
public Dictionary<string, dynamic> ModMetas { get; set; }
|
||||
|
||||
public override ModManager ModManager => ModManager.MO2;
|
||||
|
||||
public override string GamePath { get; }
|
||||
public override AbsolutePath GamePath { get; }
|
||||
|
||||
public GameMetaData CompilingGame { get; set; }
|
||||
|
||||
public override string ModListOutputFolder => "output_folder";
|
||||
public override AbsolutePath ModListOutputFolder => ((RelativePath)"output_folder").RelativeToEntryPoint();
|
||||
|
||||
public override string ModListOutputFile { get; }
|
||||
public override AbsolutePath ModListOutputFile { get; }
|
||||
|
||||
public override string VFSCacheName => Path.Combine(
|
||||
Consts.LocalAppDataPath,
|
||||
$"vfs_compile_cache-{Path.Combine(MO2Folder ?? "Unknown", "ModOrganizer.exe").StringSha256Hex()}.bin");
|
||||
public override AbsolutePath VFSCacheName =>
|
||||
Consts.LocalAppDataPath.Combine(
|
||||
$"vfs_compile_cache-{Path.Combine((string)MO2Folder ?? "Unknown", "ModOrganizer.exe").StringSha256Hex()}.bin");
|
||||
|
||||
public MO2Compiler(string mo2Folder, string mo2Profile, string outputFile)
|
||||
public MO2Compiler(AbsolutePath mo2Folder, string mo2Profile, AbsolutePath outputFile)
|
||||
{
|
||||
MO2Folder = mo2Folder;
|
||||
MO2Profile = mo2Profile;
|
||||
MO2Ini = Path.Combine(MO2Folder, "ModOrganizer.ini").LoadIniFile();
|
||||
MO2Ini = MO2Folder.Combine("ModOrganizer.ini").LoadIniFile();
|
||||
var mo2game = (string)MO2Ini.General.gameName;
|
||||
CompilingGame = GameRegistry.Games.First(g => g.Value.MO2Name == mo2game).Value;
|
||||
GamePath = ((string)MO2Ini.General.gamePath).Replace("\\\\", "\\");
|
||||
GamePath = new AbsolutePath((string)MO2Ini.General.gamePath.Replace("\\\\", "\\"));
|
||||
ModListOutputFile = outputFile;
|
||||
}
|
||||
|
||||
public dynamic MO2Ini { get; }
|
||||
|
||||
public string MO2DownloadsFolder
|
||||
public AbsolutePath MO2DownloadsFolder
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -74,9 +74,9 @@ namespace Wabbajack.Lib
|
||||
set => _mo2DownloadsFolder = value;
|
||||
}
|
||||
|
||||
public static string GetTypicalDownloadsFolder(string mo2Folder) => Path.Combine(mo2Folder, "downloads");
|
||||
public static AbsolutePath GetTypicalDownloadsFolder(AbsolutePath mo2Folder) => mo2Folder.Combine("downloads");
|
||||
|
||||
public string MO2ProfileDir => Path.Combine(MO2Folder, "profiles", MO2Profile);
|
||||
public AbsolutePath MO2ProfileDir => MO2Folder.Combine("profiles", MO2Profile);
|
||||
|
||||
internal UserStatus User { get; private set; }
|
||||
public ConcurrentBag<Directive> ExtraFiles { get; private set; }
|
||||
@ -91,9 +91,9 @@ namespace Wabbajack.Lib
|
||||
UpdateTracker.Reset();
|
||||
UpdateTracker.NextStep("Gathering information");
|
||||
Info("Looking for other profiles");
|
||||
var otherProfilesPath = Path.Combine(MO2ProfileDir, "otherprofiles.txt");
|
||||
var otherProfilesPath = MO2ProfileDir.Combine("otherprofiles.txt");
|
||||
SelectedProfiles = new HashSet<string>();
|
||||
if (File.Exists(otherProfilesPath)) SelectedProfiles = File.ReadAllLines(otherProfilesPath).ToHashSet();
|
||||
if (otherProfilesPath.Exists) SelectedProfiles = (await otherProfilesPath.ReadAllLinesAsync()).ToHashSet();
|
||||
SelectedProfiles.Add(MO2Profile);
|
||||
|
||||
Info("Using Profiles: " + string.Join(", ", SelectedProfiles.OrderBy(p => p)));
|
||||
|
@ -31,14 +31,14 @@ namespace Wabbajack.Lib
|
||||
public Game Game { get; }
|
||||
public string GameName { get; }
|
||||
|
||||
public string VortexFolder { get; set; }
|
||||
public string StagingFolder { get; set; }
|
||||
public string DownloadsFolder { get; set; }
|
||||
public AbsolutePath VortexFolder { get; set; }
|
||||
public AbsolutePath StagingFolder { get; set; }
|
||||
public AbsolutePath DownloadsFolder { get; set; }
|
||||
|
||||
public override ModManager ModManager => ModManager.Vortex;
|
||||
public override string GamePath { get; }
|
||||
public override string ModListOutputFolder => "output_folder";
|
||||
public override string ModListOutputFile { get; }
|
||||
public override AbsolutePath GamePath { get; }
|
||||
public override AbsolutePath ModListOutputFolder => ((RelativePath)"output_folder").RelativeToEntryPoint();
|
||||
public override AbsolutePath ModListOutputFile { get; }
|
||||
|
||||
public const string StagingMarkerName = "__vortex_staging_folder";
|
||||
public const string DownloadMarkerName = "__vortex_downloads_folder";
|
||||
|
@ -233,9 +233,12 @@ namespace Wabbajack.VirtualFileSystem
|
||||
#region KnownFiles
|
||||
|
||||
private List<HashRelativePath> _knownFiles = new List<HashRelativePath>();
|
||||
public void AddKnown(IEnumerable<HashRelativePath> known)
|
||||
private Dictionary<Hash, AbsolutePath> _knownArchives = new Dictionary<Hash, AbsolutePath>();
|
||||
public void AddKnown(IEnumerable<HashRelativePath> known, Dictionary<Hash, AbsolutePath> archives)
|
||||
{
|
||||
_knownFiles.AddRange(known);
|
||||
foreach (var (key, value) in archives)
|
||||
_knownArchives.TryAdd(key, value);
|
||||
}
|
||||
|
||||
public async Task BackfillMissing()
|
||||
|
Loading…
Reference in New Issue
Block a user