2019-10-26 19:52:42 +00:00
|
|
|
|
using System;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
using System.Collections.Generic;
|
2020-01-06 04:35:12 +00:00
|
|
|
|
using System.IO;
|
2019-11-20 23:39:03 +00:00
|
|
|
|
using System.Linq;
|
2020-06-27 17:04:59 +00:00
|
|
|
|
using Compression.BSA;
|
2020-04-06 20:48:54 +00:00
|
|
|
|
using Newtonsoft.Json;
|
2019-09-29 04:41:47 +00:00
|
|
|
|
using Wabbajack.Common;
|
2020-04-06 20:48:54 +00:00
|
|
|
|
using Wabbajack.Common.Serialization.Json;
|
2021-06-17 23:09:03 +00:00
|
|
|
|
using Wabbajack.ImageHashing;
|
2019-10-16 03:10:34 +00:00
|
|
|
|
using Wabbajack.Lib.Downloaders;
|
2019-11-15 13:06:34 +00:00
|
|
|
|
using Wabbajack.VirtualFileSystem;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2019-10-16 03:10:34 +00:00
|
|
|
|
namespace Wabbajack.Lib
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2019-09-14 04:35:42 +00:00
|
|
|
|
public class RawSourceFile
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public readonly RelativePath Path;
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public RawSourceFile(VirtualFile file, RelativePath path)
|
2019-08-20 04:57:08 +00:00
|
|
|
|
{
|
|
|
|
|
File = file;
|
2019-12-22 18:54:49 +00:00
|
|
|
|
Path = path;
|
2019-08-20 04:57:08 +00:00
|
|
|
|
}
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2020-04-17 03:52:19 +00:00
|
|
|
|
public AbsolutePath AbsolutePath
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (!File.IsNative)
|
|
|
|
|
throw new InvalidDataException("Can't get the absolute path of a non-native file");
|
|
|
|
|
return File.FullPath.Base;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-20 04:57:08 +00:00
|
|
|
|
|
2019-09-14 04:35:42 +00:00
|
|
|
|
public VirtualFile File { get; }
|
2019-08-20 04:57:08 +00:00
|
|
|
|
|
2020-03-22 15:50:53 +00:00
|
|
|
|
public Hash Hash => File.Hash;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
|
|
|
|
public T EvolveTo<T>() where T : Directive, new()
|
|
|
|
|
{
|
2021-06-17 23:09:03 +00:00
|
|
|
|
var v = new T {To = Path, Hash = File.Hash, Size = File.Size};
|
2019-07-21 04:40:54 +00:00
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("ModList")]
|
2019-07-21 04:40:54 +00:00
|
|
|
|
public class ModList
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// Archives required by this modlist
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public List<Archive> Archives = new List<Archive>();
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2019-11-03 13:54:49 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// Author of the ModList
|
2019-09-29 04:41:47 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string Author = string.Empty;
|
2019-09-29 04:41:47 +00:00
|
|
|
|
|
2019-10-23 16:13:41 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// Description of the ModList
|
2019-10-23 16:13:41 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string Description = string.Empty;
|
2019-10-23 16:13:41 +00:00
|
|
|
|
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// <summary>
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// Install directives
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public List<Directive> Directives = new List<Directive>();
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// The game variant to which this game applies
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public Game GameType;
|
2019-08-30 23:57:56 +00:00
|
|
|
|
|
2019-10-07 14:43:46 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// Hash of the banner-image
|
2019-10-07 14:43:46 +00:00
|
|
|
|
/// </summary>
|
2020-03-25 22:30:43 +00:00
|
|
|
|
public RelativePath Image;
|
2019-10-07 14:43:46 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// The Mod Manager used to create the modlist
|
2019-10-07 14:43:46 +00:00
|
|
|
|
/// </summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public ModManager ModManager;
|
2019-10-07 14:43:46 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// Name of the ModList
|
2019-10-07 14:43:46 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string Name = string.Empty;
|
2019-10-07 14:43:46 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-04-15 17:40:41 +00:00
|
|
|
|
/// URL to the readme
|
2019-10-07 14:43:46 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string Readme = string.Empty;
|
2019-10-07 14:43:46 +00:00
|
|
|
|
|
2019-11-20 23:39:03 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// The build version of Wabbajack used when compiling the Modlist
|
2019-11-20 23:39:03 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public Version? WabbajackVersion;
|
2019-11-20 23:39:03 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// Website of the ModList
|
2019-11-20 23:39:03 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public Uri? Website;
|
2019-11-20 23:39:03 +00:00
|
|
|
|
|
2020-04-16 14:15:03 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Current Version of the Modlist
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Version Version = new Version(1, 0, 0, 0);
|
|
|
|
|
|
2020-04-27 09:58:33 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether the Modlist is NSFW or not
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsNSFW;
|
|
|
|
|
|
2019-11-20 23:39:03 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// The size of all the archives once they're downloaded
|
2019-11-20 23:39:03 +00:00
|
|
|
|
/// </summary>
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonIgnore]
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public long DownloadSize => Archives.Sum(a => a.Size);
|
2019-11-20 23:39:03 +00:00
|
|
|
|
|
2019-12-20 20:01:01 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// The size of all the files once they are installed (excluding downloaded archives)
|
2019-12-20 20:01:01 +00:00
|
|
|
|
/// </summary>
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonIgnore]
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public long InstallSize => Directives.Sum(s => s.Size);
|
2020-01-06 04:35:12 +00:00
|
|
|
|
|
|
|
|
|
public ModList Clone()
|
|
|
|
|
{
|
2020-03-22 21:55:31 +00:00
|
|
|
|
using var ms = new MemoryStream();
|
2020-04-06 20:48:54 +00:00
|
|
|
|
this.ToJson(ms);
|
2020-03-22 21:55:31 +00:00
|
|
|
|
ms.Position = 0;
|
2020-04-06 20:48:54 +00:00
|
|
|
|
return ms.FromJson<ModList>();
|
2020-01-06 04:35:12 +00:00
|
|
|
|
}
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public abstract class Directive
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public Hash Hash { get; set; }
|
|
|
|
|
public long Size { get; set; }
|
|
|
|
|
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// <summary>
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// location the file will be copied to, relative to the install path.
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public RelativePath To { get; set; }
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class IgnoredDirectly : Directive
|
|
|
|
|
{
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string Reason = string.Empty;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class NoMatch : IgnoredDirectly
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("InlineFile")]
|
2019-07-21 04:40:54 +00:00
|
|
|
|
public class InlineFile : Directive
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// Data that will be written as-is to the destination location;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public RelativePath SourceDataID { get; set; }
|
2020-09-05 19:36:44 +00:00
|
|
|
|
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
public VirtualFile? SourceDataFile { get; set; }
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("ArchiveMeta")]
|
2019-11-04 04:36:25 +00:00
|
|
|
|
public class ArchiveMeta : Directive
|
|
|
|
|
{
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public RelativePath SourceDataID { get; set; }
|
2019-11-04 04:36:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-11 12:56:55 +00:00
|
|
|
|
public enum PropertyType { Banner, Readme }
|
2019-10-11 11:09:34 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// File meant to be extracted before the installation
|
|
|
|
|
/// </summary>
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("PropertyFile")]
|
2019-10-11 11:09:34 +00:00
|
|
|
|
public class PropertyFile : InlineFile
|
|
|
|
|
{
|
|
|
|
|
public PropertyType Type;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("CleanedESM")]
|
2019-08-25 03:46:32 +00:00
|
|
|
|
public class CleanedESM : InlineFile
|
|
|
|
|
{
|
2020-03-22 15:50:53 +00:00
|
|
|
|
public Hash SourceESMHash;
|
2019-08-25 03:46:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-24 23:20:54 +00:00
|
|
|
|
/// <summary>
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// A file that has the game and MO2 folders remapped on installation
|
2019-08-24 23:20:54 +00:00
|
|
|
|
/// </summary>
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("RemappedInlineFile")]
|
2019-08-24 23:20:54 +00:00
|
|
|
|
public class RemappedInlineFile : InlineFile
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("SteamMeta")]
|
2019-12-02 16:43:43 +00:00
|
|
|
|
public class SteamMeta : ArchiveMeta
|
|
|
|
|
{
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public int ItemID { get; set; }
|
2019-12-02 16:43:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("FromArchive")]
|
2019-07-21 04:40:54 +00:00
|
|
|
|
public class FromArchive : Directive
|
|
|
|
|
{
|
2020-04-10 01:29:53 +00:00
|
|
|
|
private string? _fullPath;
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public HashRelativePath ArchiveHashPath { get; set; }
|
2019-08-20 04:57:08 +00:00
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonIgnore]
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public VirtualFile? FromFile { get; set; }
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonIgnore]
|
2020-03-22 15:50:53 +00:00
|
|
|
|
public string FullPath => _fullPath ??= string.Join("|", ArchiveHashPath);
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("CreateBSA")]
|
2019-07-26 20:59:14 +00:00
|
|
|
|
public class CreateBSA : Directive
|
|
|
|
|
{
|
2020-03-25 22:30:43 +00:00
|
|
|
|
public RelativePath TempID { get; set; }
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public ArchiveStateObject State { get; }
|
|
|
|
|
public List<FileStateObject> FileStates { get; set; } = new List<FileStateObject>();
|
|
|
|
|
|
|
|
|
|
public CreateBSA(ArchiveStateObject state, IEnumerable<FileStateObject>? items = null)
|
|
|
|
|
{
|
|
|
|
|
State = state;
|
|
|
|
|
if (items != null)
|
|
|
|
|
{
|
|
|
|
|
FileStates.AddRange(items);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-26 20:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("PatchedFromArchive")]
|
2019-07-21 22:47:17 +00:00
|
|
|
|
public class PatchedFromArchive : FromArchive
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public Hash FromHash { get; set; }
|
|
|
|
|
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// <summary>
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// The file to apply to the source file to patch it
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-03-25 22:30:43 +00:00
|
|
|
|
public RelativePath PatchID { get; set; }
|
2020-06-30 23:09:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// During compilation this holds several possible files that could be used as a patch source. At the end
|
|
|
|
|
/// of compilation we'll go through all of these and find the smallest patch file.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
public VirtualFile[] Choices { get; set; } = { };
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
2021-06-17 23:09:03 +00:00
|
|
|
|
|
|
|
|
|
[JsonName("TransformedTexture")]
|
|
|
|
|
public class TransformedTexture : FromArchive
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The file to apply to the source file to patch it
|
|
|
|
|
/// </summary>
|
|
|
|
|
public ImageState ImageState { get; set; } = new();
|
|
|
|
|
}
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("SourcePatch")]
|
2019-09-23 21:37:10 +00:00
|
|
|
|
public class SourcePatch
|
|
|
|
|
{
|
2020-03-22 21:55:31 +00:00
|
|
|
|
public Hash Hash { get; set; }
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public RelativePath RelativePath { get; set; }
|
2019-09-23 21:37:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("MergedPatch")]
|
2019-09-23 21:37:10 +00:00
|
|
|
|
public class MergedPatch : Directive
|
|
|
|
|
{
|
2020-03-25 22:30:43 +00:00
|
|
|
|
public RelativePath PatchID { get; set; }
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public List<SourcePatch> Sources { get; set; } = new List<SourcePatch>();
|
2019-09-23 21:37:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-06 20:48:54 +00:00
|
|
|
|
[JsonName("Archive")]
|
2019-07-21 04:40:54 +00:00
|
|
|
|
public class Archive
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2020-03-27 03:10:23 +00:00
|
|
|
|
/// xxHash64 of the archive
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
2020-03-22 15:50:53 +00:00
|
|
|
|
public Hash Hash { get; set; }
|
2019-07-21 22:47:17 +00:00
|
|
|
|
|
2019-11-04 12:53:02 +00:00
|
|
|
|
/// <summary>
|
2020-03-22 21:55:31 +00:00
|
|
|
|
/// Meta INI for the downloaded archive
|
2019-07-21 22:47:17 +00:00
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string? Meta { get; set; }
|
2019-09-10 13:02:25 +00:00
|
|
|
|
|
2019-09-14 04:35:42 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Human friendly name of this archive
|
|
|
|
|
/// </summary>
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public string Name { get; set; } = string.Empty;
|
2019-09-14 04:35:42 +00:00
|
|
|
|
|
2019-12-30 04:35:54 +00:00
|
|
|
|
public long Size { get; set; }
|
2020-03-22 21:55:31 +00:00
|
|
|
|
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public AbstractDownloadState State { get; }
|
2019-08-02 22:31:13 +00:00
|
|
|
|
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public Archive(AbstractDownloadState state)
|
|
|
|
|
{
|
|
|
|
|
State = state;
|
|
|
|
|
}
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public class IndexedArchive
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public dynamic? IniData;
|
|
|
|
|
public string Meta = string.Empty;
|
|
|
|
|
public string Name = string.Empty;
|
|
|
|
|
public VirtualFile File { get; }
|
2020-06-20 23:10:43 +00:00
|
|
|
|
public AbstractDownloadState? State { get; set; }
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2020-04-10 01:29:53 +00:00
|
|
|
|
public IndexedArchive(VirtualFile file)
|
|
|
|
|
{
|
|
|
|
|
File = file;
|
|
|
|
|
}
|
2019-08-09 04:07:23 +00:00
|
|
|
|
}
|
2019-11-20 23:39:03 +00:00
|
|
|
|
}
|