2020-10-01 03:50:09 +00:00
|
|
|
|
using System;
|
2019-07-26 20:59:14 +00:00
|
|
|
|
using System.Collections.Concurrent;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2019-12-03 21:56:18 +00:00
|
|
|
|
using System.Threading;
|
2019-11-12 04:35:07 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
using Wabbajack.Common;
|
2019-10-30 12:29:06 +00:00
|
|
|
|
using Wabbajack.Lib.CompilationSteps;
|
2020-01-22 03:43:53 +00:00
|
|
|
|
using Wabbajack.Lib.Downloaders;
|
2019-10-16 03:10:34 +00:00
|
|
|
|
using Wabbajack.Lib.Validation;
|
2020-09-05 14:01:32 +00:00
|
|
|
|
using Wabbajack.VirtualFileSystem;
|
2019-09-18 21:33:23 +00:00
|
|
|
|
using Path = Alphaleonis.Win32.Filesystem.Path;
|
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-11-18 00:17:06 +00:00
|
|
|
|
public class MO2Compiler : ACompiler
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2020-03-25 12:47:25 +00:00
|
|
|
|
private AbsolutePath _mo2DownloadsFolder;
|
2019-11-15 13:06:34 +00:00
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public AbsolutePath MO2Folder;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2020-03-25 23:15:19 +00:00
|
|
|
|
public AbsolutePath MO2ModsFolder => MO2Folder.Combine(Consts.MO2ModFolderName);
|
|
|
|
|
|
2019-11-24 00:30:51 +00:00
|
|
|
|
public string MO2Profile { get; }
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2019-11-24 00:30:51 +00:00
|
|
|
|
public override ModManager ModManager => ModManager.MO2;
|
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public override AbsolutePath GamePath { get; }
|
2019-11-24 00:30:51 +00:00
|
|
|
|
|
2020-04-09 21:05:07 +00:00
|
|
|
|
public GameMetaData CompilingGame { get; }
|
2020-09-11 12:54:24 +00:00
|
|
|
|
|
|
|
|
|
public CompilerSettings Settings { get; set; }
|
2019-12-10 12:26:49 +00:00
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public override AbsolutePath ModListOutputFolder => ((RelativePath)"output_folder").RelativeToEntryPoint();
|
2019-11-03 16:43:43 +00:00
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public override AbsolutePath ModListOutputFile { get; }
|
2019-11-24 00:30:51 +00:00
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public override AbsolutePath VFSCacheName =>
|
|
|
|
|
Consts.LocalAppDataPath.Combine(
|
2020-04-21 12:40:17 +00:00
|
|
|
|
$"vfs_compile_cache-2-{Path.Combine((string)MO2Folder ?? "Unknown", "ModOrganizer.exe").StringSha256Hex()}.bin");
|
2020-02-24 15:24:13 +00:00
|
|
|
|
|
2020-04-09 21:05:07 +00:00
|
|
|
|
public dynamic MO2Ini { get; }
|
|
|
|
|
|
|
|
|
|
public static AbsolutePath GetTypicalDownloadsFolder(AbsolutePath mo2Folder) => mo2Folder.Combine("downloads");
|
|
|
|
|
|
|
|
|
|
public AbsolutePath MO2ProfileDir => MO2Folder.Combine("profiles", MO2Profile);
|
|
|
|
|
|
2020-04-12 18:55:59 +00:00
|
|
|
|
public ConcurrentBag<Directive> ExtraFiles { get; private set; } = new ConcurrentBag<Directive>();
|
2020-04-09 21:05:07 +00:00
|
|
|
|
public Dictionary<AbsolutePath, dynamic> ModInis { get; } = new Dictionary<AbsolutePath, dynamic>();
|
|
|
|
|
|
|
|
|
|
public HashSet<string> SelectedProfiles { get; set; } = new HashSet<string>();
|
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public MO2Compiler(AbsolutePath mo2Folder, string mo2Profile, AbsolutePath outputFile)
|
2020-09-05 19:36:44 +00:00
|
|
|
|
: base(steps: 21)
|
2019-11-24 00:30:51 +00:00
|
|
|
|
{
|
2019-11-21 15:51:57 +00:00
|
|
|
|
MO2Folder = mo2Folder;
|
2019-11-24 00:30:51 +00:00
|
|
|
|
MO2Profile = mo2Profile;
|
2020-03-25 12:47:25 +00:00
|
|
|
|
MO2Ini = MO2Folder.Combine("ModOrganizer.ini").LoadIniFile();
|
2019-12-10 12:26:49 +00:00
|
|
|
|
var mo2game = (string)MO2Ini.General.gameName;
|
|
|
|
|
CompilingGame = GameRegistry.Games.First(g => g.Value.MO2Name == mo2game).Value;
|
2020-03-25 12:47:25 +00:00
|
|
|
|
GamePath = new AbsolutePath((string)MO2Ini.General.gamePath.Replace("\\\\", "\\"));
|
2019-11-24 00:30:51 +00:00
|
|
|
|
ModListOutputFile = outputFile;
|
2020-09-11 12:54:24 +00:00
|
|
|
|
Settings = new CompilerSettings();
|
2019-09-12 23:44:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 12:47:25 +00:00
|
|
|
|
public AbsolutePath MO2DownloadsFolder
|
2019-07-22 22:17:46 +00:00
|
|
|
|
{
|
2019-07-21 04:40:54 +00:00
|
|
|
|
get
|
|
|
|
|
{
|
2020-03-28 02:54:14 +00:00
|
|
|
|
if (_mo2DownloadsFolder != default) return _mo2DownloadsFolder;
|
2019-09-03 22:12:39 +00:00
|
|
|
|
if (MO2Ini != null)
|
|
|
|
|
if (MO2Ini.Settings != null)
|
|
|
|
|
if (MO2Ini.Settings.download_directory != null)
|
|
|
|
|
return MO2Ini.Settings.download_directory.Replace("/", "\\");
|
2019-11-24 00:36:57 +00:00
|
|
|
|
return GetTypicalDownloadsFolder(MO2Folder);
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
2019-09-03 22:12:39 +00:00
|
|
|
|
set => _mo2DownloadsFolder = value;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 01:26:26 +00:00
|
|
|
|
protected override async Task<bool> _Begin(CancellationToken cancel)
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2020-06-14 13:13:29 +00:00
|
|
|
|
await Metrics.Send("begin_compiling", MO2Profile ?? "unknown");
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2020-09-12 20:23:03 +00:00
|
|
|
|
|
|
|
|
|
DesiredThreads.OnNext(DiskThreads);
|
|
|
|
|
FileExtractor2.FavorPerfOverRAM = FavorPerfOverRam;
|
|
|
|
|
|
2019-11-17 04:16:42 +00:00
|
|
|
|
UpdateTracker.Reset();
|
|
|
|
|
UpdateTracker.NextStep("Gathering information");
|
2020-09-11 12:54:24 +00:00
|
|
|
|
|
|
|
|
|
Utils.Log($"Loading compiler Settings");
|
|
|
|
|
Settings = await CompilerSettings.Load(MO2ProfileDir);
|
|
|
|
|
Settings.IncludedGames = Settings.IncludedGames.Add(CompilingGame.Game);
|
|
|
|
|
|
2019-09-12 23:44:35 +00:00
|
|
|
|
Info("Looking for other profiles");
|
2020-03-25 12:47:25 +00:00
|
|
|
|
var otherProfilesPath = MO2ProfileDir.Combine("otherprofiles.txt");
|
2019-09-07 04:57:49 +00:00
|
|
|
|
SelectedProfiles = new HashSet<string>();
|
2020-03-25 12:47:25 +00:00
|
|
|
|
if (otherProfilesPath.Exists) SelectedProfiles = (await otherProfilesPath.ReadAllLinesAsync()).ToHashSet();
|
2020-05-13 14:06:18 +00:00
|
|
|
|
SelectedProfiles.Add(MO2Profile!);
|
2019-09-03 21:17:00 +00:00
|
|
|
|
|
2019-09-12 23:44:35 +00:00
|
|
|
|
Info("Using Profiles: " + string.Join(", ", SelectedProfiles.OrderBy(p => p)));
|
2019-09-03 21:17:00 +00:00
|
|
|
|
|
2020-02-15 13:12:06 +00:00
|
|
|
|
Utils.Log($"VFS File Location: {VFSCacheName}");
|
2020-07-14 12:15:01 +00:00
|
|
|
|
Utils.Log($"MO2 Folder: {MO2Folder}");
|
|
|
|
|
Utils.Log($"Downloads Folder: {MO2DownloadsFolder}");
|
|
|
|
|
Utils.Log($"Game Folder: {GamePath}");
|
2020-07-27 21:33:45 +00:00
|
|
|
|
|
|
|
|
|
var watcher = new DiskSpaceWatcher(cancel, new []{MO2Folder, MO2DownloadsFolder, GamePath, AbsolutePath.EntryPoint}, (long)2 << 31,
|
|
|
|
|
drive =>
|
|
|
|
|
{
|
|
|
|
|
Utils.Log($"Aborting due to low space on {drive.Name}");
|
|
|
|
|
Abort();
|
|
|
|
|
});
|
|
|
|
|
var watcherTask = watcher.Start();
|
2020-02-15 13:12:06 +00:00
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2020-06-02 02:18:32 +00:00
|
|
|
|
|
|
|
|
|
List<AbsolutePath> roots;
|
|
|
|
|
if (UseGamePaths)
|
2019-11-22 05:19:42 +00:00
|
|
|
|
{
|
2020-06-02 02:18:32 +00:00
|
|
|
|
roots = new List<AbsolutePath>
|
|
|
|
|
{
|
2020-06-20 22:51:47 +00:00
|
|
|
|
MO2Folder, GamePath, MO2DownloadsFolder
|
2020-06-02 02:18:32 +00:00
|
|
|
|
};
|
2020-09-11 12:54:24 +00:00
|
|
|
|
roots.AddRange(Settings.IncludedGames.Select(g => g.MetaData().GameLocation()));
|
2020-06-02 02:18:32 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
roots = new List<AbsolutePath>
|
|
|
|
|
{
|
|
|
|
|
MO2Folder, MO2DownloadsFolder
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-22 05:19:42 +00:00
|
|
|
|
// TODO: make this generic so we can add more paths
|
2019-11-15 23:13:27 +00:00
|
|
|
|
|
2020-03-25 22:49:32 +00:00
|
|
|
|
var lootPath = (AbsolutePath)Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
2019-11-22 05:19:42 +00:00
|
|
|
|
"LOOT");
|
|
|
|
|
IEnumerable<RawSourceFile> lootFiles = new List<RawSourceFile>();
|
2020-03-25 22:49:32 +00:00
|
|
|
|
if (lootPath.Exists)
|
2019-11-22 05:19:42 +00:00
|
|
|
|
{
|
2020-03-25 22:49:32 +00:00
|
|
|
|
roots.Add((AbsolutePath)lootPath);
|
2019-11-22 05:19:42 +00:00
|
|
|
|
}
|
|
|
|
|
UpdateTracker.NextStep("Indexing folders");
|
2019-09-03 22:12:39 +00:00
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-12-04 01:26:26 +00:00
|
|
|
|
await VFS.AddRoots(roots);
|
2019-11-22 05:19:42 +00:00
|
|
|
|
|
2020-03-25 22:49:32 +00:00
|
|
|
|
if (lootPath.Exists)
|
2019-11-22 05:19:42 +00:00
|
|
|
|
{
|
2020-04-09 21:05:07 +00:00
|
|
|
|
if (CompilingGame.MO2Name == null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Compiling game had no MO2 name specified.");
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 15:46:42 +00:00
|
|
|
|
var lootGameDirs = new []
|
|
|
|
|
{
|
|
|
|
|
CompilingGame.MO2Name, // most of the games use the MO2 name
|
|
|
|
|
CompilingGame.MO2Name.Replace(" ", "") //eg: Fallout 4 -> Fallout4
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-03 22:56:14 +00:00
|
|
|
|
var lootGameDir = lootGameDirs.Select(x => lootPath.Combine(x))
|
|
|
|
|
.FirstOrDefault(p => p.IsDirectory);
|
2020-04-02 15:46:42 +00:00
|
|
|
|
|
2020-04-03 22:56:14 +00:00
|
|
|
|
if (lootGameDir != default)
|
2020-04-02 15:46:42 +00:00
|
|
|
|
{
|
|
|
|
|
Utils.Log($"Found LOOT game folder at {lootGameDir}");
|
2020-04-03 22:56:14 +00:00
|
|
|
|
lootFiles = lootGameDir.EnumerateFiles(false)
|
|
|
|
|
.Where(p => p.FileName == (RelativePath)"userlist.yaml")
|
|
|
|
|
.Where(p => p.IsFile)
|
2020-04-02 15:46:42 +00:00
|
|
|
|
.Select(p => new RawSourceFile(VFS.Index.ByRootPath[p],
|
2020-04-03 22:56:14 +00:00
|
|
|
|
Consts.LOOTFolderFilesDir.Combine(p.RelativeTo(lootPath))));
|
2020-04-02 15:46:42 +00:00
|
|
|
|
|
|
|
|
|
if (!lootFiles.Any())
|
|
|
|
|
Utils.Log(
|
|
|
|
|
$"Found no LOOT user data for {CompilingGame.HumanFriendlyGameName} at {lootGameDir}!");
|
|
|
|
|
}
|
2019-11-22 05:19:42 +00:00
|
|
|
|
}
|
2020-02-14 13:30:58 +00:00
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-11-17 04:16:42 +00:00
|
|
|
|
UpdateTracker.NextStep("Cleaning output folder");
|
2020-03-28 04:33:26 +00:00
|
|
|
|
await ModListOutputFolder.DeleteDirectory();
|
2020-02-19 13:42:21 +00:00
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-12-10 12:26:49 +00:00
|
|
|
|
UpdateTracker.NextStep("Inferring metas for game file downloads");
|
2019-12-13 00:40:21 +00:00
|
|
|
|
await InferMetas();
|
2019-11-15 23:13:27 +00:00
|
|
|
|
|
2019-12-13 00:40:21 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-12-10 12:26:49 +00:00
|
|
|
|
UpdateTracker.NextStep("Reindexing downloads after meta inferring");
|
2019-12-13 00:40:21 +00:00
|
|
|
|
await VFS.AddRoot(MO2DownloadsFolder);
|
2020-07-07 20:17:49 +00:00
|
|
|
|
|
2019-12-13 00:40:21 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-12-12 23:24:27 +00:00
|
|
|
|
UpdateTracker.NextStep("Pre-validating Archives");
|
2020-02-14 13:30:58 +00:00
|
|
|
|
|
2019-09-24 04:34:21 +00:00
|
|
|
|
|
2020-05-02 21:09:29 +00:00
|
|
|
|
// Find all Downloads
|
2020-03-25 22:49:32 +00:00
|
|
|
|
IndexedArchives = (await MO2DownloadsFolder.EnumerateFiles()
|
|
|
|
|
.Where(f => f.WithExtension(Consts.MetaFileExtension).Exists)
|
2020-04-10 01:29:53 +00:00
|
|
|
|
.PMap(Queue, async f => new IndexedArchive(VFS.Index.ByRootPath[f])
|
2019-09-12 23:44:35 +00:00
|
|
|
|
{
|
2020-03-25 22:49:32 +00:00
|
|
|
|
Name = (string)f.FileName,
|
|
|
|
|
IniData = f.WithExtension(Consts.MetaFileExtension).LoadIniFile(),
|
|
|
|
|
Meta = await f.WithExtension(Consts.MetaFileExtension).ReadAllTextAsync()
|
|
|
|
|
})).ToList();
|
2020-05-02 21:09:29 +00:00
|
|
|
|
|
|
|
|
|
|
2020-06-20 22:51:47 +00:00
|
|
|
|
if (UseGamePaths)
|
2020-05-02 21:09:29 +00:00
|
|
|
|
{
|
2020-09-11 12:54:24 +00:00
|
|
|
|
foreach (var ag in Settings.IncludedGames)
|
2020-05-02 21:09:29 +00:00
|
|
|
|
{
|
2020-07-05 10:15:31 +00:00
|
|
|
|
try
|
2020-06-11 16:18:21 +00:00
|
|
|
|
{
|
2020-07-05 10:15:31 +00:00
|
|
|
|
var files = await ClientAPI.GetExistingGameFiles(Queue, ag);
|
|
|
|
|
Utils.Log($"Including {files.Length} stock game files from {ag} as download sources");
|
2020-08-18 22:30:00 +00:00
|
|
|
|
GameHashes[ag] = files.Select(f => f.Hash).ToHashSet();
|
2020-07-05 10:15:31 +00:00
|
|
|
|
|
|
|
|
|
IndexedArchives.AddRange(files.Select(f =>
|
2020-06-20 22:51:47 +00:00
|
|
|
|
{
|
2020-07-05 10:15:31 +00:00
|
|
|
|
var meta = f.State.GetMetaIniString();
|
|
|
|
|
var ini = meta.LoadIniString();
|
|
|
|
|
var state = (GameFileSourceDownloader.State)f.State;
|
|
|
|
|
return new IndexedArchive(
|
|
|
|
|
VFS.Index.ByRootPath[ag.MetaData().GameLocation().Combine(state.GameFile)])
|
|
|
|
|
{
|
|
|
|
|
IniData = ini, Meta = meta,
|
|
|
|
|
};
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Utils.Error(e, "Unable to find existing game files, skipping.");
|
|
|
|
|
}
|
2020-05-02 21:09:29 +00:00
|
|
|
|
}
|
2020-08-18 22:30:00 +00:00
|
|
|
|
|
|
|
|
|
GamesWithHashes = GameHashes.SelectMany(g => g.Value.Select(h => (g, h)))
|
|
|
|
|
.GroupBy(gh => gh.h)
|
|
|
|
|
.ToDictionary(gh => gh.Key, gh => gh.Select(p => p.g.Key).ToArray());
|
2020-05-02 21:09:29 +00:00
|
|
|
|
}
|
2020-06-11 16:18:21 +00:00
|
|
|
|
|
2020-06-20 23:10:43 +00:00
|
|
|
|
IndexedArchives = IndexedArchives.DistinctBy(a => a.File.AbsoluteName).ToList();
|
|
|
|
|
|
|
|
|
|
await CleanInvalidArchivesAndFillState();
|
2019-12-12 23:24:27 +00:00
|
|
|
|
|
|
|
|
|
UpdateTracker.NextStep("Finding Install Files");
|
2020-03-25 22:49:32 +00:00
|
|
|
|
ModListOutputFolder.CreateDirectory();
|
2019-12-12 23:24:27 +00:00
|
|
|
|
|
2020-03-25 22:49:32 +00:00
|
|
|
|
var mo2Files = MO2Folder.EnumerateFiles()
|
|
|
|
|
.Where(p => p.IsFile)
|
2020-01-26 04:50:17 +00:00
|
|
|
|
.Select(p =>
|
|
|
|
|
{
|
2020-03-25 22:49:32 +00:00
|
|
|
|
if (!VFS.Index.ByRootPath.ContainsKey(p))
|
2020-01-26 04:50:17 +00:00
|
|
|
|
Utils.Log($"WELL THERE'S YOUR PROBLEM: {p} {VFS.Index.ByRootPath.Count}");
|
|
|
|
|
|
|
|
|
|
return new RawSourceFile(VFS.Index.ByRootPath[p], p.RelativeTo(MO2Folder));
|
|
|
|
|
});
|
2019-12-12 23:24:27 +00:00
|
|
|
|
|
2020-01-07 05:23:59 +00:00
|
|
|
|
// If Game Folder Files exists, ignore the game folder
|
2019-11-15 13:06:34 +00:00
|
|
|
|
IndexedFiles = IndexedArchives.SelectMany(f => f.File.ThisAndAllChildren)
|
|
|
|
|
.OrderBy(f => f.NestingFactor)
|
2019-09-12 23:44:35 +00:00
|
|
|
|
.GroupBy(f => f.Hash)
|
|
|
|
|
.ToDictionary(f => f.Key, f => f.AsEnumerable());
|
2019-08-15 04:30:37 +00:00
|
|
|
|
|
2020-07-07 20:17:49 +00:00
|
|
|
|
AllFiles.SetTo(mo2Files
|
2019-11-21 15:51:57 +00:00
|
|
|
|
.Concat(lootFiles)
|
2020-04-09 21:05:07 +00:00
|
|
|
|
.DistinctBy(f => f.Path));
|
2019-08-15 04:30:37 +00:00
|
|
|
|
|
2019-09-26 22:32:15 +00:00
|
|
|
|
Info($"Found {AllFiles.Count} files to build into mod list");
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Verifying destinations");
|
|
|
|
|
|
2019-09-30 23:39:41 +00:00
|
|
|
|
var dups = AllFiles.GroupBy(f => f.Path)
|
|
|
|
|
.Where(fs => fs.Count() > 1)
|
|
|
|
|
.Select(fs =>
|
|
|
|
|
{
|
|
|
|
|
Utils.Log($"Duplicate files installed to {fs.Key} from : {String.Join(", ", fs.Select(f => f.AbsolutePath))}");
|
|
|
|
|
return fs;
|
|
|
|
|
}).ToList();
|
|
|
|
|
|
|
|
|
|
if (dups.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
Error($"Found {dups.Count} duplicates, exiting");
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Loading INIs");
|
|
|
|
|
|
2020-04-09 21:05:07 +00:00
|
|
|
|
ModInis.SetTo(MO2Folder.Combine(Consts.MO2ModFolderName)
|
2020-03-25 23:15:19 +00:00
|
|
|
|
.EnumerateDirectories()
|
2019-09-12 23:44:35 +00:00
|
|
|
|
.Select(f =>
|
|
|
|
|
{
|
2020-03-25 23:15:19 +00:00
|
|
|
|
var modName = f.FileName;
|
|
|
|
|
var metaPath = f.Combine("meta.ini");
|
2020-03-28 18:22:53 +00:00
|
|
|
|
return metaPath.Exists ? (mod_name: f, metaPath.LoadIniFile()) : default;
|
2019-09-12 23:44:35 +00:00
|
|
|
|
})
|
2020-03-28 18:22:53 +00:00
|
|
|
|
.Where(f => f.Item1 != default)
|
2020-04-09 21:05:07 +00:00
|
|
|
|
.Select(f => new KeyValuePair<AbsolutePath, dynamic>(f.Item1, f.Item2)));
|
2019-08-11 22:57:32 +00:00
|
|
|
|
|
2020-06-20 23:10:43 +00:00
|
|
|
|
ArchivesByFullPath = IndexedArchives.ToDictionary(a => a.File.AbsoluteName);
|
|
|
|
|
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-08-20 04:57:08 +00:00
|
|
|
|
var stack = MakeStack();
|
2019-11-17 04:16:42 +00:00
|
|
|
|
UpdateTracker.NextStep("Running Compilation Stack");
|
2019-12-04 01:26:26 +00:00
|
|
|
|
var results = await AllFiles.PMap(Queue, UpdateTracker, f => RunStack(stack, f));
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2019-07-26 20:59:14 +00:00
|
|
|
|
// Add the extra files that were generated by the stack
|
2019-12-03 21:56:18 +00:00
|
|
|
|
if (cancel.IsCancellationRequested) return false;
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep($"Adding {ExtraFiles.Count} that were generated by the stack");
|
2019-12-04 01:26:26 +00:00
|
|
|
|
results = results.Concat(ExtraFiles).ToArray();
|
2019-07-26 20:59:14 +00:00
|
|
|
|
|
2020-01-20 01:36:09 +00:00
|
|
|
|
var noMatch = results.OfType<NoMatch>().ToArray();
|
|
|
|
|
PrintNoMatches(noMatch);
|
|
|
|
|
if (CheckForNoMatchExit(noMatch)) return false;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
2020-07-27 21:33:45 +00:00
|
|
|
|
foreach (var ignored in results.OfType<IgnoredDirectly>())
|
|
|
|
|
{
|
|
|
|
|
Utils.Log($"Ignored {ignored.To} because {ignored.Reason}");
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-09 21:05:07 +00:00
|
|
|
|
InstallDirectives.SetTo(results.Where(i => !(i is IgnoredDirectly)));
|
2019-07-21 22:47:17 +00:00
|
|
|
|
|
2019-09-24 15:26:44 +00:00
|
|
|
|
Info("Getting Nexus api_key, please click authorize if a browser window appears");
|
2019-08-09 21:13:02 +00:00
|
|
|
|
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Verifying Files");
|
2019-09-23 21:37:10 +00:00
|
|
|
|
zEditIntegration.VerifyMerges(this);
|
2019-08-05 23:58:42 +00:00
|
|
|
|
|
2020-06-30 23:09:59 +00:00
|
|
|
|
UpdateTracker.NextStep("Building Patches");
|
|
|
|
|
await BuildPatches();
|
|
|
|
|
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Gathering Archives");
|
2019-12-04 01:26:26 +00:00
|
|
|
|
await GatherArchives();
|
2020-02-14 13:30:58 +00:00
|
|
|
|
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Including Archive Metadata");
|
2019-12-07 07:22:54 +00:00
|
|
|
|
await IncludeArchiveMetadata();
|
2019-07-23 04:27:26 +00:00
|
|
|
|
|
2020-03-04 12:10:49 +00:00
|
|
|
|
UpdateTracker.NextStep("Gathering Metadata");
|
|
|
|
|
await GatherMetaData();
|
|
|
|
|
|
2019-09-12 23:44:35 +00:00
|
|
|
|
ModList = new ModList
|
2019-07-23 04:27:26 +00:00
|
|
|
|
{
|
2019-12-10 12:26:49 +00:00
|
|
|
|
GameType = CompilingGame.Game,
|
2020-08-21 02:45:15 +00:00
|
|
|
|
WabbajackVersion = Consts.CurrentWabbajackVersion,
|
2019-12-03 21:13:29 +00:00
|
|
|
|
Archives = SelectedArchives.ToList(),
|
2019-11-03 16:43:43 +00:00
|
|
|
|
ModManager = ModManager.MO2,
|
2019-08-02 23:04:04 +00:00
|
|
|
|
Directives = InstallDirectives,
|
2020-05-13 14:06:18 +00:00
|
|
|
|
Name = ModListName ?? MO2Profile!,
|
2019-10-07 14:44:28 +00:00
|
|
|
|
Author = ModListAuthor ?? "",
|
|
|
|
|
Description = ModListDescription ?? "",
|
2020-04-15 17:40:41 +00:00
|
|
|
|
Readme = ModlistReadme ?? "",
|
2020-03-28 02:54:14 +00:00
|
|
|
|
Image = ModListImage != default ? ModListImage.FileName : default,
|
2020-04-27 09:58:33 +00:00
|
|
|
|
Website = !string.IsNullOrWhiteSpace(ModListWebsite) ? new Uri(ModListWebsite) : null,
|
2020-05-05 14:38:06 +00:00
|
|
|
|
Version = ModlistVersion ?? new Version(1,0,0,0),
|
2020-04-27 09:58:33 +00:00
|
|
|
|
IsNSFW = ModlistIsNSFW
|
2019-07-23 04:27:26 +00:00
|
|
|
|
};
|
2020-09-05 19:36:44 +00:00
|
|
|
|
|
|
|
|
|
UpdateTracker.NextStep("Including required files");
|
|
|
|
|
await InlineFiles();
|
2019-07-23 04:27:26 +00:00
|
|
|
|
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Running Validation");
|
|
|
|
|
|
2020-03-22 15:50:53 +00:00
|
|
|
|
await ValidateModlist.RunValidation(ModList);
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Generating Report");
|
2019-09-30 23:39:41 +00:00
|
|
|
|
|
2020-02-01 12:13:12 +00:00
|
|
|
|
GenerateManifest();
|
2019-11-24 23:03:36 +00:00
|
|
|
|
|
|
|
|
|
UpdateTracker.NextStep("Exporting Modlist");
|
2020-04-01 23:59:22 +00:00
|
|
|
|
await ExportModList();
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2019-07-23 04:27:26 +00:00
|
|
|
|
ResetMembers();
|
|
|
|
|
|
2019-11-24 23:03:36 +00:00
|
|
|
|
UpdateTracker.NextStep("Done Building Modlist");
|
|
|
|
|
|
2019-09-24 04:20:24 +00:00
|
|
|
|
return true;
|
2019-07-21 04:40:54 +00:00
|
|
|
|
}
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2020-08-18 22:30:00 +00:00
|
|
|
|
public Dictionary<Game, HashSet<Hash>> GameHashes { get; set; } = new Dictionary<Game, HashSet<Hash>>();
|
|
|
|
|
public Dictionary<Hash, Game[]> GamesWithHashes { get; set; } = new Dictionary<Hash, Game[]>();
|
|
|
|
|
|
2020-06-02 02:18:32 +00:00
|
|
|
|
public bool UseGamePaths { get; set; } = true;
|
|
|
|
|
|
2020-06-20 23:10:43 +00:00
|
|
|
|
private async Task CleanInvalidArchivesAndFillState()
|
2019-12-12 23:24:27 +00:00
|
|
|
|
{
|
2019-12-13 00:40:21 +00:00
|
|
|
|
var remove = (await IndexedArchives.PMap(Queue, async a =>
|
2019-12-12 23:24:27 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-06-20 23:10:43 +00:00
|
|
|
|
a.State = (await ResolveArchive(a)).State;
|
2019-12-12 23:24:27 +00:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return a;
|
|
|
|
|
}
|
2020-04-09 21:05:07 +00:00
|
|
|
|
})).NotNull().ToHashSet();
|
2019-12-12 23:24:27 +00:00
|
|
|
|
|
|
|
|
|
if (remove.Count == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Utils.Log(
|
|
|
|
|
$"Removing {remove.Count} archives from the compilation state, this is probably not an issue but reference this if you have compilation failures");
|
2020-07-16 02:53:58 +00:00
|
|
|
|
remove.Do(r => Utils.Log($"Resolution failed for: ({r.File.Size} {r.File.Hash}) {r.File.FullPath}"));
|
2019-12-12 23:24:27 +00:00
|
|
|
|
IndexedArchives.RemoveAll(a => remove.Contains(a));
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-13 00:40:21 +00:00
|
|
|
|
private async Task InferMetas()
|
2019-12-10 12:26:49 +00:00
|
|
|
|
{
|
2020-03-25 23:15:19 +00:00
|
|
|
|
async Task<bool> HasInvalidMeta(AbsolutePath filename)
|
2020-01-22 03:43:53 +00:00
|
|
|
|
{
|
2020-03-25 23:15:19 +00:00
|
|
|
|
var metaname = filename.WithExtension(Consts.MetaFileExtension);
|
2020-03-28 02:54:14 +00:00
|
|
|
|
if (!metaname.Exists) return true;
|
2020-07-06 06:58:13 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await DownloadDispatcher.ResolveArchive(metaname.LoadIniFile()) == null;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Utils.ErrorThrow(e, $"Exception while checking meta {filename}");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-01-22 03:43:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-25 23:15:19 +00:00
|
|
|
|
var to_find = (await MO2DownloadsFolder.EnumerateFiles()
|
|
|
|
|
.Where(f => f.Extension != Consts.MetaFileExtension && f.Extension !=Consts.HashFileExtension)
|
|
|
|
|
.PMap(Queue, async f => await HasInvalidMeta(f) ? f : default))
|
|
|
|
|
.Where(f => f.Exists)
|
2019-12-10 12:26:49 +00:00
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
if (to_find.Count == 0) return;
|
|
|
|
|
|
2020-01-20 02:14:24 +00:00
|
|
|
|
Utils.Log($"Attempting to infer {to_find.Count} metas from the server.");
|
|
|
|
|
|
2020-01-12 05:00:41 +00:00
|
|
|
|
await to_find.PMap(Queue, async f =>
|
2019-12-10 12:26:49 +00:00
|
|
|
|
{
|
2020-03-25 23:15:19 +00:00
|
|
|
|
var vf = VFS.Index.ByRootPath[f];
|
2020-02-14 13:30:58 +00:00
|
|
|
|
|
2020-06-21 22:03:54 +00:00
|
|
|
|
var meta = await ClientAPI.InferDownloadState(vf.Hash);
|
|
|
|
|
|
|
|
|
|
if (meta == null)
|
2020-02-14 13:30:58 +00:00
|
|
|
|
{
|
2020-03-25 23:15:19 +00:00
|
|
|
|
await vf.AbsoluteName.WithExtension(Consts.MetaFileExtension).WriteAllLinesAsync(
|
|
|
|
|
"[General]",
|
|
|
|
|
"unknownArchive=true");
|
2020-02-14 13:30:58 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-01-12 05:00:41 +00:00
|
|
|
|
|
2020-03-25 23:15:19 +00:00
|
|
|
|
Utils.Log($"Inferred .meta for {vf.FullPath.FileName}, writing to disk");
|
2020-06-21 22:03:54 +00:00
|
|
|
|
await vf.AbsoluteName.WithExtension(Consts.MetaFileExtension).WriteAllTextAsync(meta.GetMetaIniString());
|
2019-12-10 12:26:49 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2019-12-07 07:22:54 +00:00
|
|
|
|
private async Task IncludeArchiveMetadata()
|
2019-11-04 04:36:25 +00:00
|
|
|
|
{
|
|
|
|
|
Utils.Log($"Including {SelectedArchives.Count} .meta files for downloads");
|
2020-03-25 23:33:52 +00:00
|
|
|
|
await SelectedArchives.PMap(Queue, async a =>
|
2019-11-04 04:36:25 +00:00
|
|
|
|
{
|
2020-06-20 22:51:47 +00:00
|
|
|
|
if (a.State is GameFileSourceDownloader.State) return;
|
|
|
|
|
|
2020-03-25 23:33:52 +00:00
|
|
|
|
var source = MO2DownloadsFolder.Combine(a.Name + Consts.MetaFileExtension);
|
2020-05-02 21:09:29 +00:00
|
|
|
|
var ini = a.State.GetMetaIniString();
|
|
|
|
|
var (id, fullPath) = await IncludeString(ini);
|
2020-03-25 23:33:52 +00:00
|
|
|
|
InstallDirectives.Add(new ArchiveMeta
|
2019-11-04 04:36:25 +00:00
|
|
|
|
{
|
2020-05-02 21:09:29 +00:00
|
|
|
|
SourceDataID = id,
|
2020-06-20 22:51:47 +00:00
|
|
|
|
Size = fullPath.Size,
|
2020-05-02 21:09:29 +00:00
|
|
|
|
Hash = await fullPath.FileHashAsync(),
|
2020-03-25 23:33:52 +00:00
|
|
|
|
To = source.FileName
|
2019-11-04 04:36:25 +00:00
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 04:27:26 +00:00
|
|
|
|
/// <summary>
|
2019-09-12 23:44:35 +00:00
|
|
|
|
/// Clear references to lists that hold a lot of data.
|
2019-07-23 04:27:26 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
private void ResetMembers()
|
|
|
|
|
{
|
2020-04-12 18:55:59 +00:00
|
|
|
|
AllFiles = new List<RawSourceFile>();
|
|
|
|
|
InstallDirectives = new List<Directive>();
|
|
|
|
|
SelectedArchives = new List<Archive>();
|
|
|
|
|
ExtraFiles = new ConcurrentBag<Directive>();
|
2019-07-23 04:27:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-22 03:36:25 +00:00
|
|
|
|
/// <summary>
|
2019-09-12 23:44:35 +00:00
|
|
|
|
/// Fills in the Patch fields in files that require them
|
2019-07-22 03:36:25 +00:00
|
|
|
|
/// </summary>
|
2019-12-04 01:26:26 +00:00
|
|
|
|
private async Task BuildPatches()
|
2019-07-22 03:36:25 +00:00
|
|
|
|
{
|
2019-09-12 23:44:35 +00:00
|
|
|
|
Info("Gathering patch files");
|
2019-11-22 05:19:42 +00:00
|
|
|
|
|
2020-06-30 23:09:59 +00:00
|
|
|
|
var toBuild = InstallDirectives.OfType<PatchedFromArchive>()
|
|
|
|
|
.Where(p => p.Choices.Length > 0)
|
|
|
|
|
.SelectMany(p => p.Choices.Select(c => new PatchedFromArchive
|
|
|
|
|
{
|
|
|
|
|
To = p.To,
|
|
|
|
|
Hash = p.Hash,
|
|
|
|
|
ArchiveHashPath = c.MakeRelativePaths(),
|
|
|
|
|
FromFile = c,
|
|
|
|
|
Size = p.Size,
|
|
|
|
|
}))
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
|
|
if (toBuild.Length == 0) return;
|
2019-07-22 03:36:25 +00:00
|
|
|
|
|
2020-09-05 14:01:32 +00:00
|
|
|
|
// Extract all the source files
|
|
|
|
|
var indexed = toBuild.GroupBy(f => (VFS.Index.FileForArchiveHashPath(f.ArchiveHashPath)))
|
|
|
|
|
.ToDictionary(f => f.Key);
|
|
|
|
|
await VFS.Extract(Queue, indexed.Keys.ToHashSet(),
|
|
|
|
|
async (vf, sf) =>
|
|
|
|
|
{
|
|
|
|
|
// For each, extract the destination
|
|
|
|
|
var matches = indexed[vf];
|
|
|
|
|
using var iqueue = new WorkQueue(1);
|
|
|
|
|
foreach (var match in matches)
|
|
|
|
|
{
|
|
|
|
|
var destFile = FindDestFile(match.To);
|
|
|
|
|
// Build the patch
|
|
|
|
|
await VFS.Extract(iqueue, new[] {destFile}.ToHashSet(),
|
|
|
|
|
async (destvf, destsfn) =>
|
|
|
|
|
{
|
|
|
|
|
Info($"Patching {match.To}");
|
|
|
|
|
Status($"Patching {match.To}");
|
|
|
|
|
await using var srcStream = await sf.GetStream();
|
|
|
|
|
await using var destStream = await destsfn.GetStream();
|
|
|
|
|
var patchSize = await Utils.CreatePatchCached(srcStream, vf.Hash, destStream, destvf.Hash);
|
|
|
|
|
Info($"Patch size {patchSize} for {match.To}");
|
|
|
|
|
});
|
|
|
|
|
}
|
2020-06-30 23:09:59 +00:00
|
|
|
|
|
2020-09-05 14:01:32 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Load in the patches
|
2020-06-30 23:09:59 +00:00
|
|
|
|
await InstallDirectives.OfType<PatchedFromArchive>()
|
|
|
|
|
.Where(p => p.PatchID == default)
|
|
|
|
|
.PMap(Queue, async pfa =>
|
|
|
|
|
{
|
|
|
|
|
var patches = pfa.Choices
|
|
|
|
|
.Select(c => (Utils.TryGetPatch(c.Hash, pfa.Hash, out var data), data, c))
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
2020-09-05 14:01:32 +00:00
|
|
|
|
// Pick the best patch
|
2020-06-30 23:09:59 +00:00
|
|
|
|
if (patches.All(p => p.Item1))
|
|
|
|
|
{
|
2020-08-18 22:30:00 +00:00
|
|
|
|
var (_, bytes, file) = IncludePatches.PickPatch(this, patches);
|
2020-06-30 23:09:59 +00:00
|
|
|
|
pfa.FromFile = file;
|
|
|
|
|
pfa.FromHash = file.Hash;
|
|
|
|
|
pfa.ArchiveHashPath = file.MakeRelativePaths();
|
|
|
|
|
pfa.PatchID = await IncludeFile(bytes!);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var firstFailedPatch = InstallDirectives.OfType<PatchedFromArchive>().FirstOrDefault(f => f.PatchID == default);
|
2019-12-20 20:32:04 +00:00
|
|
|
|
if (firstFailedPatch != null)
|
|
|
|
|
Error($"Missing patches after generation, this should not happen. First failure: {firstFailedPatch.FullPath}");
|
2019-07-22 03:36:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-05 14:01:32 +00:00
|
|
|
|
private VirtualFile FindDestFile(RelativePath to)
|
2019-07-26 20:59:14 +00:00
|
|
|
|
{
|
2020-09-05 14:01:32 +00:00
|
|
|
|
var abs = to.RelativeTo(MO2Folder);
|
|
|
|
|
if (abs.Exists)
|
|
|
|
|
return VFS.Index.ByRootPath[abs];
|
2019-07-26 20:59:14 +00:00
|
|
|
|
|
|
|
|
|
if (to.StartsWith(Consts.BSACreationDir))
|
|
|
|
|
{
|
2020-03-25 23:33:52 +00:00
|
|
|
|
var bsaId = (RelativePath)((string)to).Split('\\')[1];
|
|
|
|
|
var bsa = InstallDirectives.OfType<CreateBSA>().First(b => b.TempID == bsaId);
|
|
|
|
|
var find = (RelativePath)Path.Combine(((string)to).Split('\\').Skip(2).ToArray());
|
2020-09-05 14:01:32 +00:00
|
|
|
|
|
|
|
|
|
return VFS.Index.ByRootPath[MO2Folder.Combine(bsa.To)].Children.First(c => c.RelativeName == find);
|
2019-07-26 20:59:14 +00:00
|
|
|
|
}
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2020-04-09 21:05:07 +00:00
|
|
|
|
throw new ArgumentException($"Couldn't load data for {to}");
|
2019-07-26 20:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-03 16:43:43 +00:00
|
|
|
|
public override IEnumerable<ICompilationStep> GetStack()
|
2019-10-31 02:24:42 +00:00
|
|
|
|
{
|
2020-03-25 23:33:52 +00:00
|
|
|
|
return MakeStack();
|
2019-10-31 02:24:42 +00:00
|
|
|
|
|
|
|
|
|
}
|
2019-07-21 04:40:54 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2019-09-12 23:44:35 +00:00
|
|
|
|
/// Creates a execution stack. The stack should be passed into Run stack. Each function
|
|
|
|
|
/// in this stack will be run in-order and the first to return a non-null result will have its
|
|
|
|
|
/// result included into the pack
|
2019-07-21 04:40:54 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2019-11-03 16:43:43 +00:00
|
|
|
|
public override IEnumerable<ICompilationStep> MakeStack()
|
2019-07-21 04:40:54 +00:00
|
|
|
|
{
|
2019-10-31 02:24:42 +00:00
|
|
|
|
Utils.Log("Generating compilation stack");
|
2019-10-30 12:29:06 +00:00
|
|
|
|
return new List<ICompilationStep>
|
|
|
|
|
{
|
2020-01-07 00:24:33 +00:00
|
|
|
|
new IgnoreGameFilesIfGameFolderFilesExist(this),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IncludePropertyFiles(this),
|
2020-07-05 15:11:52 +00:00
|
|
|
|
//new IncludeSteamWorkshopItems(this),
|
2020-07-01 03:46:26 +00:00
|
|
|
|
new IgnoreSaveFiles(this),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreStartsWith(this,"logs\\"),
|
|
|
|
|
new IgnoreStartsWith(this, "downloads\\"),
|
|
|
|
|
new IgnoreStartsWith(this,"webcache\\"),
|
|
|
|
|
new IgnoreStartsWith(this, "overwrite\\"),
|
2020-03-04 05:23:08 +00:00
|
|
|
|
new IgnoreStartsWith(this, "crashDumps\\"),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnorePathContains(this,"temporary_logs"),
|
|
|
|
|
new IgnorePathContains(this, "GPUCache"),
|
|
|
|
|
new IgnorePathContains(this, "SSEEdit Cache"),
|
|
|
|
|
new IgnoreOtherProfiles(this),
|
|
|
|
|
new IgnoreDisabledMods(this),
|
|
|
|
|
new IncludeThisProfile(this),
|
2019-07-21 04:40:54 +00:00
|
|
|
|
// Ignore the ModOrganizer.ini file it contains info created by MO2 on startup
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IncludeStubbedConfigFiles(this),
|
|
|
|
|
new IncludeLootFiles(this),
|
2020-05-11 12:51:57 +00:00
|
|
|
|
new IgnoreStartsWith(this, Path.Combine((string)Consts.GameFolderFilesDir, "Data")),
|
|
|
|
|
new IgnoreStartsWith(this, Path.Combine((string)Consts.GameFolderFilesDir, "Papyrus Compiler")),
|
|
|
|
|
new IgnoreStartsWith(this, Path.Combine((string)Consts.GameFolderFilesDir, "Skyrim")),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreRegex(this, Consts.GameFolderFilesDir + "\\\\.*\\.bsa"),
|
2020-03-10 04:11:11 +00:00
|
|
|
|
new IncludeRegex(this, "^[^\\\\]*\\.bat$"),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IncludeModIniData(this),
|
|
|
|
|
new DirectMatch(this),
|
|
|
|
|
new IncludeTaggedMods(this, Consts.WABBAJACK_INCLUDE),
|
2020-07-27 21:33:45 +00:00
|
|
|
|
new IgnoreEndsWith(this, ".pyc"),
|
|
|
|
|
new IgnoreEndsWith(this, ".log"),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new DeconstructBSAs(this), // Deconstruct BSAs before building patches so we don't generate massive patch files
|
|
|
|
|
new IncludePatches(this),
|
|
|
|
|
new IncludeDummyESPs(this),
|
2019-07-21 12:42:29 +00:00
|
|
|
|
|
2019-09-26 23:08:10 +00:00
|
|
|
|
// There are some types of files that will error the compilation, because they're created on-the-fly via tools
|
2019-07-26 20:59:14 +00:00
|
|
|
|
// so if we don't have a match by this point, just drop them.
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreEndsWith(this, ".ini"),
|
|
|
|
|
new IgnoreEndsWith(this, ".html"),
|
|
|
|
|
new IgnoreEndsWith(this, ".txt"),
|
2019-07-26 20:59:14 +00:00
|
|
|
|
// Don't know why, but this seems to get copied around a bit
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreEndsWith(this, "HavokBehaviorPostProcess.exe"),
|
2019-08-03 17:37:32 +00:00
|
|
|
|
// Theme file MO2 downloads somehow
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreEndsWith(this, "splash.png"),
|
2020-01-06 15:20:18 +00:00
|
|
|
|
// File to force MO2 into portable mode
|
|
|
|
|
new IgnoreEndsWith(this, "portable.txt"),
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreEndsWith(this, ".bin"),
|
|
|
|
|
new IgnoreEndsWith(this, ".refcache"),
|
2020-07-05 10:20:26 +00:00
|
|
|
|
//Include custom categories
|
|
|
|
|
new IncludeRegex(this, "categories.dat$"),
|
2019-09-02 22:36:57 +00:00
|
|
|
|
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IgnoreWabbajackInstallCruft(this),
|
2019-07-21 22:47:17 +00:00
|
|
|
|
|
2020-06-20 22:51:47 +00:00
|
|
|
|
//new PatchStockESMs(this),
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new IncludeAllConfigs(this),
|
|
|
|
|
new zEditIntegration.IncludeZEditPatches(this),
|
2019-11-02 18:36:38 +00:00
|
|
|
|
new IncludeTaggedMods(this, Consts.WABBAJACK_NOMATCH_INCLUDE),
|
2019-09-12 23:44:35 +00:00
|
|
|
|
|
2019-10-30 12:29:06 +00:00
|
|
|
|
new DropAll(this)
|
2019-07-21 04:40:54 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 23:39:03 +00:00
|
|
|
|
}
|